From 6bc7eb4186ed44a9f350b77f4faa0b862e95b07e Mon Sep 17 00:00:00 2001 From: ash Date: Wed, 9 Apr 2025 18:06:45 +0800 Subject: [PATCH 01/11] add .idea --- .gitignore | 1 + chapter01/asyncio/cotrast_async.py | 6 ++++-- chapter03/more_routers/main.py | 8 +++----- chapter03/swaggershow/main.py | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 3583241..14a130c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ __pycache__/ *.py[cod] +.idea/ \ No newline at end of file diff --git a/chapter01/asyncio/cotrast_async.py b/chapter01/asyncio/cotrast_async.py index fedbbe0..264f621 100644 --- a/chapter01/asyncio/cotrast_async.py +++ b/chapter01/asyncio/cotrast_async.py @@ -21,8 +21,10 @@ async def request_async(): @take_up_time def run(): - tasks = [asyncio.ensure_future(request_async()) for x in range(0, 49)] - loop = asyncio.get_event_loop() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + tasks = [asyncio.ensure_future(request_async(), loop=loop) for x in range(0, 49)] + # loop = asyncio.get_event_loop() tasks = asyncio.gather(*tasks) loop.run_until_complete(tasks) diff --git a/chapter03/more_routers/main.py b/chapter03/more_routers/main.py index c19f5fe..6c12f66 100644 --- a/chapter03/more_routers/main.py +++ b/chapter03/more_routers/main.py @@ -29,12 +29,10 @@ async def login(): return {"Hello": "static"} - - if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/swaggershow/main.py b/chapter03/swaggershow/main.py index c686370..1fb817d 100644 --- a/chapter03/swaggershow/main.py +++ b/chapter03/swaggershow/main.py @@ -46,6 +46,6 @@ async def index(): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From c6c19e72c2a5f6bdfaa1cb63a86385fc65b6b48a Mon Sep 17 00:00:00 2001 From: ash Date: Thu, 10 Apr 2025 09:37:51 +0800 Subject: [PATCH 02/11] Update main.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 几处错误拼写。 --- chapter03/static_dynamic/main.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chapter03/static_dynamic/main.py b/chapter03/static_dynamic/main.py index 3df2df3..3892ad7 100644 --- a/chapter03/static_dynamic/main.py +++ b/chapter03/static_dynamic/main.py @@ -21,15 +21,15 @@ async def index2(): app.add_api_route(path="/index2", endpoint=index2, methods=["GET", "POST"]) -router_uesr = APIRouter(prefix="/user", tags=["用户模块"]) +router_user = APIRouter(prefix="/user", tags=["用户模块"]) -@router_uesr.get("/user/login") +@router_user.get("/user/login") def user_login(): return {"ok": "登入成功!"} -@router_uesr.api_route("/user/api/login", methods=['GET', 'POST']) +@router_user.api_route("/user/api/login", methods=['GET', 'POST']) def user_api_route_login(): return {"ok": "登入成功!"} @@ -38,13 +38,13 @@ def add_user_api_route_login(): return {"ok": "登入成功!"} -router_uesr.add_api_route("/user/add/api/login", methods=['GET', 'POST'], endpoint=add_user_api_route_login) -app.include_router(router_uesr) +router_user.add_api_route("/user/add/api/login", methods=['GET', 'POST'], endpoint=add_user_api_route_login) +app.include_router(router_user) if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From c852e1fbd45b5e6bfffc6f303e3aa0937c44feae Mon Sep 17 00:00:00 2001 From: ash Date: Thu, 10 Apr 2025 21:33:58 +0800 Subject: [PATCH 03/11] Update main.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改错拼写单词。 --- chapter03/startup_shutdown/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapter03/startup_shutdown/main.py b/chapter03/startup_shutdown/main.py index 51912c4..26eae34 100644 --- a/chapter03/startup_shutdown/main.py +++ b/chapter03/startup_shutdown/main.py @@ -29,6 +29,6 @@ def shutdown_event_sync(): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From 26f3715720a2d71e127772b056ce4d12d20930a2 Mon Sep 17 00:00:00 2001 From: ash Date: Thu, 10 Apr 2025 22:26:04 +0800 Subject: [PATCH 04/11] Update main.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、修改了index2的响应字符。 2、调整了部分函数的行距,让有关联的更近。 --- chapter03/static_dynamic/main.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/chapter03/static_dynamic/main.py b/chapter03/static_dynamic/main.py index 3892ad7..01222de 100644 --- a/chapter03/static_dynamic/main.py +++ b/chapter03/static_dynamic/main.py @@ -14,30 +14,25 @@ async def index(): return {"index": "index"} - async def index2(): - return JSONResponse({"index": "index"}) - + return JSONResponse({"index": "index2"}) app.add_api_route(path="/index2", endpoint=index2, methods=["GET", "POST"]) -router_user = APIRouter(prefix="/user", tags=["用户模块"]) +router_user = APIRouter(prefix="/user", tags=["用户模块"]) @router_user.get("/user/login") def user_login(): return {"ok": "登入成功!"} - @router_user.api_route("/user/api/login", methods=['GET', 'POST']) def user_api_route_login(): return {"ok": "登入成功!"} - def add_user_api_route_login(): return {"ok": "登入成功!"} - router_user.add_api_route("/user/add/api/login", methods=['GET', 'POST'], endpoint=add_user_api_route_login) app.include_router(router_user) From a48b10136bebad5fa4c61f64488fd850e5d4a426 Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:11:39 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84modeel=E6=8B=BC=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter03/async_sync/main.py | 6 +++--- chapter03/background_tasks/main.py | 6 +++--- chapter03/close_docs/main.py | 6 +++--- chapter03/configparser_config/main.py | 6 +++--- chapter03/env_config/main.py | 6 +++--- chapter03/global_exception/main.py | 6 +++--- chapter03/localswagger/main.py | 6 +++--- chapter03/mount_app/fastapiapp.py | 6 +++--- chapter03/mount_app/flaskapp.py | 12 ++++++------ chapter03/parameter_body/main.py | 6 +++--- chapter03/parameter_cookie/main.py | 6 +++--- chapter03/parameter_form_and_file/main.py | 6 +++--- chapter03/parameter_header/main.py | 6 +++--- chapter03/parameter_path/main.py | 6 +++--- chapter03/parameter_query/main.py | 6 +++--- chapter03/parameter_request/main.py | 6 +++--- chapter03/parameter_response/main_file_response.py | 6 +++--- chapter03/parameter_response/main_html_response.py | 6 +++--- chapter03/parameter_response/main_json_response.py | 6 +++--- .../parameter_response/main_plain_text_response.py | 7 +++---- .../parameter_response/main_redirect_response.py | 6 +++--- chapter03/parameter_response/main_response_model.py | 6 +++--- chapter03/parameter_response/main_status_code.py | 6 +++--- 23 files changed, 72 insertions(+), 73 deletions(-) diff --git a/chapter03/async_sync/main.py b/chapter03/async_sync/main.py index 6555ab7..8582877 100644 --- a/chapter03/async_sync/main.py +++ b/chapter03/async_sync/main.py @@ -26,6 +26,6 @@ def syncdef(): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/background_tasks/main.py b/chapter03/background_tasks/main.py index 5895c4e..8ae376e 100644 --- a/chapter03/background_tasks/main.py +++ b/chapter03/background_tasks/main.py @@ -19,6 +19,6 @@ async def index(tasks: BackgroundTasks): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/close_docs/main.py b/chapter03/close_docs/main.py index 45fd59d..28bd56b 100644 --- a/chapter03/close_docs/main.py +++ b/chapter03/close_docs/main.py @@ -12,6 +12,6 @@ import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/configparser_config/main.py b/chapter03/configparser_config/main.py index e7a3a1b..2969437 100644 --- a/chapter03/configparser_config/main.py +++ b/chapter03/configparser_config/main.py @@ -18,6 +18,6 @@ import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/env_config/main.py b/chapter03/env_config/main.py index b451bde..f026b45 100644 --- a/chapter03/env_config/main.py +++ b/chapter03/env_config/main.py @@ -44,6 +44,6 @@ def get_settings(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/global_exception/main.py b/chapter03/global_exception/main.py index 218e64f..32738f6 100644 --- a/chapter03/global_exception/main.py +++ b/chapter03/global_exception/main.py @@ -21,6 +21,6 @@ async def exception_not_found(request, exc): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/localswagger/main.py b/chapter03/localswagger/main.py index 270946f..6615645 100644 --- a/chapter03/localswagger/main.py +++ b/chapter03/localswagger/main.py @@ -27,6 +27,6 @@ async def custom_swagger_ui_html(): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/mount_app/fastapiapp.py b/chapter03/mount_app/fastapiapp.py index 03cc6d9..de9e188 100644 --- a/chapter03/mount_app/fastapiapp.py +++ b/chapter03/mount_app/fastapiapp.py @@ -21,6 +21,6 @@ async def index(): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/mount_app/flaskapp.py b/chapter03/mount_app/flaskapp.py index 03cc6d9..81cc4a6 100644 --- a/chapter03/mount_app/flaskapp.py +++ b/chapter03/mount_app/flaskapp.py @@ -5,22 +5,22 @@ from fastapi.responses import JSONResponse app = FastAPI(title='主应用',description="我是主应用文档的描述",version="v1.0.0") -@app.get('/index',summary='首页') +@app.get('/index', summary='首页') async def index(): return JSONResponse({"index": "我是属于主应用的接口!"}) subapp = FastAPI(title='子应用',description="我是子应用文档的描述",version="v1.0.0") -@subapp.get('/index',summary='首页') +@subapp.get('/index', summary='首页') async def index(): return JSONResponse({"index": "我是属于子应用的接口!"}) -app.mount(path='/subapp',app=subapp,name='subapp') +app.mount(path='/subapp', app=subapp, name='subapp') if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_body/main.py b/chapter03/parameter_body/main.py index e25e081..8c7b4b5 100644 --- a/chapter03/parameter_body/main.py +++ b/chapter03/parameter_body/main.py @@ -134,6 +134,6 @@ async def update_item(item: ItemUser3, importance: int = Body(..., gt=0)): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_cookie/main.py b/chapter03/parameter_cookie/main.py index 023bdc9..ea1327e 100644 --- a/chapter03/parameter_cookie/main.py +++ b/chapter03/parameter_cookie/main.py @@ -25,6 +25,6 @@ async def Cookier_handel(xiaozhong: Optional[str] = Cookie(None)): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_form_and_file/main.py b/chapter03/parameter_form_and_file/main.py index 41ac4a4..e26f675 100644 --- a/chapter03/parameter_form_and_file/main.py +++ b/chapter03/parameter_form_and_file/main.py @@ -69,6 +69,6 @@ async def uploadfiles(file: UploadFile = File(...)): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_header/main.py b/chapter03/parameter_header/main.py index a948b68..130bb66 100644 --- a/chapter03/parameter_header/main.py +++ b/chapter03/parameter_header/main.py @@ -30,6 +30,6 @@ async def read_headerlist(x_token: List[str] = Header(None)): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_path/main.py b/chapter03/parameter_path/main.py index d24b4f6..6fc12b1 100644 --- a/chapter03/parameter_path/main.py +++ b/chapter03/parameter_path/main.py @@ -69,6 +69,6 @@ async def callback(*,item_id: int = Path(...,), q: str): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_query/main.py b/chapter03/parameter_query/main.py index 1886443..cb82a46 100644 --- a/chapter03/parameter_query/main.py +++ b/chapter03/parameter_query/main.py @@ -44,6 +44,6 @@ async def query_list(q: List[str] = Query(["test1", "test2"])): import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_request/main.py b/chapter03/parameter_request/main.py index 511af34..5cd3305 100644 --- a/chapter03/parameter_request/main.py +++ b/chapter03/parameter_request/main.py @@ -28,6 +28,6 @@ async def get_request(request: Request): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_file_response.py b/chapter03/parameter_response/main_file_response.py index 5eedefa..db031f0 100644 --- a/chapter03/parameter_response/main_file_response.py +++ b/chapter03/parameter_response/main_file_response.py @@ -29,6 +29,6 @@ async def async_dwonfile(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_html_response.py b/chapter03/parameter_response/main_html_response.py index b529671..69d3322 100644 --- a/chapter03/parameter_response/main_html_response.py +++ b/chapter03/parameter_response/main_html_response.py @@ -33,6 +33,6 @@ async def index(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_json_response.py b/chapter03/parameter_response/main_json_response.py index 49952c7..e5641eb 100644 --- a/chapter03/parameter_response/main_json_response.py +++ b/chapter03/parameter_response/main_json_response.py @@ -24,6 +24,6 @@ async def index(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_plain_text_response.py b/chapter03/parameter_response/main_plain_text_response.py index 1b8c3e6..8bf0553 100644 --- a/chapter03/parameter_response/main_plain_text_response.py +++ b/chapter03/parameter_response/main_plain_text_response.py @@ -11,7 +11,6 @@ app = FastAPI() - @app.post("/api/v1/text1/") async def index(): return 'ok' @@ -23,6 +22,6 @@ async def index(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_redirect_response.py b/chapter03/parameter_response/main_redirect_response.py index 0ac15d8..00bd9bf 100644 --- a/chapter03/parameter_response/main_redirect_response.py +++ b/chapter03/parameter_response/main_redirect_response.py @@ -36,6 +36,6 @@ async def index(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_response_model.py b/chapter03/parameter_response/main_response_model.py index 615f8af..94ffd8b 100644 --- a/chapter03/parameter_response/main_response_model.py +++ b/chapter03/parameter_response/main_response_model.py @@ -35,6 +35,6 @@ async def create_user(*, user: UserIn): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) diff --git a/chapter03/parameter_response/main_status_code.py b/chapter03/parameter_response/main_status_code.py index 09d8eab..51f64b8 100644 --- a/chapter03/parameter_response/main_status_code.py +++ b/chapter03/parameter_response/main_status_code.py @@ -39,6 +39,6 @@ async def set_http_code(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From b5cd9f3cbd19e8e283e1295135638fd34260284e Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:12:43 +0800 Subject: [PATCH 06/11] Update main_streaming_response.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、修改错误的modeel拼写。 2、调整import顺序。 --- .../parameter_response/main_streaming_response.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/chapter03/parameter_response/main_streaming_response.py b/chapter03/parameter_response/main_streaming_response.py index 4cfb255..69c5b6b 100644 --- a/chapter03/parameter_response/main_streaming_response.py +++ b/chapter03/parameter_response/main_streaming_response.py @@ -2,15 +2,12 @@ # -*- coding: utf-8 -*- from fastapi import FastAPI - from starlette.responses import HTMLResponse, RedirectResponse from os import getcwd, path +import cv2 app = FastAPI() - -import cv2 - PORTION_SIZE = 1024 * 1024 current_directory = getcwd() + "/" CHUNK_SIZE = 1024 * 1024 @@ -51,6 +48,6 @@ def main(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From 0c8aa7928aaa9458327cb7d3b89ec429302a23ad Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:13:11 +0800 Subject: [PATCH 07/11] Update main_xml_response.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、修改一个错误的xml大小写。 2、修改modeel拼写。 --- chapter03/parameter_response/main_xml_response.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/chapter03/parameter_response/main_xml_response.py b/chapter03/parameter_response/main_xml_response.py index c3b7dad..9f0c7c2 100644 --- a/chapter03/parameter_response/main_xml_response.py +++ b/chapter03/parameter_response/main_xml_response.py @@ -15,7 +15,7 @@ def get_xml_data(): data = """ George - John + John Reminder Don't forget the meeting! @@ -25,6 +25,7 @@ def get_xml_data(): if __name__ == "__main__": import uvicorn import os - app_modeel_name = os.path.basename(__file__).replace(".py", "") - print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) From f48c139a1fb726dffeaaf387f2dab0767d212698 Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:13:35 +0800 Subject: [PATCH 08/11] Update main.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加动态路由,让url的结果更清晰。 --- chapter03/static_dynamic/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chapter03/static_dynamic/main.py b/chapter03/static_dynamic/main.py index 01222de..5cf0d2c 100644 --- a/chapter03/static_dynamic/main.py +++ b/chapter03/static_dynamic/main.py @@ -22,13 +22,13 @@ async def index2(): router_user = APIRouter(prefix="/user", tags=["用户模块"]) -@router_user.get("/user/login") -def user_login(): - return {"ok": "登入成功!"} +@router_user.get("/{user}/login") +def user_login(user): + return {"ok": f"用户 {user} login登入成功!"} -@router_user.api_route("/user/api/login", methods=['GET', 'POST']) -def user_api_route_login(): - return {"ok": "登入成功!"} +@router_user.api_route("/{user}/api/login", methods=['GET', 'POST']) +def user_api_route_login(user): + return {"ok": f"用户 {user} api登入成功!"} def add_user_api_route_login(): return {"ok": "登入成功!"} From ace6a6f595f9128093d98451807fe220ed043469 Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:42:35 +0800 Subject: [PATCH 09/11] Update main.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 减少等待时长 --- chapter03/async_sync/main.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/chapter03/async_sync/main.py b/chapter03/async_sync/main.py index 8582877..367b7ad 100644 --- a/chapter03/async_sync/main.py +++ b/chapter03/async_sync/main.py @@ -9,19 +9,17 @@ @app.get(path="/async") async def asyncdef(): - await asyncio.sleep(10) + await asyncio.sleep(3) print("当前协程运行的线程ID:", threading.current_thread().ident) return {"index": "async"} @app.get(path="/sync") def syncdef(): - time.sleep(10) - print("当前普通函数运行的线程ID:",threading.current_thread().ident) + time.sleep(3) + print("当前普通函数运行的线程ID:", threading.current_thread().ident) return {"index": "sync"} - - if __name__ == "__main__": import uvicorn import os From 3228f698ca68034910251e4821dfaddc376bae1e Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 15:42:43 +0800 Subject: [PATCH 10/11] Create main.py --- chapter03/3_3_2_demo_more_routers/main.py | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 chapter03/3_3_2_demo_more_routers/main.py diff --git a/chapter03/3_3_2_demo_more_routers/main.py b/chapter03/3_3_2_demo_more_routers/main.py new file mode 100644 index 0000000..6fd40c5 --- /dev/null +++ b/chapter03/3_3_2_demo_more_routers/main.py @@ -0,0 +1,27 @@ +from fastapi import FastAPI +from fastapi import APIRouter + +app = FastAPI(routes=None) + +router_user = APIRouter(prefix="/user", tags=["用户模块"]) +router_pay = APIRouter(prefix="/pay", tags=["支付模块"]) + +@router_user.get("/{user}/login") +def user_login(user: str): + return {"user": user, "login": f"{user} login success!"} + + +@router_pay.post("/{user}/pay") +def user_pay(user: str): + return {"user": user, "pay": f"{user} pay success!"} + +app.include_router(router_user) +app.include_router(router_pay) + +if __name__ == "__main__": + import uvicorn + import os + + app_model_name = os.path.basename(__file__).replace(".py", "") + print(app_model_name) + uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) \ No newline at end of file From 9c9cfe7c64ac8ff0b265a3e360c5301f0764fe0a Mon Sep 17 00:00:00 2001 From: ash Date: Fri, 11 Apr 2025 16:46:19 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E4=BD=BF=E7=94=A8black=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E5=85=A8=E9=83=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter01/asyncio/contrast_async_other.py | 7 +- chapter01/asyncio/contrast_sync.py | 10 +- chapter01/asyncio/cotrast_async.py | 4 +- chapter02/main.py | 28 +- .../main.py | 16 +- .../main.py | 20 +- .../main.py | 19 +- .../{async_sync => 3_3_async_sync}/main.py | 5 +- .../fastapiapp.py | 18 +- .../{mount_app => 3_4_mount_app}/flaskapp.py | 18 +- .../main.py | 18 +- .../static/swagger-ui-bundle.js | 0 .../static/swagger-ui.css | 0 chapter03/background_tasks/main.py | 7 +- chapter03/close_docs/main.py | 3 +- chapter03/configparser_config/main.py | 12 +- chapter03/env_config/main.py | 9 +- chapter03/global_exception/main.py | 12 +- chapter03/parameter_body/main.py | 52 +- chapter03/parameter_cookie/main.py | 10 +- chapter03/parameter_form_and_file/main.py | 45 +- chapter03/parameter_header/main.py | 16 +- chapter03/parameter_path/main.py | 53 +- chapter03/parameter_query/main.py | 36 +- chapter03/parameter_request/main.py | 20 +- .../parameter_response/main_file_response.py | 18 +- .../parameter_response/main_html_response.py | 6 +- .../parameter_response/main_json_response.py | 6 +- .../main_plain_text_response.py | 9 +- .../main_redirect_response.py | 26 +- .../parameter_response/main_response_model.py | 6 +- .../parameter_response/main_status_code.py | 22 +- .../main_streaming_response.py | 16 +- .../parameter_response/main_xml_response.py | 4 +- chapter03/startup_shutdown/main.py | 6 +- chapter03/swaggershow/main.py | 16 +- chapter04/business_error/main.py | 32 +- chapter04/custom_exception/main.py | 10 +- chapter04/http_exception/main.py | 30 +- chapter04/middleware_exception/main.py | 19 +- chapter04/request_validation_error/main.py | 8 +- chapter05/body/main.py | 35 +- chapter05/pydantic_base/main.py | 22 +- chapter05/pydantic_fastapi_get/main.py | 56 +- chapter05/pydantic_fastapi_post/main.py | 35 +- chapter05/pydantic_field/main.py | 22 +- chapter05/pydantic_obj_to_dict_json/main.py | 9 +- chapter05/pydantic_orm/main.py | 32 +- .../pydantic_validator/address_error_main.py | 23 +- chapter05/pydantic_validator/main.py | 13 +- .../pydantic_validator/root_validator_main.py | 11 +- .../share_logic_auth_main.py | 9 +- chapter05/pydantic_validator_order/main.py | 9 +- chapter06/depend_class/main.py | 9 +- chapter06/depend_class_more_depends/main.py | 12 +- chapter06/depend_class_nest_depends/main.py | 21 +- chapter06/depend_func/main.py | 7 +- chapter06/depend_global_depends/main.py | 16 +- chapter06/depend_group_router/main.py | 22 +- chapter07/base_http_middleware/main.py | 25 +- chapter07/cors_middleware/main.py | 3 +- chapter07/https_redirect_middleware/main.py | 7 +- chapter07/log_response_middleware/main.py | 20 +- chapter07/middleware_process_time/main.py | 6 +- chapter07/tracdid_middleware/main.py | 20 +- chapter07/trusted_host_middleware/main.py | 19 +- chapter07/whileIp_middleware/main.py | 25 +- chapter08/aioredis_fastapi/main.py | 29 +- chapter08/aioredis_lock/main.py | 25 +- chapter08/aioredis_pubsub/main.py | 30 +- chapter08/databases_sql/main.py | 21 +- chapter08/databases_sqlalchemy/main.py | 7 +- chapter08/fastapi_sqlalchemy/alembic/env.py | 8 +- .../alembic/versions/287a3cf31b84_shann.py | 9 +- .../versions/3328ff109aa7_add_mobile.py | 9 +- chapter08/fastapi_sqlalchemy/api/__init__.py | 10 +- chapter08/fastapi_sqlalchemy/api/user.py | 36 +- .../fastapi_sqlalchemy/config/__init__.py | 10 +- .../fastapi_sqlalchemy/config/confiig.py | 12 +- chapter08/fastapi_sqlalchemy/db/__init__.py | 10 +- chapter08/fastapi_sqlalchemy/db/database.py | 8 +- .../dependencies/__init__.py | 11 +- chapter08/fastapi_sqlalchemy/main.py | 21 +- .../fastapi_sqlalchemy/models/__init__.py | 12 +- chapter08/fastapi_sqlalchemy/models/user.py | 3 +- .../fastapi_sqlalchemy/schemas/__init__.py | 10 +- chapter08/fastapi_sqlalchemy/schemas/user.py | 22 +- .../fastapi_sqlalchemy/servies/__init__.py | 10 +- chapter08/fastapi_sqlalchemy/servies/user.py | 27 +- chapter08/lua_register_script/2mian.py | 23 +- chapter08/lua_register_script/mian.py | 18 +- chapter08/sql_model/main.py | 3 +- chapter08/sqlalchemy_async_sqlite3/main.py | 50 +- chapter08/sqlalchemy_sync_sqlite3/main.py | 43 +- chapter08/sqlite3_connect/main.py | 12 +- chapter08/sqlmodel_async_sqlite3/main.py | 55 +- chapter08/sqlmodel_sync_sqlite3/main.py | 36 +- chapter09/api_key/main.py | 50 +- chapter09/http_basic/main.py | 15 +- chapter09/http_digest/main.py | 114 ++-- chapter09/jwt_use/main.py | 12 +- chapter09/mode_client/main.py | 86 ++- chapter09/mode_code/get_token.py | 20 +- chapter09/mode_code/main.py | 96 ++- chapter09/mode_password/main.py | 51 +- chapter10/shorr_url_pro/api/__init__.py | 10 +- chapter10/shorr_url_pro/api/short.py | 22 +- chapter10/shorr_url_pro/api/user.py | 36 +- chapter10/shorr_url_pro/config/__init__.py | 10 +- chapter10/shorr_url_pro/config/config.py | 16 +- chapter10/shorr_url_pro/db/__init__.py | 10 +- chapter10/shorr_url_pro/db/database.py | 6 +- .../shorr_url_pro/dependencies/__init__.py | 11 +- chapter10/shorr_url_pro/main.py | 27 +- chapter10/shorr_url_pro/models/__init__.py | 12 +- chapter10/shorr_url_pro/models/model.py | 11 +- chapter10/shorr_url_pro/schemas/__init__.py | 10 +- chapter10/shorr_url_pro/schemas/user.py | 22 +- chapter10/shorr_url_pro/servies/__init__.py | 10 +- chapter10/shorr_url_pro/servies/short.py | 14 +- chapter10/shorr_url_pro/servies/user.py | 2 +- chapter10/short_url_pro/api/short.py | 22 +- chapter10/short_url_pro/api/user.py | 61 +- chapter10/short_url_pro/app.py | 18 +- chapter10/short_url_pro/config/config.py | 4 +- chapter10/short_url_pro/db/database.py | 6 +- .../short_url_pro/dependencies/__init__.py | 6 +- chapter10/short_url_pro/main.py | 5 +- chapter10/short_url_pro/models/model.py | 14 +- chapter10/short_url_pro/schemas/__init__.py | 13 +- chapter10/short_url_pro/servies/short.py | 24 +- chapter10/short_url_pro/servies/user.py | 20 +- chapter10/short_url_pro/utils/auth_helper.py | 11 +- .../short_url_pro/utils/passlib_hepler.py | 5 +- .../short_url_pro/utils/random_helper.py | 5 +- chapter11/distributed_websocket/api/room.py | 39 +- chapter11/distributed_websocket/api/user.py | 28 +- chapter11/distributed_websocket/app.py | 5 +- .../distributed_websocket/config/config.py | 4 +- .../distributed_websocket/db/database.py | 6 +- .../dependencies/__init__.py | 3 +- chapter11/distributed_websocket/main.py | 9 +- .../distributed_websocket/models/model.py | 7 +- .../distributed_websocket/schemas/__init__.py | 12 +- .../distributed_websocket/servies/user.py | 18 +- .../utils/auth_helper.py | 4 +- .../utils/passlib_hepler.py | 5 +- .../utils/random_helper.py | 5 +- .../utils/room_connection_helper.py | 53 +- .../room_connection_helper_distributed.py | 120 +++- chapter11/websocket/api/room.py | 13 +- chapter11/websocket/api/user.py | 28 +- chapter11/websocket/app.py | 1 + chapter11/websocket/config/config.py | 4 +- chapter11/websocket/db/database.py | 6 +- chapter11/websocket/dependencies/__init__.py | 3 +- chapter11/websocket/main.py | 9 +- chapter11/websocket/models/model.py | 7 +- chapter11/websocket/schemas/__init__.py | 12 +- chapter11/websocket/servies/user.py | 18 +- chapter11/websocket/utils/auth_helper.py | 4 +- chapter11/websocket/utils/passlib_hepler.py | 5 +- chapter11/websocket/utils/random_helper.py | 5 +- .../websocket/utils/room_connection_helper.py | 53 +- .../apis/doctor/api/__init__.py | 7 +- .../apis/doctor/api/doctor_api.py | 50 +- .../apis/doctor/repository/__init__.py | 123 +++- .../apis/hospital/api/__init__.py | 5 +- .../apis/hospital/api/get_hospital_info.py | 2 +- .../apis/hospital/repository/__init__.py | 5 +- .../apis/payorders/api/__init__.py | 5 +- .../apis/payorders/api/doctor_order_check.py | 33 +- .../payorders/api/doctor_reserve_order.py | 546 +++++++++------ .../payorders/api/doctor_reserve_reorder.py | 161 +++-- .../payorders/api/payback_reserve_order.py | 194 ++++-- .../apis/payorders/api/reserve_order_info.py | 32 +- .../apis/payorders/dependencies/__init__.py | 3 +- .../apis/payorders/repository/__init__.py | 118 ++-- .../apis/payorders/schemas/__init__.py | 25 +- .../apis/userorders/api/__init__.py | 12 +- .../userorders/api/refund_reserve_order.py | 78 ++- .../userorders/api/unpay_reserve_order.py | 51 +- .../apis/userorders/api/user_order_info.py | 26 +- .../apis/userorders/api/user_order_list.py | 18 +- .../apis/userorders/api/wxauth_login.py | 46 +- .../apis/userorders/repository/__init__.py | 167 +++-- .../apis/userorders/schemas/__init__.py | 38 +- chapter12/booking_system/app.py | 126 ++-- chapter12/booking_system/app_sync.py | 84 ++- chapter12/booking_system/config/config.py | 25 +- chapter12/booking_system/db/async_database.py | 38 +- chapter12/booking_system/db/models.py | 197 ++++-- chapter12/booking_system/db/sync_database.py | 68 +- .../exts/async_rabbit/__init__.py | 74 ++- .../exts/exceptions/__init__.py | 51 +- .../exts/logururoute/__init__.py | 155 +++-- .../booking_system/exts/logururoute/config.py | 39 +- .../booking_system/exts/rabbit/__init__.py | 92 ++- .../booking_system/exts/rabbit2/__init__.py | 96 ++- .../exts/requestvar/__init__.py | 5 +- .../booking_system/exts/responses/__init__.py | 2 +- .../exts/responses/json_response.py | 75 ++- .../booking_system/exts/wechatpy/__init__.py | 13 +- .../booking_system/exts/wechatpy/_compat.py | 19 +- .../exts/wechatpy/client/__init__.py | 59 +- .../exts/wechatpy/client/api/base.py | 12 +- .../exts/wechatpy/client/api/card.py | 360 ++++------ .../exts/wechatpy/client/api/customservice.py | 85 +-- .../exts/wechatpy/client/api/datacube.py | 144 ++-- .../exts/wechatpy/client/api/device.py | 106 ++- .../exts/wechatpy/client/api/group.py | 43 +- .../exts/wechatpy/client/api/invoice.py | 204 +++--- .../exts/wechatpy/client/api/jsapi.py | 63 +- .../exts/wechatpy/client/api/marketing.py | 47 +- .../exts/wechatpy/client/api/material.py | 199 +++--- .../exts/wechatpy/client/api/media.py | 68 +- .../exts/wechatpy/client/api/menu.py | 26 +- .../wechatpy/client/api/merchant/__init__.py | 206 ++---- .../wechatpy/client/api/merchant/category.py | 20 +- .../wechatpy/client/api/merchant/common.py | 10 +- .../wechatpy/client/api/merchant/express.py | 32 +- .../wechatpy/client/api/merchant/group.py | 42 +- .../wechatpy/client/api/merchant/order.py | 42 +- .../wechatpy/client/api/merchant/shelf.py | 39 +- .../wechatpy/client/api/merchant/stock.py | 22 +- .../exts/wechatpy/client/api/message.py | 363 +++++----- .../exts/wechatpy/client/api/misc.py | 11 +- .../exts/wechatpy/client/api/poi.py | 19 +- .../exts/wechatpy/client/api/qrcode.py | 16 +- .../exts/wechatpy/client/api/scan.py | 43 +- .../exts/wechatpy/client/api/semantic.py | 39 +- .../exts/wechatpy/client/api/shakearound.py | 221 +++--- .../exts/wechatpy/client/api/tag.py | 83 +-- .../exts/wechatpy/client/api/template.py | 28 +- .../exts/wechatpy/client/api/user.py | 59 +- .../exts/wechatpy/client/api/wifi.py | 78 +-- .../exts/wechatpy/client/api/wxa.py | 217 +++--- .../exts/wechatpy/client/base.py | 164 ++--- .../booking_system/exts/wechatpy/component.py | 629 +++++++++--------- .../booking_system/exts/wechatpy/constants.py | 35 +- .../exts/wechatpy/crypto/__init__.py | 66 +- .../exts/wechatpy/crypto/base.py | 13 +- .../exts/wechatpy/crypto/cryptography.py | 6 +- .../wechatpy/enterprise/client/__init__.py | 24 +- .../wechatpy/enterprise/client/api/agent.py | 52 +- .../wechatpy/enterprise/client/api/appchat.py | 62 +- .../wechatpy/enterprise/client/api/batch.py | 94 +-- .../wechatpy/enterprise/client/api/chat.py | 124 ++-- .../enterprise/client/api/department.py | 38 +- .../wechatpy/enterprise/client/api/jsapi.py | 30 +- .../enterprise/client/api/material.py | 109 ++- .../wechatpy/enterprise/client/api/media.py | 26 +- .../wechatpy/enterprise/client/api/menu.py | 22 +- .../wechatpy/enterprise/client/api/message.py | 178 +++-- .../wechatpy/enterprise/client/api/misc.py | 4 +- .../wechatpy/enterprise/client/api/oauth.py | 22 +- .../wechatpy/enterprise/client/api/service.py | 42 +- .../enterprise/client/api/shakearound.py | 9 +- .../wechatpy/enterprise/client/api/tag.py | 45 +- .../wechatpy/enterprise/client/api/user.py | 148 ++--- .../exts/wechatpy/enterprise/crypto.py | 23 +- .../exts/wechatpy/enterprise/exceptions.py | 2 +- .../exts/wechatpy/enterprise/parser.py | 8 +- .../booking_system/exts/wechatpy/events.py | 545 ++++++++------- .../exts/wechatpy/exceptions.py | 83 +-- .../booking_system/exts/wechatpy/fields.py | 154 ++--- .../booking_system/exts/wechatpy/messages.py | 102 +-- .../booking_system/exts/wechatpy/oauth.py | 149 ++--- .../booking_system/exts/wechatpy/parser.py | 44 +- .../exts/wechatpy/pay/__init__.py | 157 +++-- .../exts/wechatpy/pay/api/coupon.py | 64 +- .../exts/wechatpy/pay/api/jsapi.py | 39 +- .../exts/wechatpy/pay/api/micropay.py | 56 +- .../exts/wechatpy/pay/api/order.py | 123 ++-- .../exts/wechatpy/pay/api/redpack.py | 115 ++-- .../exts/wechatpy/pay/api/refund.py | 65 +- .../exts/wechatpy/pay/api/tools.py | 43 +- .../exts/wechatpy/pay/api/transfer.py | 92 +-- .../exts/wechatpy/pay/api/withhold.py | 92 ++- .../booking_system/exts/wechatpy/pay/base.py | 11 +- .../booking_system/exts/wechatpy/pay/utils.py | 47 +- .../booking_system/exts/wechatpy/replies.py | 192 +++--- .../exts/wechatpy/session/memcachedstorage.py | 6 +- .../exts/wechatpy/session/redisstorage.py | 6 +- .../exts/wechatpy/session/shovestorage.py | 4 +- .../booking_system/exts/wechatpy/utils.py | 29 +- chapter12/booking_system/main.py | 8 +- .../middlewares/loger/middleware.py | 242 ++++--- chapter12/booking_system/order_consumer.py | 60 +- chapter12/booking_system/plugins/base.py | 15 +- .../booking_system/plugins/request_hook.py | 29 +- chapter12/booking_system/utils/cast_helper.py | 4 +- .../booking_system/utils/datatime_helper.py | 59 +- chapter12/booking_system/utils/json_helper.py | 12 +- .../booking_system/utils/ordernum_helper.py | 43 +- .../booking_system/utils/run_with_asyncio.py | 6 +- chapter12/booking_system/utils/xmlhelper.py | 22 +- .../apis/doctor/api/__init__.py | 7 +- .../apis/doctor/api/doctor_api.py | 50 +- .../apis/doctor/repository/__init__.py | 123 +++- .../apis/hospital/api/__init__.py | 5 +- .../apis/hospital/api/get_hospital_info.py | 2 +- .../apis/hospital/repository/__init__.py | 5 +- .../apis/payorders/api/__init__.py | 5 +- .../apis/payorders/api/doctor_order_check.py | 33 +- .../payorders/api/doctor_reserve_order.py | 546 +++++++++------ .../payorders/api/doctor_reserve_reorder.py | 161 +++-- .../payorders/api/payback_reserve_order.py | 194 ++++-- .../apis/payorders/api/reserve_order_info.py | 32 +- .../apis/payorders/dependencies/__init__.py | 3 +- .../apis/payorders/repository/__init__.py | 118 ++-- .../apis/payorders/schemas/__init__.py | 25 +- .../apis/userorders/api/__init__.py | 12 +- .../userorders/api/refund_reserve_order.py | 78 ++- .../userorders/api/unpay_reserve_order.py | 51 +- .../apis/userorders/api/user_order_info.py | 26 +- .../apis/userorders/api/user_order_list.py | 18 +- .../apis/userorders/api/wxauth_login.py | 46 +- .../apis/userorders/repository/__init__.py | 167 +++-- .../apis/userorders/schemas/__init__.py | 38 +- chapter13/booking_system/app.py | 130 ++-- chapter13/booking_system/app_sync.py | 84 ++- chapter13/booking_system/config/config.py | 25 +- chapter13/booking_system/db/async_database.py | 38 +- chapter13/booking_system/db/models.py | 197 ++++-- chapter13/booking_system/db/sync_database.py | 68 +- .../exts/async_rabbit/__init__.py | 74 ++- .../exts/exceptions/__init__.py | 51 +- .../exts/logururoute/__init__.py | 155 +++-- .../booking_system/exts/logururoute/config.py | 39 +- .../booking_system/exts/rabbit/__init__.py | 92 ++- .../booking_system/exts/rabbit2/__init__.py | 96 ++- .../exts/requestvar/__init__.py | 5 +- .../booking_system/exts/responses/__init__.py | 2 +- .../exts/responses/json_response.py | 75 ++- .../booking_system/exts/wechatpy/__init__.py | 13 +- .../booking_system/exts/wechatpy/_compat.py | 19 +- .../exts/wechatpy/client/__init__.py | 59 +- .../exts/wechatpy/client/api/base.py | 12 +- .../exts/wechatpy/client/api/card.py | 360 ++++------ .../exts/wechatpy/client/api/customservice.py | 85 +-- .../exts/wechatpy/client/api/datacube.py | 144 ++-- .../exts/wechatpy/client/api/device.py | 106 ++- .../exts/wechatpy/client/api/group.py | 43 +- .../exts/wechatpy/client/api/invoice.py | 204 +++--- .../exts/wechatpy/client/api/jsapi.py | 63 +- .../exts/wechatpy/client/api/marketing.py | 47 +- .../exts/wechatpy/client/api/material.py | 199 +++--- .../exts/wechatpy/client/api/media.py | 68 +- .../exts/wechatpy/client/api/menu.py | 26 +- .../wechatpy/client/api/merchant/__init__.py | 206 ++---- .../wechatpy/client/api/merchant/category.py | 20 +- .../wechatpy/client/api/merchant/common.py | 10 +- .../wechatpy/client/api/merchant/express.py | 32 +- .../wechatpy/client/api/merchant/group.py | 42 +- .../wechatpy/client/api/merchant/order.py | 42 +- .../wechatpy/client/api/merchant/shelf.py | 39 +- .../wechatpy/client/api/merchant/stock.py | 22 +- .../exts/wechatpy/client/api/message.py | 363 +++++----- .../exts/wechatpy/client/api/misc.py | 11 +- .../exts/wechatpy/client/api/poi.py | 19 +- .../exts/wechatpy/client/api/qrcode.py | 16 +- .../exts/wechatpy/client/api/scan.py | 43 +- .../exts/wechatpy/client/api/semantic.py | 39 +- .../exts/wechatpy/client/api/shakearound.py | 221 +++--- .../exts/wechatpy/client/api/tag.py | 83 +-- .../exts/wechatpy/client/api/template.py | 28 +- .../exts/wechatpy/client/api/user.py | 59 +- .../exts/wechatpy/client/api/wifi.py | 78 +-- .../exts/wechatpy/client/api/wxa.py | 217 +++--- .../exts/wechatpy/client/base.py | 164 ++--- .../booking_system/exts/wechatpy/component.py | 629 +++++++++--------- .../booking_system/exts/wechatpy/constants.py | 35 +- .../exts/wechatpy/crypto/__init__.py | 66 +- .../exts/wechatpy/crypto/base.py | 13 +- .../exts/wechatpy/crypto/cryptography.py | 6 +- .../wechatpy/enterprise/client/__init__.py | 24 +- .../wechatpy/enterprise/client/api/agent.py | 52 +- .../wechatpy/enterprise/client/api/appchat.py | 62 +- .../wechatpy/enterprise/client/api/batch.py | 94 +-- .../wechatpy/enterprise/client/api/chat.py | 124 ++-- .../enterprise/client/api/department.py | 38 +- .../wechatpy/enterprise/client/api/jsapi.py | 30 +- .../enterprise/client/api/material.py | 109 ++- .../wechatpy/enterprise/client/api/media.py | 26 +- .../wechatpy/enterprise/client/api/menu.py | 22 +- .../wechatpy/enterprise/client/api/message.py | 178 +++-- .../wechatpy/enterprise/client/api/misc.py | 4 +- .../wechatpy/enterprise/client/api/oauth.py | 22 +- .../wechatpy/enterprise/client/api/service.py | 42 +- .../enterprise/client/api/shakearound.py | 9 +- .../wechatpy/enterprise/client/api/tag.py | 45 +- .../wechatpy/enterprise/client/api/user.py | 148 ++--- .../exts/wechatpy/enterprise/crypto.py | 23 +- .../exts/wechatpy/enterprise/exceptions.py | 2 +- .../exts/wechatpy/enterprise/parser.py | 8 +- .../booking_system/exts/wechatpy/events.py | 545 ++++++++------- .../exts/wechatpy/exceptions.py | 83 +-- .../booking_system/exts/wechatpy/fields.py | 154 ++--- .../booking_system/exts/wechatpy/messages.py | 102 +-- .../booking_system/exts/wechatpy/oauth.py | 149 ++--- .../booking_system/exts/wechatpy/parser.py | 44 +- .../exts/wechatpy/pay/__init__.py | 157 +++-- .../exts/wechatpy/pay/api/coupon.py | 64 +- .../exts/wechatpy/pay/api/jsapi.py | 39 +- .../exts/wechatpy/pay/api/micropay.py | 56 +- .../exts/wechatpy/pay/api/order.py | 123 ++-- .../exts/wechatpy/pay/api/redpack.py | 115 ++-- .../exts/wechatpy/pay/api/refund.py | 65 +- .../exts/wechatpy/pay/api/tools.py | 43 +- .../exts/wechatpy/pay/api/transfer.py | 92 +-- .../exts/wechatpy/pay/api/withhold.py | 92 ++- .../booking_system/exts/wechatpy/pay/base.py | 11 +- .../booking_system/exts/wechatpy/pay/utils.py | 47 +- .../booking_system/exts/wechatpy/replies.py | 192 +++--- .../exts/wechatpy/session/memcachedstorage.py | 6 +- .../exts/wechatpy/session/redisstorage.py | 6 +- .../exts/wechatpy/session/shovestorage.py | 4 +- .../booking_system/exts/wechatpy/utils.py | 29 +- chapter13/booking_system/main.py | 8 +- .../middlewares/loger/middleware.py | 242 ++++--- chapter13/booking_system/order_consumer.py | 60 +- chapter13/booking_system/plugins/base.py | 15 +- .../booking_system/plugins/request_hook.py | 29 +- chapter13/booking_system/testcase/conftest.py | 16 +- .../testcase/test_async_api_v1.py | 5 +- .../testcase/test_async_api_v2.py | 8 +- .../booking_system/testcase/test_sync_api.py | 16 +- chapter13/booking_system/utils/cast_helper.py | 4 +- .../booking_system/utils/datatime_helper.py | 59 +- chapter13/booking_system/utils/json_helper.py | 12 +- .../booking_system/utils/ordernum_helper.py | 43 +- .../booking_system/utils/run_with_asyncio.py | 6 +- chapter13/booking_system/utils/xmlhelper.py | 22 +- chapter13/pytest_demo/cast_helper.py | 4 +- chapter13/pytest_demo/test_add.py | 4 +- .../pytest_fixture_demo/testcase/conftest.py | 1 - .../testcase/test_case1.py | 4 +- .../pytest_fixture_demo/tests/test_fixs.py | 6 +- .../tests/test_fixs_parametrize.py | 8 +- .../tests/test_fixs_parametrize_class.py | 9 +- .../tests/test_fixs_params.py | 10 +- chapter13/unittest_demo/main.py | 13 +- .../apis/doctor/api/__init__.py | 7 +- .../apis/doctor/api/doctor_api.py | 50 +- .../apis/doctor/repository/__init__.py | 123 +++- .../apis/hospital/api/__init__.py | 5 +- .../apis/hospital/api/get_hospital_info.py | 2 +- .../apis/hospital/repository/__init__.py | 5 +- .../apis/payorders/api/__init__.py | 5 +- .../apis/payorders/api/doctor_order_check.py | 33 +- .../payorders/api/doctor_reserve_order.py | 546 +++++++++------ .../payorders/api/doctor_reserve_reorder.py | 161 +++-- .../payorders/api/payback_reserve_order.py | 194 ++++-- .../apis/payorders/api/reserve_order_info.py | 32 +- .../apis/payorders/dependencies/__init__.py | 3 +- .../apis/payorders/repository/__init__.py | 118 ++-- .../apis/payorders/schemas/__init__.py | 25 +- .../apis/userorders/api/__init__.py | 12 +- .../userorders/api/refund_reserve_order.py | 78 ++- .../userorders/api/unpay_reserve_order.py | 51 +- .../apis/userorders/api/user_order_info.py | 26 +- .../apis/userorders/api/user_order_list.py | 18 +- .../apis/userorders/api/wxauth_login.py | 46 +- .../apis/userorders/repository/__init__.py | 167 +++-- .../apis/userorders/schemas/__init__.py | 38 +- chapter14/booking_system/app.py | 130 ++-- chapter14/booking_system/app_sync.py | 84 ++- chapter14/booking_system/config/config.py | 25 +- chapter14/booking_system/db/async_database.py | 38 +- chapter14/booking_system/db/models.py | 197 ++++-- chapter14/booking_system/db/sync_database.py | 68 +- .../exts/async_rabbit/__init__.py | 74 ++- .../exts/exceptions/__init__.py | 51 +- .../exts/logururoute/__init__.py | 155 +++-- .../booking_system/exts/logururoute/config.py | 39 +- .../booking_system/exts/rabbit/__init__.py | 92 ++- .../booking_system/exts/rabbit2/__init__.py | 96 ++- .../exts/requestvar/__init__.py | 5 +- .../booking_system/exts/responses/__init__.py | 2 +- .../exts/responses/json_response.py | 75 ++- .../booking_system/exts/wechatpy/__init__.py | 13 +- .../booking_system/exts/wechatpy/_compat.py | 19 +- .../exts/wechatpy/client/__init__.py | 59 +- .../exts/wechatpy/client/api/base.py | 12 +- .../exts/wechatpy/client/api/card.py | 360 ++++------ .../exts/wechatpy/client/api/customservice.py | 85 +-- .../exts/wechatpy/client/api/datacube.py | 144 ++-- .../exts/wechatpy/client/api/device.py | 106 ++- .../exts/wechatpy/client/api/group.py | 43 +- .../exts/wechatpy/client/api/invoice.py | 204 +++--- .../exts/wechatpy/client/api/jsapi.py | 63 +- .../exts/wechatpy/client/api/marketing.py | 47 +- .../exts/wechatpy/client/api/material.py | 199 +++--- .../exts/wechatpy/client/api/media.py | 68 +- .../exts/wechatpy/client/api/menu.py | 26 +- .../wechatpy/client/api/merchant/__init__.py | 206 ++---- .../wechatpy/client/api/merchant/category.py | 20 +- .../wechatpy/client/api/merchant/common.py | 10 +- .../wechatpy/client/api/merchant/express.py | 32 +- .../wechatpy/client/api/merchant/group.py | 42 +- .../wechatpy/client/api/merchant/order.py | 42 +- .../wechatpy/client/api/merchant/shelf.py | 39 +- .../wechatpy/client/api/merchant/stock.py | 22 +- .../exts/wechatpy/client/api/message.py | 363 +++++----- .../exts/wechatpy/client/api/misc.py | 11 +- .../exts/wechatpy/client/api/poi.py | 19 +- .../exts/wechatpy/client/api/qrcode.py | 16 +- .../exts/wechatpy/client/api/scan.py | 43 +- .../exts/wechatpy/client/api/semantic.py | 39 +- .../exts/wechatpy/client/api/shakearound.py | 221 +++--- .../exts/wechatpy/client/api/tag.py | 83 +-- .../exts/wechatpy/client/api/template.py | 28 +- .../exts/wechatpy/client/api/user.py | 59 +- .../exts/wechatpy/client/api/wifi.py | 78 +-- .../exts/wechatpy/client/api/wxa.py | 217 +++--- .../exts/wechatpy/client/base.py | 164 ++--- .../booking_system/exts/wechatpy/component.py | 629 +++++++++--------- .../booking_system/exts/wechatpy/constants.py | 35 +- .../exts/wechatpy/crypto/__init__.py | 66 +- .../exts/wechatpy/crypto/base.py | 13 +- .../exts/wechatpy/crypto/cryptography.py | 6 +- .../wechatpy/enterprise/client/__init__.py | 24 +- .../wechatpy/enterprise/client/api/agent.py | 52 +- .../wechatpy/enterprise/client/api/appchat.py | 62 +- .../wechatpy/enterprise/client/api/batch.py | 94 +-- .../wechatpy/enterprise/client/api/chat.py | 124 ++-- .../enterprise/client/api/department.py | 38 +- .../wechatpy/enterprise/client/api/jsapi.py | 30 +- .../enterprise/client/api/material.py | 109 ++- .../wechatpy/enterprise/client/api/media.py | 26 +- .../wechatpy/enterprise/client/api/menu.py | 22 +- .../wechatpy/enterprise/client/api/message.py | 178 +++-- .../wechatpy/enterprise/client/api/misc.py | 4 +- .../wechatpy/enterprise/client/api/oauth.py | 22 +- .../wechatpy/enterprise/client/api/service.py | 42 +- .../enterprise/client/api/shakearound.py | 9 +- .../wechatpy/enterprise/client/api/tag.py | 45 +- .../wechatpy/enterprise/client/api/user.py | 148 ++--- .../exts/wechatpy/enterprise/crypto.py | 23 +- .../exts/wechatpy/enterprise/exceptions.py | 2 +- .../exts/wechatpy/enterprise/parser.py | 8 +- .../booking_system/exts/wechatpy/events.py | 545 ++++++++------- .../exts/wechatpy/exceptions.py | 83 +-- .../booking_system/exts/wechatpy/fields.py | 154 ++--- .../booking_system/exts/wechatpy/messages.py | 102 +-- .../booking_system/exts/wechatpy/oauth.py | 149 ++--- .../booking_system/exts/wechatpy/parser.py | 44 +- .../exts/wechatpy/pay/__init__.py | 157 +++-- .../exts/wechatpy/pay/api/coupon.py | 64 +- .../exts/wechatpy/pay/api/jsapi.py | 39 +- .../exts/wechatpy/pay/api/micropay.py | 56 +- .../exts/wechatpy/pay/api/order.py | 123 ++-- .../exts/wechatpy/pay/api/redpack.py | 115 ++-- .../exts/wechatpy/pay/api/refund.py | 65 +- .../exts/wechatpy/pay/api/tools.py | 43 +- .../exts/wechatpy/pay/api/transfer.py | 92 +-- .../exts/wechatpy/pay/api/withhold.py | 92 ++- .../booking_system/exts/wechatpy/pay/base.py | 11 +- .../booking_system/exts/wechatpy/pay/utils.py | 47 +- .../booking_system/exts/wechatpy/replies.py | 192 +++--- .../exts/wechatpy/session/memcachedstorage.py | 6 +- .../exts/wechatpy/session/redisstorage.py | 6 +- .../exts/wechatpy/session/shovestorage.py | 4 +- .../booking_system/exts/wechatpy/utils.py | 29 +- chapter14/booking_system/main.py | 8 +- .../middlewares/loger/middleware.py | 242 ++++--- chapter14/booking_system/order_consumer.py | 60 +- chapter14/booking_system/plugins/base.py | 15 +- .../booking_system/plugins/request_hook.py | 29 +- chapter14/booking_system/testcase/conftest.py | 16 +- .../testcase/test_async_api_v1.py | 5 +- .../testcase/test_async_api_v2.py | 8 +- .../booking_system/testcase/test_sync_api.py | 16 +- chapter14/booking_system/utils/cast_helper.py | 4 +- .../booking_system/utils/datatime_helper.py | 59 +- chapter14/booking_system/utils/json_helper.py | 12 +- .../booking_system/utils/ordernum_helper.py | 43 +- .../booking_system/utils/run_with_asyncio.py | 6 +- chapter14/booking_system/utils/xmlhelper.py | 22 +- chapter15/Fastapi_cProfile/main.py | 14 +- chapter15/Jaeger/test_jaeger_client/main.py | 46 +- .../middeware/__init__.py | 30 +- .../middeware/main.py | 19 +- .../main_asgiref_async_to_sync.py | 12 +- .../main_asgiref_sync_to_async.py | 16 +- .../main_asyncer_asyncify.py | 16 +- .../async_sync_change/main_asyncer_syncify.py | 16 +- .../main_asgiref_sync_to_async.py | 21 +- chapter15/body/main_01.py | 2 +- chapter15/body/main_02.py | 7 +- chapter15/body/main_03.py | 10 +- chapter15/body/main_04.py | 16 +- chapter15/cProfile/c_profile_text_run.py | 4 +- .../cProfile/runtest_profile_stats_run.py | 1 + chapter15/contextvar_request/bind_.py | 2 +- chapter15/contextvar_request/main_class.py | 13 +- chapter15/contextvar_request/request.py | 2 +- chapter15/depends/main_class.py | 5 +- chapter15/depends/main_class_call.py | 13 +- .../depends/main_class_security_scopes.py | 2 +- chapter15/depends/main_fun.py | 8 +- chapter15/depends/main_fun_security_scopes.py | 4 +- chapter15/fastapi_cache/main.py | 35 +- chapter15/fastapi_cache/uu.py | 22 +- chapter15/model_sort/main_asyncer_syncify.py | 6 +- chapter15/plugins/base.py | 42 +- chapter15/plugins/main.py | 24 +- chapter15/sentry/main.py | 3 +- chapter15/smtplib/main_aiosmtplib.py | 55 +- chapter15/smtplib/main_smtplib.py | 51 +- chapter16/Jaeger/test_jaeger_client/main.py | 46 +- .../middeware/__init__.py | 30 +- .../middeware/main.py | 19 +- .../main_asgiref_async_to_sync.py | 12 +- .../main_asgiref_sync_to_async.py | 16 +- .../main_asyncer_asyncify.py | 16 +- .../async_sync_change/main_asyncer_syncify.py | 16 +- .../main_asgiref_sync_to_async.py | 21 +- chapter16/body/main_01.py | 2 +- chapter16/body/main_02.py | 7 +- chapter16/body/main_03.py | 10 +- chapter16/body/main_04.py | 16 +- chapter16/contextvar_request/bind_.py | 2 +- chapter16/contextvar_request/main_class.py | 13 +- chapter16/contextvar_request/request.py | 2 +- chapter16/depends/main_class.py | 5 +- chapter16/depends/main_class_call.py | 13 +- .../depends/main_class_security_scopes.py | 2 +- chapter16/depends/main_fun.py | 8 +- chapter16/depends/main_fun_security_scopes.py | 4 +- chapter16/model_sort/main_asyncer_syncify.py | 6 +- chapter16/plugins/base.py | 42 +- chapter16/plugins/main.py | 24 +- chapter16/sentry/main.py | 3 +- chapter16/smtplib/aaaa.py | 32 +- chapter16/smtplib/main_aiosmtplib.py | 55 +- chapter16/smtplib/main_smtplib.py | 51 +- 638 files changed, 19227 insertions(+), 16842 deletions(-) rename chapter03/{more_routers => 3_2_2_more_routers}/main.py (68%) rename chapter03/{static_dynamic => 3_2_2_static_dynamic}/main.py (53%) rename chapter03/{3_3_2_demo_more_routers => 3_2_3_demo_more_routers}/main.py (59%) rename chapter03/{async_sync => 3_3_async_sync}/main.py (90%) rename chapter03/{mount_app => 3_4_mount_app}/fastapiapp.py (54%) rename chapter03/{mount_app => 3_4_mount_app}/flaskapp.py (54%) rename chapter03/{localswagger => 3_5_localswagger}/main.py (67%) rename chapter03/{localswagger => 3_5_localswagger}/static/swagger-ui-bundle.js (100%) rename chapter03/{localswagger => 3_5_localswagger}/static/swagger-ui.css (100%) diff --git a/chapter01/asyncio/contrast_async_other.py b/chapter01/asyncio/contrast_async_other.py index c574171..a755778 100644 --- a/chapter01/asyncio/contrast_async_other.py +++ b/chapter01/asyncio/contrast_async_other.py @@ -19,7 +19,7 @@ async def wrapper(*args, **kwargs): async def request_async(): # 异步请求函数 async with aiohttp.ClientSession() as session: - async with session.get('https://www.baidu.com') as resp: + async with session.get("https://www.baidu.com") as resp: pass @@ -44,9 +44,10 @@ def main(): import os -if __name__ == '__main__': + +if __name__ == "__main__": # 需要注意需要在此处设置才可以运行 - if os.name == 'nt': + if os.name == "nt": # 在Windows系统中设置事件循环策略,解决 "Event loop is closed" 错误 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) main() diff --git a/chapter01/asyncio/contrast_sync.py b/chapter01/asyncio/contrast_sync.py index a4d41f6..b8655b5 100644 --- a/chapter01/asyncio/contrast_sync.py +++ b/chapter01/asyncio/contrast_sync.py @@ -1,6 +1,7 @@ import requests import time + def take_up_time(func): def wrapper(*args, **kwargs): print("开始执行---->") @@ -9,17 +10,20 @@ def wrapper(*args, **kwargs): using = (time.time() - now) * 1000 print(f"结束执行,消耗时间为:{using}ms") return result + return wrapper + def request_sync(url): response = requests.get(url) return response + @take_up_time def run(): for i in range(0, 50): - request_sync('https://www.baidu.com') + request_sync("https://www.baidu.com") -if __name__ == '__main__': - run() \ No newline at end of file +if __name__ == "__main__": + run() diff --git a/chapter01/asyncio/cotrast_async.py b/chapter01/asyncio/cotrast_async.py index 264f621..73e8a45 100644 --- a/chapter01/asyncio/cotrast_async.py +++ b/chapter01/asyncio/cotrast_async.py @@ -15,7 +15,7 @@ def wrapper(*args, **kwargs): async def request_async(): async with aiohttp.ClientSession() as session: - async with session.get('https://www.baidu.com') as resp: + async with session.get("https://www.baidu.com") as resp: pass @@ -29,5 +29,5 @@ def run(): loop.run_until_complete(tasks) -if __name__ == '__main__': +if __name__ == "__main__": run() diff --git a/chapter02/main.py b/chapter02/main.py index 3da497d..e059797 100644 --- a/chapter02/main.py +++ b/chapter02/main.py @@ -7,10 +7,12 @@ from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles -app = FastAPI(title="学习Fastapi框架文档", - description="以下是关于相Fastapi框架文档介绍和描述", - version="0.0.1",debug=True) - +app = FastAPI( + title="学习Fastapi框架文档", + description="以下是关于相Fastapi框架文档介绍和描述", + version="0.0.1", + debug=True, +) templates = Jinja2Templates(directory=f"{pathlib.Path.cwd()}/templates/") @@ -18,26 +20,26 @@ app.mount("/static", staticfiles, name="static") -@app.get('/', response_class=HTMLResponse) -@app.get('/index', response_class=HTMLResponse) -@app.post('/index', response_class=HTMLResponse) +@app.get("/", response_class=HTMLResponse) +@app.get("/index", response_class=HTMLResponse) +@app.post("/index", response_class=HTMLResponse) async def index(request: Request): - return templates.TemplateResponse("index.html", - {"request": request}) + return templates.TemplateResponse("index.html", {"request": request}) def myinex(): return {"Hello": "myinex api"} + app.get("/myindex", tags=["路由注册方式"], summary="路由注册方式说明")(myinex) -@app.route('/loginjig', methods=['GET', 'POST'], name='loginjig') +@app.route("/loginjig", methods=["GET", "POST"], name="loginjig") def loginjig(req: Request): - return PlainTextResponse('大爷') + return PlainTextResponse("大爷") -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=65535, reload=True, debug=True) + uvicorn.run(app="main:app", host="127.0.0.1", port=65535, reload=True, debug=True) diff --git a/chapter03/more_routers/main.py b/chapter03/3_2_2_more_routers/main.py similarity index 68% rename from chapter03/more_routers/main.py rename to chapter03/3_2_2_more_routers/main.py index 6c12f66..a8aed87 100644 --- a/chapter03/more_routers/main.py +++ b/chapter03/3_2_2_more_routers/main.py @@ -6,25 +6,27 @@ app = FastAPI() + # ============多重URL地址绑定函数============ # ========================================= -@app.get('/', response_class=JSONResponse) -@app.get('/index', response_class=JSONResponse) -@app.post('/index', response_class=JSONResponse) -@app.get("/app/hello", tags=['app实例对象注册接口-示例']) +@app.get("/", response_class=JSONResponse) +@app.get("/index", response_class=JSONResponse) +@app.post("/index", response_class=JSONResponse) +@app.get("/app/hello", tags=["app实例对象注册接口-示例"]) def app_hello(): return {"Hello": "app api"} + # ============同一个URL动态和静态路由========== # ========================================= # 动态路由 -@app.get('/user/{userid}') +@app.get("/user/{userid}") async def login(userid: str): return {"Hello": "dynamic"} # 静态路由 -@app.get('/user/userid') +@app.get("/user/userid") async def login(): return {"Hello": "static"} @@ -35,4 +37,4 @@ async def login(): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/static_dynamic/main.py b/chapter03/3_2_2_static_dynamic/main.py similarity index 53% rename from chapter03/static_dynamic/main.py rename to chapter03/3_2_2_static_dynamic/main.py index 5cf0d2c..1fa6387 100644 --- a/chapter03/static_dynamic/main.py +++ b/chapter03/3_2_2_static_dynamic/main.py @@ -14,27 +14,13 @@ async def index(): return {"index": "index"} + async def index2(): return JSONResponse({"index": "index2"}) -app.add_api_route(path="/index2", endpoint=index2, methods=["GET", "POST"]) - - -router_user = APIRouter(prefix="/user", tags=["用户模块"]) -@router_user.get("/{user}/login") -def user_login(user): - return {"ok": f"用户 {user} login登入成功!"} - -@router_user.api_route("/{user}/api/login", methods=['GET', 'POST']) -def user_api_route_login(user): - return {"ok": f"用户 {user} api登入成功!"} - -def add_user_api_route_login(): - return {"ok": "登入成功!"} +app.add_api_route(path="/index2", endpoint=index2, methods=["GET", "POST"]) -router_user.add_api_route("/user/add/api/login", methods=['GET', 'POST'], endpoint=add_user_api_route_login) -app.include_router(router_user) if __name__ == "__main__": import uvicorn @@ -42,4 +28,4 @@ def add_user_api_route_login(): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/3_3_2_demo_more_routers/main.py b/chapter03/3_2_3_demo_more_routers/main.py similarity index 59% rename from chapter03/3_3_2_demo_more_routers/main.py rename to chapter03/3_2_3_demo_more_routers/main.py index 6fd40c5..4660254 100644 --- a/chapter03/3_3_2_demo_more_routers/main.py +++ b/chapter03/3_2_3_demo_more_routers/main.py @@ -6,6 +6,7 @@ router_user = APIRouter(prefix="/user", tags=["用户模块"]) router_pay = APIRouter(prefix="/pay", tags=["支付模块"]) + @router_user.get("/{user}/login") def user_login(user: str): return {"user": user, "login": f"{user} login success!"} @@ -15,13 +16,29 @@ def user_login(user: str): def user_pay(user: str): return {"user": user, "pay": f"{user} pay success!"} + app.include_router(router_user) app.include_router(router_pay) + +@router_user.api_route("/{user}/api/login", methods=["GET", "POST"]) +def user_api_route_login(user): + return {"ok": f"用户 {user} api登入成功!"} + + +def add_user_api_route_login(): + return {"ok": "登入成功!"} + + +router_user.add_api_route( + "/user/add/api/login", methods=["GET", "POST"], endpoint=add_user_api_route_login +) +app.include_router(router_user) + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) \ No newline at end of file + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/async_sync/main.py b/chapter03/3_3_async_sync/main.py similarity index 90% rename from chapter03/async_sync/main.py rename to chapter03/3_3_async_sync/main.py index 367b7ad..05c3a5e 100644 --- a/chapter03/async_sync/main.py +++ b/chapter03/3_3_async_sync/main.py @@ -5,14 +5,17 @@ import threading import time import asyncio + app = FastAPI(routes=None) + @app.get(path="/async") async def asyncdef(): await asyncio.sleep(3) print("当前协程运行的线程ID:", threading.current_thread().ident) return {"index": "async"} + @app.get(path="/sync") def syncdef(): time.sleep(3) @@ -26,4 +29,4 @@ def syncdef(): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/mount_app/fastapiapp.py b/chapter03/3_4_mount_app/fastapiapp.py similarity index 54% rename from chapter03/mount_app/fastapiapp.py rename to chapter03/3_4_mount_app/fastapiapp.py index de9e188..dbf7a0c 100644 --- a/chapter03/mount_app/fastapiapp.py +++ b/chapter03/3_4_mount_app/fastapiapp.py @@ -4,17 +4,23 @@ from fastapi import FastAPI from fastapi.responses import JSONResponse -app = FastAPI(title='主应用',description="我是主应用文档的描述",version="v1.0.0") -@app.get('/index',summary='首页') +app = FastAPI(title="主应用", description="我是主应用文档的描述", version="v1.0.0") + + +@app.get("/index", summary="首页") async def index(): return JSONResponse({"index": "我是属于主应用的接口!"}) -subapp = FastAPI(title='子应用',description="我是子应用文档的描述",version="v1.0.0") -@subapp.get('/index',summary='首页') + +subapp = FastAPI(title="子应用", description="我是子应用文档的描述", version="v1.0.0") + + +@subapp.get("/index", summary="首页") async def index(): return JSONResponse({"index": "我是属于子应用的接口!"}) -app.mount(path='/subapp',app=subapp,name='subapp') + +app.mount(path="/subapp", app=subapp, name="subapp") if __name__ == "__main__": @@ -23,4 +29,4 @@ async def index(): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/mount_app/flaskapp.py b/chapter03/3_4_mount_app/flaskapp.py similarity index 54% rename from chapter03/mount_app/flaskapp.py rename to chapter03/3_4_mount_app/flaskapp.py index 81cc4a6..dbf7a0c 100644 --- a/chapter03/mount_app/flaskapp.py +++ b/chapter03/3_4_mount_app/flaskapp.py @@ -4,17 +4,23 @@ from fastapi import FastAPI from fastapi.responses import JSONResponse -app = FastAPI(title='主应用',description="我是主应用文档的描述",version="v1.0.0") -@app.get('/index', summary='首页') +app = FastAPI(title="主应用", description="我是主应用文档的描述", version="v1.0.0") + + +@app.get("/index", summary="首页") async def index(): return JSONResponse({"index": "我是属于主应用的接口!"}) -subapp = FastAPI(title='子应用',description="我是子应用文档的描述",version="v1.0.0") -@subapp.get('/index', summary='首页') + +subapp = FastAPI(title="子应用", description="我是子应用文档的描述", version="v1.0.0") + + +@subapp.get("/index", summary="首页") async def index(): return JSONResponse({"index": "我是属于子应用的接口!"}) -app.mount(path='/subapp', app=subapp, name='subapp') + +app.mount(path="/subapp", app=subapp, name="subapp") if __name__ == "__main__": @@ -23,4 +29,4 @@ async def index(): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/localswagger/main.py b/chapter03/3_5_localswagger/main.py similarity index 67% rename from chapter03/localswagger/main.py rename to chapter03/3_5_localswagger/main.py index 6615645..31d8ba4 100644 --- a/chapter03/localswagger/main.py +++ b/chapter03/3_5_localswagger/main.py @@ -2,17 +2,22 @@ # -*- coding: utf-8 -*- - from fastapi import FastAPI -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles import pathlib app = FastAPI(docs_url=None) -app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") +app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" +) -@app.get('/docs', include_in_schema=False) +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -20,13 +25,14 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/localswagger/static/swagger-ui-bundle.js b/chapter03/3_5_localswagger/static/swagger-ui-bundle.js similarity index 100% rename from chapter03/localswagger/static/swagger-ui-bundle.js rename to chapter03/3_5_localswagger/static/swagger-ui-bundle.js diff --git a/chapter03/localswagger/static/swagger-ui.css b/chapter03/3_5_localswagger/static/swagger-ui.css similarity index 100% rename from chapter03/localswagger/static/swagger-ui.css rename to chapter03/3_5_localswagger/static/swagger-ui.css diff --git a/chapter03/background_tasks/main.py b/chapter03/background_tasks/main.py index 8ae376e..f5e6548 100644 --- a/chapter03/background_tasks/main.py +++ b/chapter03/background_tasks/main.py @@ -4,21 +4,26 @@ from fastapi import FastAPI from starlette.background import BackgroundTasks import time + app = FastAPI(routes=None) import asyncio + + def send_mail(n): time.sleep(n) + @app.api_route(path="/index", methods=["GET", "POST"]) async def index(tasks: BackgroundTasks): tasks.add_task(send_mail, 10) print(id(asyncio.get_event_loop())) return {"index": "index"} + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/close_docs/main.py b/chapter03/close_docs/main.py index 28bd56b..e4c781d 100644 --- a/chapter03/close_docs/main.py +++ b/chapter03/close_docs/main.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from fastapi import FastAPI + app = FastAPI( docs_url=None, redoc_url=None, @@ -14,4 +15,4 @@ app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/configparser_config/main.py b/chapter03/configparser_config/main.py index 2969437..ca1a95b 100644 --- a/chapter03/configparser_config/main.py +++ b/chapter03/configparser_config/main.py @@ -5,13 +5,13 @@ import configparser config = configparser.ConfigParser() -config.read('conf.ini', encoding='utf-8') +config.read("conf.ini", encoding="utf-8") app = FastAPI( - debug=bool(config.get('fastapi_config', 'debug')), - title=config.get('fastapi_config', 'title'), - description=config.get('fastapi_config', 'description'), - version=config.get('fastapi_config', 'version'), + debug=bool(config.get("fastapi_config", "debug")), + title=config.get("fastapi_config", "title"), + description=config.get("fastapi_config", "description"), + version=config.get("fastapi_config", "version"), ) if __name__ == "__main__": @@ -20,4 +20,4 @@ app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/env_config/main.py b/chapter03/env_config/main.py index f026b45..98e8065 100644 --- a/chapter03/env_config/main.py +++ b/chapter03/env_config/main.py @@ -14,7 +14,7 @@ class Settings(BaseSettings): class Config: env_file = ".env" - env_file_encoding = 'utf-8' + env_file_encoding = "utf-8" @validator("version", pre=True) def version_len_check(cls, v: str) -> Optional[str]: @@ -22,17 +22,19 @@ def version_len_check(cls, v: str) -> Optional[str]: return None return v + @lru_cache() def get_settings(): return Settings() + settings = Settings() print(settings.debug) print(settings.title) print(settings.description) print(settings.version) -settings = Settings(_env_file='.env', _env_file_encoding='utf-8') +settings = Settings(_env_file=".env", _env_file_encoding="utf-8") app = FastAPI( debug=settings.debug, title=settings.title, @@ -44,6 +46,7 @@ def get_settings(): if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/global_exception/main.py b/chapter03/global_exception/main.py index 32738f6..8f8be95 100644 --- a/chapter03/global_exception/main.py +++ b/chapter03/global_exception/main.py @@ -4,11 +4,13 @@ from fastapi import FastAPI from starlette.responses import JSONResponse + async def exception_not_found(request, exc): - return JSONResponse({ - "code": exc.status_code, - "error": "没有定义这个请求地址"}, - status_code=exc.status_code) + return JSONResponse( + {"code": exc.status_code, "error": "没有定义这个请求地址"}, + status_code=exc.status_code, + ) + exception_handlers = { 404: exception_not_found, @@ -23,4 +25,4 @@ async def exception_not_found(request, exc): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_body/main.py b/chapter03/parameter_body/main.py index 8c7b4b5..1ea9662 100644 --- a/chapter03/parameter_body/main.py +++ b/chapter03/parameter_body/main.py @@ -21,40 +21,40 @@ class Item(BaseModel): @app.post("/action/") def callback(item: Item): return { - 'user_id': item.user_id, - 'article_id': item.article_id, - 'token': item.token, - 'timestamp': item.timestamp + "user_id": item.user_id, + "article_id": item.article_id, + "token": item.token, + "timestamp": item.timestamp, } @app.post("/action/body") def callbackbody( - token: str = Body(...), - user_id: int = Body(..., gt=10), - timestamp: str = Body(...), - article_id: str = Body(default=None), + token: str = Body(...), + user_id: int = Body(..., gt=10), + timestamp: str = Body(...), + article_id: str = Body(default=None), ): return { - 'user_id': user_id, - 'article_id': article_id, - 'token': token, - 'timestamp': timestamp + "user_id": user_id, + "article_id": article_id, + "token": token, + "timestamp": timestamp, } @app.post("/action/body2") def callbackbody( - token: str = Body(default=None), - user_id: int = Body(default=None, gt=10), - timestamp: str = Body(default=None), - article_id: str = Body(default=None), + token: str = Body(default=None), + user_id: int = Body(default=None, gt=10), + timestamp: str = Body(default=None), + article_id: str = Body(default=None), ): return { - 'user_id': user_id, - 'article_id': article_id, - 'token': token, - 'timestamp': timestamp + "user_id": user_id, + "article_id": article_id, + "token": token, + "timestamp": timestamp, } @@ -67,9 +67,7 @@ class Itement(BaseModel): @app.post("/action/body3") def callbackbody(item: Itement = Body(default=None, embed=False)): - return { - 'body': item - } + return {"body": item} # ================= @@ -92,8 +90,7 @@ async def update_item1111(item: ItemUser, user: User): @app.put("/items/more") -async def update_item(item: Item, user: User, importance: int = Body(..., gt=0) - ): +async def update_item(item: Item, user: User, importance: int = Body(..., gt=0)): results = {"item": item, "user": user, "importance": importance} return results @@ -107,8 +104,7 @@ class ItemUser2(BaseModel): @app.put("/items/body4") -async def update_item(item: ItemUser2, importance: int = Body(..., gt=0) - ): +async def update_item(item: ItemUser2, importance: int = Body(..., gt=0)): results = {"item": item, "user": item.user, "importance": importance} return results @@ -136,4 +132,4 @@ async def update_item(item: ItemUser3, importance: int = Body(..., gt=0)): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_cookie/main.py b/chapter03/parameter_cookie/main.py index ea1327e..9f2a066 100644 --- a/chapter03/parameter_cookie/main.py +++ b/chapter03/parameter_cookie/main.py @@ -13,13 +13,13 @@ @app.get("/set_cookie/") def setcookie(response: Response): response.set_cookie(key="xiaozhong", value="chengxuyuan-xiaozhongtongxue") - return 'set_cookie ok!' + return "set_cookie ok!" + @app.get("/get_cookie") async def Cookier_handel(xiaozhong: Optional[str] = Cookie(None)): - return { - 'xiaozhong':xiaozhong - } + return {"xiaozhong": xiaozhong} + if __name__ == "__main__": import uvicorn @@ -27,4 +27,4 @@ async def Cookier_handel(xiaozhong: Optional[str] = Cookie(None)): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_form_and_file/main.py b/chapter03/parameter_form_and_file/main.py index e26f675..51968cc 100644 --- a/chapter03/parameter_form_and_file/main.py +++ b/chapter03/parameter_form_and_file/main.py @@ -12,63 +12,70 @@ app = FastAPI() - - @app.post("/demo/login/") -async def login(username: str = Form(...,title="用户名",description="用户名字段描述", max_length=5), - password: str = Form(...,title="用户密码",description="用户密码字段描述", max_length=20)): +async def login( + username: str = Form( + ..., title="用户名", description="用户名字段描述", max_length=5 + ), + password: str = Form( + ..., title="用户密码", description="用户密码字段描述", max_length=20 + ), +): return {"username": username, "password": password} -@app.post("/sync_file",summary='File形式的-单文件上传') +@app.post("/sync_file", summary="File形式的-单文件上传") def sync_file(file: bytes = File(...)): - ''' + """ 基于使用File类 文件内容会以bytes的形式读入内存通常主要用于上传小的文件 :param file: :return: - ''' - with open('./data.bat', 'wb') as f: + """ + with open("./data.bat", "wb") as f: f.write(file) - return {'file_size': len(file)} + return {"file_size": len(file)} + -@app.post("/async_file",summary='File形式的-单文件上传') +@app.post("/async_file", summary="File形式的-单文件上传") async def async_file(file: bytes = File(...)): - ''' + """ 基于使用File类 使用异步的方式进行文件接收处理 :param file: :return: - ''' + """ # 异步方式执行with操作,修改为 async with async with aiofiles.open("./data.bat", "wb") as fp: await fp.write(file) - return {'file_size': len(file)} + return {"file_size": len(file)} # 多文件的上传 -@app.post("/sync_file2",summary='File列表形式的-多文件上传') +@app.post("/sync_file2", summary="File列表形式的-多文件上传") def sync_file2(files: List[bytes] = File(...)): - ''' + """ 基于使用File类 运行多文件上传处理 :param files: :return: - ''' + """ return {"file_sizes": [len(file) for file in files]} -@app.post("/uploadfiles",summary='UploadFile形式的-单文件上传') + +@app.post("/uploadfiles", summary="UploadFile形式的-单文件上传") async def uploadfiles(file: UploadFile = File(...)): result = { "filename": file.filename, "content-type": file.content_type, } content = await file.read() - with open(f"./{file.filename}", 'wb') as f: + with open(f"./{file.filename}", "wb") as f: f.write(content) return result + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_header/main.py b/chapter03/parameter_header/main.py index 130bb66..5dbcccb 100644 --- a/chapter03/parameter_header/main.py +++ b/chapter03/parameter_header/main.py @@ -9,27 +9,29 @@ @app.get("/demo/header/") -async def read_items(user_agent: Optional[str] = Header(None,convert_underscores=True), - accept_encoding: Optional[str] = Header(None,convert_underscores=True), - accept: Optional[str] = Header(None), - accept_token: Optional[str] = Header(...,convert_underscores=False), - ): +async def read_items( + user_agent: Optional[str] = Header(None, convert_underscores=True), + accept_encoding: Optional[str] = Header(None, convert_underscores=True), + accept: Optional[str] = Header(None), + accept_token: Optional[str] = Header(..., convert_underscores=False), +): return { "user_agent": user_agent, "accept_encoding": accept_encoding, "accept": accept, "token": accept_token, - } + @app.get("/headerlist/") async def read_headerlist(x_token: List[str] = Header(None)): return {"X-Token values": x_token} + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_path/main.py b/chapter03/parameter_path/main.py index 6fc12b1..04c87fa 100644 --- a/chapter03/parameter_path/main.py +++ b/chapter03/parameter_path/main.py @@ -8,33 +8,30 @@ app = FastAPI() -@app.post("/parameter/", summary='我是路径参数', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) +@app.post( + "/parameter/", + summary="我是路径参数", + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, +) async def parameter(q: List[str] = Query(["test1", "test2"])): return { - 'message': q, + "message": q, } @app.get("/user/{user_id}/article/{article_id}") async def callback(user_id: int, article_id: str): - return { - 'user_id': user_id, - 'article_id': article_id - } + return {"user_id": user_id, "article_id": article_id} @app.get("/uls/{file_path}") async def callback_file_path(file_path: str): - return { - 'file_path': file_path - } + return {"file_path": file_path} @app.get("/uls/{file_path:path}") async def callback_file_path_2(file_path: str): - return { - 'file_path': file_path - } + return {"file_path": file_path} class ModelName(str, Enum): @@ -53,17 +50,29 @@ async def get_model(model_name: ModelName): @app.get("/pay/{user_id}/article/{article_id}") -async def callback(user_id: int = Path(..., title="用户ID", description='用户ID信息', ge=10000), - article_id: str = Path(..., title="文章ID", description='用户所属文章ID信息', min_length=1, - max_length=50)): - return { - 'user_id': user_id, - 'article_id': article_id - } +async def callback( + user_id: int = Path(..., title="用户ID", description="用户ID信息", ge=10000), + article_id: str = Path( + ..., + title="文章ID", + description="用户所属文章ID信息", + min_length=1, + max_length=50, + ), +): + return {"user_id": user_id, "article_id": article_id} + @app.get("/items/{item_id}") -async def callback(*,item_id: int = Path(...,), q: str): - return 'OK' +async def callback( + *, + item_id: int = Path( + ..., + ), + q: str, +): + return "OK" + if __name__ == "__main__": import uvicorn @@ -71,4 +80,4 @@ async def callback(*,item_id: int = Path(...,), q: str): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_query/main.py b/chapter03/parameter_query/main.py index cb82a46..dff249f 100644 --- a/chapter03/parameter_query/main.py +++ b/chapter03/parameter_query/main.py @@ -9,36 +9,30 @@ @app.get("/query/") -async def callback(user_id: int, user_name: Optional[str] = None, user_token: str = 'token'): - return { - 'user_id': user_id, - 'user_name': user_name, - 'user_token': user_token - } +async def callback( + user_id: int, user_name: Optional[str] = None, user_token: str = "token" +): + return {"user_id": user_id, "user_name": user_name, "user_token": user_token} + @app.get("/query/bool/") async def callback(isbool: bool = False): - return { - 'isbool': isbool - } + return {"isbool": isbool} + @app.get("/query/morequery") async def callback( - user_id: int = Query(..., ge=10, le=100), - user_name: str = Query(None, min_length=1, max_length=50, regex="^fixedquery$"), - user_token: str = Query(default='token', min_length=1, max_length=50), + user_id: int = Query(..., ge=10, le=100), + user_name: str = Query(None, min_length=1, max_length=50, regex="^fixedquery$"), + user_token: str = Query(default="token", min_length=1, max_length=50), ): - return { - 'user_id': user_id, - 'user_name': user_name, - 'user_token': user_token - } + return {"user_id": user_id, "user_name": user_name, "user_token": user_token} + @app.get("/query/list/") async def query_list(q: List[str] = Query(["test1", "test2"])): - return { - 'q': q - } + return {"q": q} + if __name__ == "__main__": import uvicorn @@ -46,4 +40,4 @@ async def query_list(q: List[str] = Query(["test1", "test2"])): app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_request/main.py b/chapter03/parameter_request/main.py index 5cd3305..afeac06 100644 --- a/chapter03/parameter_request/main.py +++ b/chapter03/parameter_request/main.py @@ -13,21 +13,23 @@ @app.get("/get_request/") async def get_request(request: Request): - form_data= await request.form() + form_data = await request.form() body_data = await request.body() return { - 'url':request.url, - 'base_url': request.base_url, - 'client_host ': request.client.host, - 'query_params': request.query_params, - 'json_data':await request.json() if body_data else None, - 'form_data':form_data, - 'body_data': body_data, + "url": request.url, + "base_url": request.base_url, + "client_host ": request.client.host, + "query_params": request.query_params, + "json_data": await request.json() if body_data else None, + "form_data": form_data, + "body_data": body_data, } + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_file_response.py b/chapter03/parameter_response/main_file_response.py index db031f0..179bbb4 100644 --- a/chapter03/parameter_response/main_file_response.py +++ b/chapter03/parameter_response/main_file_response.py @@ -14,21 +14,29 @@ @app.post("/dwonfile1") def sync_dwonfile(): - return FileResponse(path='./data.bat',filename='data.bat',media_type="application/octet-stream") - + return FileResponse( + path="./data.bat", filename="data.bat", media_type="application/octet-stream" + ) @app.post("/dwonfile1") def sync_dwonfile(): - return FileResponse(path='./data.bat',filename='data.bat',media_type="application/octet-stream") + return FileResponse( + path="./data.bat", filename="data.bat", media_type="application/octet-stream" + ) + @app.post("/dwonfile2") async def async_dwonfile(): - return FileResponse(path='./data.bat',filename='data.bat',media_type="application/octet-stream") + return FileResponse( + path="./data.bat", filename="data.bat", media_type="application/octet-stream" + ) + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_html_response.py b/chapter03/parameter_response/main_html_response.py index 69d3322..65be56f 100644 --- a/chapter03/parameter_response/main_html_response.py +++ b/chapter03/parameter_response/main_html_response.py @@ -13,6 +13,7 @@ from fastapi.responses import HTMLResponse + def generate_html_response(): html_content = """ @@ -26,13 +27,16 @@ def generate_html_response(): """ return HTMLResponse(content=html_content, status_code=200) + @app.get("/", response_class=HTMLResponse) async def index(): return generate_html_response() + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_json_response.py b/chapter03/parameter_response/main_json_response.py index e5641eb..ace30c6 100644 --- a/chapter03/parameter_response/main_json_response.py +++ b/chapter03/parameter_response/main_json_response.py @@ -11,19 +11,21 @@ app = FastAPI() - @app.post("/api/v1/json1/") async def index(): # 默认返回类型就是JSONResponse return {"code": 0, "msg": "ok", "data": None} + @app.post("/api/v1/json2/") async def index(): return JSONResponse(status_code=404, content={"code": 0, "msg": "ok", "data": None}) + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_plain_text_response.py b/chapter03/parameter_response/main_plain_text_response.py index 8bf0553..23adaef 100644 --- a/chapter03/parameter_response/main_plain_text_response.py +++ b/chapter03/parameter_response/main_plain_text_response.py @@ -13,15 +13,18 @@ @app.post("/api/v1/text1/") async def index(): - return 'ok' + return "ok" + @app.post("/api/v1/text2/") async def index(): - return PlainTextResponse(status_code=404, content='ok') + return PlainTextResponse(status_code=404, content="ok") + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_redirect_response.py b/chapter03/parameter_response/main_redirect_response.py index 00bd9bf..9c34c2c 100644 --- a/chapter03/parameter_response/main_redirect_response.py +++ b/chapter03/parameter_response/main_redirect_response.py @@ -3,39 +3,39 @@ from fastapi import FastAPI -from starlette.responses import HTMLResponse, RedirectResponse +from starlette.responses import HTMLResponse, RedirectResponse app = FastAPI() - @app.get("/baidu", response_class=HTMLResponse) async def index(): - # 外部地址重定向 - return RedirectResponse("https://wwww.baidu.com") + # 外部地址重定向 + return RedirectResponse("https://wwww.baidu.com") + @app.get("/redirect1") async def index(): - # 内部地址重定向 - return RedirectResponse("/index",status_code=301) + # 内部地址重定向 + return RedirectResponse("/index", status_code=301) @app.get("/redirect2") async def index(): - # 内部地址重定向 - return RedirectResponse("/index",status_code=302) + # 内部地址重定向 + return RedirectResponse("/index", status_code=302) + @app.get("/index") async def index(): - return { - 'code':200, - 'messgaee':'重定向成功' - } + return {"code": 200, "messgaee": "重定向成功"} + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_response_model.py b/chapter03/parameter_response/main_response_model.py index 94ffd8b..e3f1c3a 100644 --- a/chapter03/parameter_response/main_response_model.py +++ b/chapter03/parameter_response/main_response_model.py @@ -11,6 +11,7 @@ app = FastAPI() + class UserIn(BaseModel): username: str password: str @@ -27,6 +28,8 @@ class UserOut(BaseModel): @app.post("/user/", response_model=UserOut) async def create_user(*, user: UserIn): return user + + @app.post("/user/", response_model=UserOut) async def create_user(*, user: UserIn): return user @@ -35,6 +38,7 @@ async def create_user(*, user: UserIn): if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_status_code.py b/chapter03/parameter_response/main_status_code.py index 51f64b8..9d01c54 100644 --- a/chapter03/parameter_response/main_status_code.py +++ b/chapter03/parameter_response/main_status_code.py @@ -14,31 +14,39 @@ @app.get("/set_http_code/demo1/", status_code=500) async def set_http_code(): return { - 'message': 'ok', + "message": "ok", } + @app.get("/set_http_code/demo2/", status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) async def set_http_code(): return { - 'message': 'ok', + "message": "ok", } + @app.get("/set_http_code/demo3/") async def set_http_code(response: Response): response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR return { - 'message': 'ok', + "message": "ok", } + @app.get("/set_http_code/demo4/") async def set_http_code(): - return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ - 'message': 'ok', - }) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "message": "ok", + }, + ) + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_streaming_response.py b/chapter03/parameter_response/main_streaming_response.py index 69c5b6b..b8cd4d1 100644 --- a/chapter03/parameter_response/main_streaming_response.py +++ b/chapter03/parameter_response/main_streaming_response.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from fastapi import FastAPI -from starlette.responses import HTMLResponse, RedirectResponse +from starlette.responses import HTMLResponse, RedirectResponse from os import getcwd, path import cv2 @@ -15,6 +15,7 @@ video_path = Path("big_buck_bunny.mp4") + def read_in_chunks(): # 读取视频位置 videoPath = "./big_buck_bunny.mp4" # 读取视频路径 @@ -33,7 +34,10 @@ def read_in_chunks(): # 设置播放帧的速度等待时间 cv2.waitKey(1) # 迭代返回对应的数据帧 - yield (b'--frame\r\n' b'Content-Type: image/jpeg/\r\n\r\n' + bytearray(encodedImage) + b'\r\n') + yield ( + b"--frame\r\n" + b"Content-Type: image/jpeg/\r\n\r\n" + bytearray(encodedImage) + b"\r\n" + ) else: break # 释放 @@ -43,11 +47,15 @@ def read_in_chunks(): @app.get("/streamvideo") def main(): # 迭代的方式返回流数据 - return StreamingResponse(read_in_chunks(), media_type="multipart/x-mixed-replace;boundary=frame") + return StreamingResponse( + read_in_chunks(), media_type="multipart/x-mixed-replace;boundary=frame" + ) + if __name__ == "__main__": import uvicorn import os + app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/parameter_response/main_xml_response.py b/chapter03/parameter_response/main_xml_response.py index 9f0c7c2..c65e12a 100644 --- a/chapter03/parameter_response/main_xml_response.py +++ b/chapter03/parameter_response/main_xml_response.py @@ -10,6 +10,7 @@ app = FastAPI() + @app.get("/xml/") def get_xml_data(): data = """ @@ -22,10 +23,11 @@ def get_xml_data(): """ return Response(content=data, media_type="application/xml") + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/startup_shutdown/main.py b/chapter03/startup_shutdown/main.py index 26eae34..0cce27a 100644 --- a/chapter03/startup_shutdown/main.py +++ b/chapter03/startup_shutdown/main.py @@ -7,15 +7,18 @@ app = FastAPI() + # 生命周期异步上下文管理器处理程序代替单独的启动和关闭处理程序 @app.on_event("startup") async def startup_event_async(): print("服务进程启动成功-async函数") + @app.on_event("startup") def startup_event_sync(): print("服务进程启动成功-sync函数") + @app.on_event("shutdown") async def shutdown_event_async(): print("服务进程已关闭-async函数") @@ -25,10 +28,11 @@ async def shutdown_event_async(): def shutdown_event_sync(): print("服务进程已关闭-sync函数") + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter03/swaggershow/main.py b/chapter03/swaggershow/main.py index 1fb817d..0416f62 100644 --- a/chapter03/swaggershow/main.py +++ b/chapter03/swaggershow/main.py @@ -5,13 +5,13 @@ app = FastAPI( title="文档的标题", - description='关于该API文档一些描述信息补充说明', - version='v1.0.0', - openapi_prefix='', + description="关于该API文档一些描述信息补充说明", + version="v1.0.0", + openapi_prefix="", swagger_ui_oauth2_redirect_url="/docs/oauth2-redirect", swagger_ui_init_oauth=None, - docs_url='/docs', - redoc_url='/redoc', + docs_url="/docs", + redoc_url="/redoc", openapi_url="/openapi/openapi_json.json", terms_of_service="https://terms/团队的官网网站/", deprecated=True, @@ -35,17 +35,19 @@ {"url": "/", "description": "本地调试环境"}, {"url": "https://xx.xx.com", "description": "线上测试环境"}, {"url": "https://xx2.xx2.com", "description": "线上生产环境"}, - ] + ], ) + @app.get(path="/index") async def index(): return {"index": "index"} + if __name__ == "__main__": import uvicorn import os app_model_name = os.path.basename(__file__).replace(".py", "") print(app_model_name) - uvicorn.run(f"{app_model_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_model_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter04/business_error/main.py b/chapter04/business_error/main.py index aec402f..0e0e2aa 100644 --- a/chapter04/business_error/main.py +++ b/chapter04/business_error/main.py @@ -8,6 +8,8 @@ from enum import Enum + + class ExceptionEnum(Enum): SUCCESS = ("0000", "OK") FAILED = ("9999", "系统异常") @@ -15,9 +17,16 @@ class ExceptionEnum(Enum): USER_REGIESTER_ERROR = ("10002", "注册异常") PERMISSIONS_ERROR = ("2000", "用户权限错误") + class BusinessError(Exception): - __slots__ = ['err_code', 'err_code_des'] - def __init__(self, result: ExceptionEnum = None, err_code: str = "00000", err_code_des: str = ""): + __slots__ = ["err_code", "err_code_des"] + + def __init__( + self, + result: ExceptionEnum = None, + err_code: str = "00000", + err_code_des: str = "", + ): if result: self.err_code = result.value[0] self.err_code_des = err_code_des or result.value[1] @@ -26,18 +35,21 @@ def __init__(self, result: ExceptionEnum = None, err_code: str = "00000", err_c self.err_code_des = err_code_des super().__init__(self) + @app.exception_handler(BusinessError) async def custom_exception_handler(request: Request, exc: BusinessError): - return JSONResponse(content={ - 'return_code':'FAIL', - 'return_msg':'参数错误', - 'err_code': exc.err_code, - 'err_code_des': exc.err_code_des, - }) + return JSONResponse( + content={ + "return_code": "FAIL", + "return_msg": "参数错误", + "err_code": exc.err_code, + "err_code_des": exc.err_code_des, + } + ) @app.get("/custom_exception") -async def custom_exception(name: str = 'zhong'): +async def custom_exception(name: str = "zhong"): if name == "xiaozhong": raise BusinessError(ExceptionEnum.USER_NO_DATA) return {"name": name} @@ -49,4 +61,4 @@ async def custom_exception(name: str = 'zhong'): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter04/custom_exception/main.py b/chapter04/custom_exception/main.py index af1a4ea..6d315fe 100644 --- a/chapter04/custom_exception/main.py +++ b/chapter04/custom_exception/main.py @@ -14,13 +14,15 @@ def __init__(self, message: str): @app.exception_handler(CustomException) async def custom_exception_handler(request: Request, exc: CustomException): - return JSONResponse(content={"message": exc.message}, ) + return JSONResponse( + content={"message": exc.message}, + ) @app.get("/custom_exception") -async def read_unicorn(name: str = 'zhong'): +async def read_unicorn(name: str = "zhong"): if name == "zhong": - raise CustomException(message='抛出自定义异常') + raise CustomException(message="抛出自定义异常") return {"name": name} @@ -30,4 +32,4 @@ async def read_unicorn(name: str = 'zhong'): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter04/http_exception/main.py b/chapter04/http_exception/main.py index ae42477..acbbdc4 100644 --- a/chapter04/http_exception/main.py +++ b/chapter04/http_exception/main.py @@ -11,20 +11,28 @@ app = FastAPI() + @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): - return JSONResponse(status_code=exc.status_code, content=exc.detail, headers=exc.headers) + return JSONResponse( + status_code=exc.status_code, content=exc.detail, headers=exc.headers + ) + @app.get("/http_exception") -async def http_exception(action_scopes: str = Query(default='admin')): - if action_scopes == 'admin': - raise HTTPException(status_code=403, - headers={"x-auth": "NO AUTH!"}, - detail={ - 'code': '403', - 'message': '错误当前你没有权限访问', - }) - return {'code': '200', } +async def http_exception(action_scopes: str = Query(default="admin")): + if action_scopes == "admin": + raise HTTPException( + status_code=403, + headers={"x-auth": "NO AUTH!"}, + detail={ + "code": "403", + "message": "错误当前你没有权限访问", + }, + ) + return { + "code": "200", + } if __name__ == "__main__": @@ -33,4 +41,4 @@ async def http_exception(action_scopes: str = Query(default='admin')): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='0.0.0.0', port=9082, workers=3) + uvicorn.run(f"{app_modeel_name}:app", host="0.0.0.0", port=9082, workers=3) diff --git a/chapter04/middleware_exception/main.py b/chapter04/middleware_exception/main.py index 1dedece..174b902 100644 --- a/chapter04/middleware_exception/main.py +++ b/chapter04/middleware_exception/main.py @@ -7,12 +7,11 @@ app = FastAPI() - @app.middleware("http") async def add_process_time_header(request: Request, call_next): # 故意直接的抛出异常tr - raise CustomException(message='抛出自定义异常') + raise CustomException(message="抛出自定义异常") response = await call_next(request) return response @@ -26,18 +25,23 @@ def __init__(self, message: str): @app.exception_handler(Exception) async def custom_exception_handler(request: Request, exc: Exception): print("触发全局自定义Exception") - if isinstance(exc,CustomException): + if isinstance(exc, CustomException): print("触发全局自定义CustomException") - return JSONResponse(content={"message": exc.message}, ) + return JSONResponse( + content={"message": exc.message}, + ) + @app.exception_handler(CustomException) async def custom_exception_handler(request: Request, exc: CustomException): print("触发全局自定义CustomException") - return JSONResponse(content={"message": exc.message}, ) + return JSONResponse( + content={"message": exc.message}, + ) @app.get("/custom_exception") -async def read_unicorn(name: str = 'zhong'): +async def read_unicorn(name: str = "zhong"): return {"name": name} @@ -45,6 +49,7 @@ async def read_unicorn(name: str = 'zhong'): if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter04/request_validation_error/main.py b/chapter04/request_validation_error/main.py index 34a9838..468737c 100644 --- a/chapter04/request_validation_error/main.py +++ b/chapter04/request_validation_error/main.py @@ -8,9 +8,12 @@ app = FastAPI() + @app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): - return JSONResponse({'mes':'触发了RequestValidationError错误,,错误信息:%s !'%(str(exc))}) + return JSONResponse( + {"mes": "触发了RequestValidationError错误,,错误信息:%s !" % (str(exc))} + ) @app.get("/request_exception/") @@ -23,10 +26,11 @@ async def websocket_endpoint(websocket: WebSocket, user: str): pass websocket.query_params + if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter05/body/main.py b/chapter05/body/main.py index 30c0d0a..c1fec01 100644 --- a/chapter05/body/main.py +++ b/chapter05/body/main.py @@ -5,26 +5,41 @@ class User(BaseModel): - username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") - age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12) - password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', gl=6, example=6) - password_new: str = Field(..., title='新密码', description='密码需要长度大于6', gl=6, example=6) + username: str = Field( + ..., + title="姓名", + description="姓名字段需要长度大于6且小于等于12", + max_length=12, + min_length=6, + example="Foo", + ) + age: int = Field( + ..., title="年龄", description="年龄需要大于18岁", ge=18, example=12 + ) + password_old: str = Field( + ..., title="旧密码", description="密码需要长度大于6", gl=6, example=6 + ) + password_new: str = Field( + ..., title="新密码", description="密码需要长度大于6", gl=6, example=6 + ) @root_validator def check_passwords(cls, values): - password_old, password_new = values.get('password_old'), values.get('password_new') + password_old, password_new = values.get("password_old"), values.get( + "password_new" + ) # 新旧号码的确认匹配处理 if password_old and password_new and password_old != password_new: - raise ValueError('passwords do not match') + raise ValueError("passwords do not match") return values @app.post("/user") def read_user(user: User): return { - 'username': user.username, - 'password_old': user.password_old, - 'password_new': user.password_new, + "username": user.username, + "password_old": user.password_old, + "password_new": user.password_new, } @@ -34,4 +49,4 @@ def read_user(user: User): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter05/pydantic_base/main.py b/chapter05/pydantic_base/main.py index 67a773e..0f35410 100644 --- a/chapter05/pydantic_base/main.py +++ b/chapter05/pydantic_base/main.py @@ -2,12 +2,18 @@ # -*- coding: utf-8 -*- from typing import Union, Optional, List -from pydantic import BaseModel, \ - DirectoryPath, \ - IPvAnyAddress, \ - FilePath, \ - EmailStr, \ - NameEmail, SecretStr, SecretBytes, ValidationError, HttpUrl +from pydantic import ( + BaseModel, + DirectoryPath, + IPvAnyAddress, + FilePath, + EmailStr, + NameEmail, + SecretStr, + SecretBytes, + ValidationError, + HttpUrl, +) from datetime import date @@ -31,9 +37,9 @@ class Person(BaseModel): website: HttpUrl -if __name__ == '__main__': +if __name__ == "__main__": try: - user = Person(name='xiaozhong') + user = Person(name="xiaozhong") except ValidationError as e: print(e.errors()) print(e.json()) diff --git a/chapter05/pydantic_fastapi_get/main.py b/chapter05/pydantic_fastapi_get/main.py index 7fbe130..4c752c8 100644 --- a/chapter05/pydantic_fastapi_get/main.py +++ b/chapter05/pydantic_fastapi_get/main.py @@ -1,42 +1,64 @@ from fastapi import FastAPI, UploadFile, File from pydantic import BaseModel, root_validator, Field from fastapi import Depends + app = FastAPI() class User(BaseModel): - username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") - age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12) - password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', gl=6, example=6) - password_new: str = Field(..., title='新密码', description='密码需要长度大于6', gl=6, example=6) + username: str = Field( + ..., + title="姓名", + description="姓名字段需要长度大于6且小于等于12", + max_length=12, + min_length=6, + example="Foo", + ) + age: int = Field( + ..., title="年龄", description="年龄需要大于18岁", ge=18, example=12 + ) + password_old: str = Field( + ..., title="旧密码", description="密码需要长度大于6", gl=6, example=6 + ) + password_new: str = Field( + ..., title="新密码", description="密码需要长度大于6", gl=6, example=6 + ) @root_validator def check_passwords(cls, values): - password_old, password_new = values.get('password_old'), values.get('password_new') + password_old, password_new = values.get("password_old"), values.get( + "password_new" + ) # 新旧号码的确认匹配处理 if password_old and password_new and password_old != password_new: - raise ValueError('passwords do not match') + raise ValueError("passwords do not match") return values @app.get("/user") -def read_user(user: User=Depends()): +def read_user(user: User = Depends()): return { - 'username': user.username, - 'password_old': user.password_old, - 'password_new': user.password_new, + "username": user.username, + "password_old": user.password_old, + "password_new": user.password_new, } + class FileGet(BaseModel): - username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") + username: str = Field( + ..., + title="姓名", + description="姓名字段需要长度大于6且小于等于12", + max_length=12, + min_length=6, + example="Foo", + ) file: UploadFile = File(...) + @app.post("/file_get") -async def file_get(user: FileGet=Depends()): - return { - 'username': user.username, - 'filenme': user.file.filename - } +async def file_get(user: FileGet = Depends()): + return {"username": user.username, "filenme": user.file.filename} if __name__ == "__main__": @@ -45,4 +67,4 @@ async def file_get(user: FileGet=Depends()): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter05/pydantic_fastapi_post/main.py b/chapter05/pydantic_fastapi_post/main.py index 30c0d0a..c1fec01 100644 --- a/chapter05/pydantic_fastapi_post/main.py +++ b/chapter05/pydantic_fastapi_post/main.py @@ -5,26 +5,41 @@ class User(BaseModel): - username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") - age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12) - password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', gl=6, example=6) - password_new: str = Field(..., title='新密码', description='密码需要长度大于6', gl=6, example=6) + username: str = Field( + ..., + title="姓名", + description="姓名字段需要长度大于6且小于等于12", + max_length=12, + min_length=6, + example="Foo", + ) + age: int = Field( + ..., title="年龄", description="年龄需要大于18岁", ge=18, example=12 + ) + password_old: str = Field( + ..., title="旧密码", description="密码需要长度大于6", gl=6, example=6 + ) + password_new: str = Field( + ..., title="新密码", description="密码需要长度大于6", gl=6, example=6 + ) @root_validator def check_passwords(cls, values): - password_old, password_new = values.get('password_old'), values.get('password_new') + password_old, password_new = values.get("password_old"), values.get( + "password_new" + ) # 新旧号码的确认匹配处理 if password_old and password_new and password_old != password_new: - raise ValueError('passwords do not match') + raise ValueError("passwords do not match") return values @app.post("/user") def read_user(user: User): return { - 'username': user.username, - 'password_old': user.password_old, - 'password_new': user.password_new, + "username": user.username, + "password_old": user.password_old, + "password_new": user.password_new, } @@ -34,4 +49,4 @@ def read_user(user: User): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter05/pydantic_field/main.py b/chapter05/pydantic_field/main.py index 0e87440..78e0f73 100644 --- a/chapter05/pydantic_field/main.py +++ b/chapter05/pydantic_field/main.py @@ -7,13 +7,25 @@ class User(BaseModel): - name: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") - age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12) - password: str = Field(..., title='密码', description='密码需要长度大于6', gl=6, example=6) + name: str = Field( + ..., + title="姓名", + description="姓名字段需要长度大于6且小于等于12", + max_length=12, + min_length=6, + example="Foo", + ) + age: int = Field( + ..., title="年龄", description="年龄需要大于18岁", ge=18, example=12 + ) + password: str = Field( + ..., title="密码", description="密码需要长度大于6", gl=6, example=6 + ) tax: Optional[float] = Field(None, example=3.2) -if __name__ == '__main__': - user=User(name='xiaozhong',age=18,password='xxxxxxxxxxx') + +if __name__ == "__main__": + user = User(name="xiaozhong", age=18, password="xxxxxxxxxxx") print(user.name) print(user.age) print(user.password) diff --git a/chapter05/pydantic_obj_to_dict_json/main.py b/chapter05/pydantic_obj_to_dict_json/main.py index 8dfcc6a..458e3dc 100644 --- a/chapter05/pydantic_obj_to_dict_json/main.py +++ b/chapter05/pydantic_obj_to_dict_json/main.py @@ -13,10 +13,9 @@ class Person(BaseModel): enable: bool = True # 布尔类型 - -if __name__ == '__main__': +if __name__ == "__main__": try: - user = Person(name='xiaozhong', password='123456', age=15) + user = Person(name="xiaozhong", password="123456", age=15) except ValidationError as e: print(e.errors()) print(e.json()) @@ -24,12 +23,12 @@ class Person(BaseModel): # print(user.dict()) print(user.dict(exclude_unset=True)) # print(user.dict(exclude={'password'})) - print(user.json(exclude={'password'},models_as_dict=False)) + print(user.json(exclude={"password"}, models_as_dict=False)) # # 进行拷贝================== # new_user = user.copy() # print("userID", user, id(user)) # print("new_userID", new_user, id(new_user)) # # 仅仅包含密码输出=========== - new_user = user.copy(include={'password'}) + new_user = user.copy(include={"password"}) # print("new_user", new_user) print("new_userID", new_user, id(new_user)) diff --git a/chapter05/pydantic_orm/main.py b/chapter05/pydantic_orm/main.py index 41e5478..6509f88 100644 --- a/chapter05/pydantic_orm/main.py +++ b/chapter05/pydantic_orm/main.py @@ -1,23 +1,39 @@ from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field # ORM模型基类 Base = declarative_base() + + # ORM模型类定义 class UserSqlalchemyOrmModel(Base): # 表名称 - __tablename__ = 'user' + __tablename__ = "user" # 表字段 - id = Column(Integer, primary_key=True, nullable=False) # 定义ID + id = Column(Integer, primary_key=True, nullable=False) # 定义ID userid = Column(String(20), index=True, nullable=False, unique=True) # 创建索引 - username = Column(String(32), index=True,unique=True) + username = Column(String(32), index=True, unique=True) class UserPydanticModel(BaseModel): id: int - userid:str = Field(..., title='用户ID', description='用户ID字段需要长度大于6且小于等于20', max_length=20, min_length=6, example="0000001") - username: str = Field(..., title='用户名称', description='用户名称字段需要长度大于6且小于等于32', max_length=20, min_length=6,example="0000001") + userid: str = Field( + ..., + title="用户ID", + description="用户ID字段需要长度大于6且小于等于20", + max_length=20, + min_length=6, + example="0000001", + ) + username: str = Field( + ..., + title="用户名称", + description="用户名称字段需要长度大于6且小于等于32", + max_length=20, + min_length=6, + example="0000001", + ) class Config: # 表示可以-模型类可以从ROM中创建,没有这个话则会报错哦! @@ -25,7 +41,7 @@ class Config: # 创建ORM类的对象 -user_orm = UserSqlalchemyOrmModel(id=123,userid='1000001001',username='xiaozhong') +user_orm = UserSqlalchemyOrmModel(id=123, userid="1000001001", username="xiaozhong") # 从ORM类的对象实例化UserPydanticModel的模型对象 print(UserPydanticModel.from_orm(user_orm)) -#输出结果:id=123 userid='1000001001' username='xiaozhong' +# 输出结果:id=123 userid='1000001001' username='xiaozhong' diff --git a/chapter05/pydantic_validator/address_error_main.py b/chapter05/pydantic_validator/address_error_main.py index aff9f9e..47a88e1 100644 --- a/chapter05/pydantic_validator/address_error_main.py +++ b/chapter05/pydantic_validator/address_error_main.py @@ -4,24 +4,27 @@ from pydantic import BaseModel, validator, ValidationError, PydanticValueError + class AddressError(PydanticValueError): - code = '错误类型' - msg_template = '当前地址长度不对,它应该需要{errmeg},当前传入的值为:{value}' + code = "错误类型" + msg_template = "当前地址长度不对,它应该需要{errmeg},当前传入的值为:{value}" + class Person(BaseModel): username: str address: str - @validator("address",pre=False) + @validator("address", pre=False) def adress_rule(cls, address): # 如果地址长度小于6,那么则返回 if len(address) < 6: - raise AddressError(errmeg='小于6',value=address) + raise AddressError(errmeg="小于6", value=address) elif len(address) > 12: - raise AddressError(errmeg='大于12',value=address) + raise AddressError(errmeg="大于12", value=address) return address -if __name__ == '__main__': + +if __name__ == "__main__": # try: # user = Person(username='xiaozhong', address='12345') # except ValidationError as e: @@ -29,19 +32,17 @@ def adress_rule(cls, address): # else: # print(user.username, user.address) - class Person(BaseModel): name: str nums: str age: Optional[int] - - if __name__ == '__main__': + if __name__ == "__main__": try: - user = Person(name='xiaozhong') + user = Person(name="xiaozhong") except ValidationError as e: # print(e.errors()) # print(e.json()) print(str(e)) else: - print(user.name, user.age) \ No newline at end of file + print(user.name, user.age) diff --git a/chapter05/pydantic_validator/main.py b/chapter05/pydantic_validator/main.py index cf97d7f..780dec6 100644 --- a/chapter05/pydantic_validator/main.py +++ b/chapter05/pydantic_validator/main.py @@ -10,17 +10,20 @@ class Person(BaseModel): password: str # '*' 在这里是匹配任意字段 - @validator('*', pre=True) - def split(cls, v,): + @validator("*", pre=True) + def split( + cls, + v, + ): """如果传参是字符串,根据逗号切割成list""" if isinstance(v, str): - return v.split(',') + return v.split(",") return v -if __name__ == '__main__': +if __name__ == "__main__": try: - user = Person(username='xiaozhong', password='123456') + user = Person(username="xiaozhong", password="123456") except ValidationError as e: print(e.errors()) print(e.json()) diff --git a/chapter05/pydantic_validator/root_validator_main.py b/chapter05/pydantic_validator/root_validator_main.py index 801d949..d1d9766 100644 --- a/chapter05/pydantic_validator/root_validator_main.py +++ b/chapter05/pydantic_validator/root_validator_main.py @@ -14,15 +14,18 @@ class User(BaseModel): @root_validator def check_passwords(cls, values): - password_old, password_new = values.get('password_old'), values.get('password_new') + password_old, password_new = values.get("password_old"), values.get( + "password_new" + ) # 新旧号码的确认匹配处理 if password_old and password_new and password_old != password_new: - raise ValueError('passwords do not match') + raise ValueError("passwords do not match") return values -if __name__ == '__main__': + +if __name__ == "__main__": try: - user = User(username='xiaozhong', password_old='123456', password_new='123456_') + user = User(username="xiaozhong", password_old="123456", password_new="123456_") except ValidationError as e: print(e.errors()) else: diff --git a/chapter05/pydantic_validator/share_logic_auth_main.py b/chapter05/pydantic_validator/share_logic_auth_main.py index c1ad275..709e418 100644 --- a/chapter05/pydantic_validator/share_logic_auth_main.py +++ b/chapter05/pydantic_validator/share_logic_auth_main.py @@ -27,8 +27,7 @@ class Xuser(Base): pass -yuser = Yuser(name='xiaozhong') -print("xiaozhong:名字",yuser.name) -xuser = Xuser(name='_xiao') -print("_xiao:名字",xuser.name) - +yuser = Yuser(name="xiaozhong") +print("xiaozhong:名字", yuser.name) +xuser = Xuser(name="_xiao") +print("_xiao:名字", xuser.name) diff --git a/chapter05/pydantic_validator_order/main.py b/chapter05/pydantic_validator_order/main.py index 357dfee..965eafa 100644 --- a/chapter05/pydantic_validator_order/main.py +++ b/chapter05/pydantic_validator_order/main.py @@ -9,7 +9,7 @@ class Person(BaseModel): username: str address: Dict - @validator("address",pre=True) + @validator("address", pre=True) def adress_rule(cls, address): # 如果地址长度小于6,那么则返回 if len(address) < 6: @@ -18,10 +18,11 @@ def adress_rule(cls, address): raise ValueError("地址长度不能大于12") return address -if __name__ == '__main__': + +if __name__ == "__main__": try: - user = Person(username='xiaozhong', address='12345') + user = Person(username="xiaozhong", address="12345") except ValidationError as e: print(e.errors()) else: - print(user.username, user.address) \ No newline at end of file + print(user.username, user.address) diff --git a/chapter06/depend_class/main.py b/chapter06/depend_class/main.py index f8c304a..71f591d 100644 --- a/chapter06/depend_class/main.py +++ b/chapter06/depend_class/main.py @@ -9,15 +9,16 @@ app = FastAPI() + class UsernameCheck: - def __init__(self, username:str=Query(...)): - if username != 'zhong': + def __init__(self, username: str = Query(...)): + if username != "zhong": raise HTTPException(status_code=403, detail="没有权限访问") self.username = username @app.get("/user/login/") -def user_login(username: UsernameCheck = Depends(UsernameCheck)): +def user_login(username: UsernameCheck = Depends(UsernameCheck)): return username @@ -32,4 +33,4 @@ def user_info(username: UsernameCheck = Depends(UsernameCheck)): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter06/depend_class_more_depends/main.py b/chapter06/depend_class_more_depends/main.py index 16422a7..2f27228 100644 --- a/chapter06/depend_class_more_depends/main.py +++ b/chapter06/depend_class_more_depends/main.py @@ -7,21 +7,23 @@ class UsernameCheck: - def __init__(self,pwssword:str): + def __init__(self, pwssword: str): pass self.pwssword = pwssword def username_form_query(self, username: str = Query(...)): - if username != 'zhong': + if username != "zhong": raise HTTPException(status_code=403, detail="没有权限访问") self.username = username def username_form_post(self, username: str = Body(...)): - if username != 'zhong': + if username != "zhong": raise HTTPException(status_code=403, detail="没有权限访问") self.username = username -upw= UsernameCheck(pwssword="123456") + +upw = UsernameCheck(pwssword="123456") + @app.get("/user/login/") def user_login(username: UsernameCheck = Depends(upw.username_form_query)): @@ -39,4 +41,4 @@ def user_info(username: UsernameCheck = Depends(upw.username_form_post)): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter06/depend_class_nest_depends/main.py b/chapter06/depend_class_nest_depends/main.py index 586b867..308a443 100644 --- a/chapter06/depend_class_nest_depends/main.py +++ b/chapter06/depend_class_nest_depends/main.py @@ -7,30 +7,31 @@ app = FastAPI() -def username_check(username:str=Query(...)): - if username != 'zhong': +def username_check(username: str = Query(...)): + if username != "zhong": raise HTTPException(status_code=403, detail="用户名错误!没有权限访问!") return username -def age_check(username:str=Depends(username_check),age:int=Query(...)): - if age <18: + +def age_check(username: str = Depends(username_check), age: int = Query(...)): + if age < 18: raise HTTPException(status_code=403, detail="用户名未满18岁!禁止吸烟!") - return username,age + return username, age @app.get("/user/login/") def user_login(username_and_age: Tuple = Depends(age_check)): return { - 'username': username_and_age[0], - 'age': username_and_age[1], + "username": username_and_age[0], + "age": username_and_age[1], } @app.get("/user/info") def user_info(username_and_age: Tuple = Depends(age_check)): return { - 'username':username_and_age[0], - 'age': username_and_age[1], + "username": username_and_age[0], + "age": username_and_age[1], } @@ -40,4 +41,4 @@ def user_info(username_and_age: Tuple = Depends(age_check)): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter06/depend_func/main.py b/chapter06/depend_func/main.py index 8c40158..d58824e 100644 --- a/chapter06/depend_func/main.py +++ b/chapter06/depend_func/main.py @@ -9,8 +9,9 @@ app = FastAPI() -def username_check(username:str=Query(...)): - if username != 'zhong': + +def username_check(username: str = Query(...)): + if username != "zhong": raise HTTPException(status_code=403, detail="没有权限访问") return username @@ -31,4 +32,4 @@ def user_info(username: str = Depends(username_check)): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter06/depend_global_depends/main.py b/chapter06/depend_global_depends/main.py index 5045737..4aa7b57 100644 --- a/chapter06/depend_global_depends/main.py +++ b/chapter06/depend_global_depends/main.py @@ -8,7 +8,7 @@ def username_check(username: str = Query(...)): - if username != 'zhong': + if username != "zhong": raise HTTPException(status_code=403, detail="用户名错误!没有权限访问!") return username @@ -24,16 +24,12 @@ def age_check(age: int = Query(...)): @app.get("/user/login/") def user_login(): - return { - 'code': 'ok' - } + return {"code": "ok"} @app.get("/user/info/") def user_info(): - return { - 'code': 'ok' - } + return {"code": "ok"} from fastapi import APIRouter @@ -43,9 +39,7 @@ def user_info(): @api_router.get("/user/apirouter/") def user_apirouter(): - return { - 'code': 'ok' - } + return {"code": "ok"} if __name__ == "__main__": @@ -54,4 +48,4 @@ def user_apirouter(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter06/depend_group_router/main.py b/chapter06/depend_group_router/main.py index 983a21d..d476d17 100644 --- a/chapter06/depend_group_router/main.py +++ b/chapter06/depend_group_router/main.py @@ -9,7 +9,7 @@ def username_check(username: str = Query(...)): - if username != 'zhong': + if username != "zhong": raise HTTPException(status_code=403, detail="用户名错误!没有权限访问!") return username @@ -22,28 +22,26 @@ def age_check(age: int = Query(...)): app = FastAPI() -user_group_router = APIRouter(prefix='/user') +user_group_router = APIRouter(prefix="/user") @user_group_router.get("/login") def user_login(): - return { - 'code': 'login_ok' - } + return {"code": "login_ok"} -order_group_router = APIRouter(prefix='/order') +order_group_router = APIRouter(prefix="/order") @order_group_router.get("/pay") def order_pay(): - return { - 'code': 'pay_ok' - } + return {"code": "pay_ok"} -app.include_router(user_group_router,dependencies=[Depends(username_check)]) -app.include_router(order_group_router,dependencies=[Depends(username_check), Depends(age_check)]) +app.include_router(user_group_router, dependencies=[Depends(username_check)]) +app.include_router( + order_group_router, dependencies=[Depends(username_check), Depends(age_check)] +) if __name__ == "__main__": @@ -52,4 +50,4 @@ def order_pay(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/base_http_middleware/main.py b/chapter07/base_http_middleware/main.py index c23e2f9..02c233e 100644 --- a/chapter07/base_http_middleware/main.py +++ b/chapter07/base_http_middleware/main.py @@ -10,44 +10,45 @@ class TimeCcalculateMiddleware(BaseHTTPMiddleware): # dispatch 必须实现 async def dispatch(self, request: Request, call_next): - print('TimeCcalculateMiddleware-Start') + print("TimeCcalculateMiddleware-Start") start_time = time.time() response = await call_next(request) process_time = round(time.time() - start_time, 4) # 返回接口响应时间 response.headers["X-Process-Time"] = f"{process_time} (s)" - print('TimeCcalculateMiddleware-End') + print("TimeCcalculateMiddleware-End") return response # 基于BaseHTTPMiddleware的中间件实例, class AuthMiddleware(BaseHTTPMiddleware): - def __init__(self, app, header_value='auth'): + def __init__(self, app, header_value="auth"): super().__init__(app) self.header_value = header_value # dispatch 必须实现 async def dispatch(self, request: Request, call_next): - print('AuthMiddleware-Start') + print("AuthMiddleware-Start") response = await call_next(request) - response.headers['Custom'] = self.header_value - print('AuthMiddleware-End') + response.headers["Custom"] = self.header_value + print("AuthMiddleware-End") return response app.add_middleware(TimeCcalculateMiddleware) -app.add_middleware(AuthMiddleware, header_value='CustomAuth') +app.add_middleware(AuthMiddleware, header_value="CustomAuth") @app.get("/index") async def index(): - print('index-Start') - return { - 'code': 200 - } + print("index-Start") + return {"code": 200} + + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/cors_middleware/main.py b/chapter07/cors_middleware/main.py index f6e2021..14a546d 100644 --- a/chapter07/cors_middleware/main.py +++ b/chapter07/cors_middleware/main.py @@ -25,11 +25,10 @@ async def main(): return {"message": "Hello World"} - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/https_redirect_middleware/main.py b/chapter07/https_redirect_middleware/main.py index 78843eb..b062d56 100644 --- a/chapter07/https_redirect_middleware/main.py +++ b/chapter07/https_redirect_middleware/main.py @@ -7,11 +7,10 @@ app.add_middleware(HTTPSRedirectMiddleware) + @app.get("/index") async def httpsredirec(): - return { - 'code':200 - } + return {"code": 200} if __name__ == "__main__": @@ -20,4 +19,4 @@ async def httpsredirec(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/log_response_middleware/main.py b/chapter07/log_response_middleware/main.py index c5327ad..2bb0f50 100644 --- a/chapter07/log_response_middleware/main.py +++ b/chapter07/log_response_middleware/main.py @@ -2,17 +2,14 @@ from fastapi import FastAPI, Request, Response from starlette.middleware.base import RequestResponseEndpoint + app = FastAPI() class LogMiddleware: async def __call__( - self, - request: Request, - call_next: RequestResponseEndpoint, - *args, - **kwargs + self, request: Request, call_next: RequestResponseEndpoint, *args, **kwargs ): try: # 下一个响应报文内容 @@ -25,7 +22,7 @@ async def __call__( status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.real, ) else: - response_body = b'' + response_body = b"" # 解析读取对应的响应报文内容型芯 async for chunk in response.body_iterator: response_body += chunk @@ -34,20 +31,19 @@ async def __call__( content=response_body, status_code=response.status_code, headers=dict(response.headers), - media_type=response.media_type + media_type=response.media_type, ) return response -app.middleware('http')(LogMiddleware()) +app.middleware("http")(LogMiddleware()) app.add_middleware(LogMiddleware) + @app.get("/index") async def index(): - return { - 'code': 200 - } + return {"code": 200} if __name__ == "__main__": @@ -56,4 +52,4 @@ async def index(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/middleware_process_time/main.py b/chapter07/middleware_process_time/main.py index ed645b0..b738f18 100644 --- a/chapter07/middleware_process_time/main.py +++ b/chapter07/middleware_process_time/main.py @@ -17,9 +17,7 @@ async def add_process_time_header(request: Request, call_next): @app.get("/index") async def index(): - return { - 'code': 200 - } + return {"code": 200} if __name__ == "__main__": @@ -28,4 +26,4 @@ async def index(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/tracdid_middleware/main.py b/chapter07/tracdid_middleware/main.py index 131f795..a7bbe3a 100644 --- a/chapter07/tracdid_middleware/main.py +++ b/chapter07/tracdid_middleware/main.py @@ -7,30 +7,34 @@ import uuid + # 基于BaseHTTPMiddleware的中间件实例 import contextvars -request_context = contextvars.ContextVar('request_context') + +request_context = contextvars.ContextVar("request_context") + class TracdIDMiddleware(BaseHTTPMiddleware): # dispatch 必须实现 - async def dispatch(self, request:Request, call_next): + async def dispatch(self, request: Request, call_next): request_context.set(request) request.state.traceid = uuid.uuid4() responser = await call_next(request) # 返回接口响应时间 return responser + def log_info(mage=None): - request: Request =request_context.get() - print('index-requet',request.state.traceid) + request: Request = request_context.get() + print("index-requet", request.state.traceid) + app.add_middleware(TracdIDMiddleware) + @app.get("/index") async def index(): - return { - 'code': 200 - } + return {"code": 200} if __name__ == "__main__": @@ -39,4 +43,4 @@ async def index(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/trusted_host_middleware/main.py b/chapter07/trusted_host_middleware/main.py index be5242f..6784905 100644 --- a/chapter07/trusted_host_middleware/main.py +++ b/chapter07/trusted_host_middleware/main.py @@ -4,24 +4,27 @@ app = FastAPI() -app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]) +app.add_middleware( + TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"] +) + @app.get("/index") async def truste(): - return { - 'code':200 - } + return {"code": 200} + from fastapi import FastAPI + app.add_middleware(GZipMiddleware, minimum_size=1000) app = FastAPI() + @app.get("/index") async def gzip(): - return { - 'code':200 - } + return {"code": 200} + if __name__ == "__main__": import uvicorn @@ -29,4 +32,4 @@ async def gzip(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter07/whileIp_middleware/main.py b/chapter07/whileIp_middleware/main.py index 808f6d6..b42856f 100644 --- a/chapter07/whileIp_middleware/main.py +++ b/chapter07/whileIp_middleware/main.py @@ -12,17 +12,24 @@ class WhileIpMiddleware: - def __init__(self, app: ASGIApp, - allow_ip: typing.Sequence[str] = (), - ) -> None: + def __init__( + self, + app: ASGIApp, + allow_ip: typing.Sequence[str] = (), + ) -> None: self.app = app self.allow_ip = allow_ip or "*" async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - if scope["type"] in ("http", "websocket") and scope["scheme"] in ("http", "ws"): + if scope["type"] in ("http", "websocket") and scope["scheme"] in ( + "http", + "ws", + ): conn = HTTPConnection(scope=scope) if self.allow_ip and conn.client.host not in self.allow_ip: - response = PlainTextResponse(content="不在IP白名单内", status_code=403) + response = PlainTextResponse( + content="不在IP白名单内", status_code=403 + ) await response(scope, receive, send) return await self.app(scope, receive, send) @@ -30,14 +37,12 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: await self.app(scope, receive, send) -app.add_middleware(WhileIpMiddleware, allow_ip=['127.0.0.2']) +app.add_middleware(WhileIpMiddleware, allow_ip=["127.0.0.2"]) @app.get("/index") async def index(): - return { - 'code': 200 - } + return {"code": 200} if __name__ == "__main__": @@ -46,4 +51,4 @@ async def index(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter08/aioredis_fastapi/main.py b/chapter08/aioredis_fastapi/main.py index 5a2c907..a1fd02b 100644 --- a/chapter08/aioredis_fastapi/main.py +++ b/chapter08/aioredis_fastapi/main.py @@ -5,19 +5,20 @@ app = FastAPI() + @app.on_event("startup") async def startup_event(): # app.state.redis_client = aioredis.from_url("redis://localhost") # app.state.redis_client = aioredis.Redis(host='localhost') # pool = ConnectionPool(host='localhost',) # app.state.redis_client = aioredis.Redis(connection_pool=pool) - pool = ConnectionPool(host='localhost', encoding="utf-8", decode_responses=True) + pool = ConnectionPool(host="localhost", encoding="utf-8", decode_responses=True) app.state.redis_client = aioredis.Redis(connection_pool=pool) # redis_client:Redis = app.state.redis_client await app.state.redis_client.flushall() - await app.state.redis_client.set("test_key",'testdata') + await app.state.redis_client.set("test_key", "testdata") print(await app.state.redis_client.get("test_key")) - await app.state.redis_client.set("test_zh", '我是谁') + await app.state.redis_client.set("test_zh", "我是谁") print(await app.state.redis_client.get("test_zh")) @@ -25,40 +26,46 @@ async def startup_event(): async def shutdown_event(): app.state.redis_client.close() + @app.get("/index") async def index(): - key = 'xiaozhong' + key = "xiaozhong" # 设置缓存数据 - await app.state.redis_client.set(key=key,value="测试数据") + await app.state.redis_client.set(key=key, value="测试数据") # 读取缓存数据 cache1 = await app.state.redis_client.get(key=key) - key_2 = 'xiaozhong_2' + key_2 = "xiaozhong_2" # 添加数据,5秒后自动清除 await app.state.redis_client.setex(key=key_2, seconds=5, value="测试数据2") # 测试2缓存数据的获取 cache2 = await app.state.redis_client.get(key=key_2) return { - "cache1":cache1, + "cache1": cache1, "cache2": cache2, } + @app.get("/index2") async def index2(request: Request): async with request.app.state.redis_client.pipeline(transaction=True) as pipe: - ok1, ok2 = await (pipe.set("xiaozhong", "测试数据").set("xiaozhong_2", "测试数据2").execute()) + ok1, ok2 = await ( + pipe.set("xiaozhong", "测试数据").set("xiaozhong_2", "测试数据2").execute() + ) pass async with request.app.state.redis_client.pipeline(transaction=True) as pipe: - cache1, cache2 = await (pipe.get("xiaozhong").get("xiaozhong_2").execute()) + cache1, cache2 = await pipe.get("xiaozhong").get("xiaozhong_2").execute() print(cache1, cache2) return { - "cache1":cache1, + "cache1": cache1, "cache2": cache2, } + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter08/aioredis_lock/main.py b/chapter08/aioredis_lock/main.py index 69c03d3..e349013 100644 --- a/chapter08/aioredis_lock/main.py +++ b/chapter08/aioredis_lock/main.py @@ -8,13 +8,30 @@ async def redis_look(): r = aioredis.from_url("redis://localhost", encoding="utf-8", decode_responses=True) # 定义获取锁对象,设置锁的超时时间 - def get_lock(redis, lock_name, timeout=10,sleep=0.2,blocking_timeout=None,lock_class=Lock,thread_local=True): - return redis.lock(name=lock_name, timeout=timeout,sleep=sleep,blocking_timeout=blocking_timeout, lock_class=lock_class,thread_local=thread_local) + def get_lock( + redis, + lock_name, + timeout=10, + sleep=0.2, + blocking_timeout=None, + lock_class=Lock, + thread_local=True, + ): + return redis.lock( + name=lock_name, + timeout=timeout, + sleep=sleep, + blocking_timeout=blocking_timeout, + lock_class=lock_class, + thread_local=thread_local, + ) # 实例化一个锁对象 - lock = get_lock(redis=r, lock_name='xiaozhong') + lock = get_lock(redis=r, lock_name="xiaozhong") # 开始获取到锁对象blocking为Flase,则不再阻塞,直接返回结果 - lock_acquire = await lock.acquire(blocking=False,) + lock_acquire = await lock.acquire( + blocking=False, + ) if lock_acquire: # 开始上锁--- is_locked = await lock.locked() diff --git a/chapter08/aioredis_pubsub/main.py b/chapter08/aioredis_pubsub/main.py index 23bfed9..06472ec 100644 --- a/chapter08/aioredis_pubsub/main.py +++ b/chapter08/aioredis_pubsub/main.py @@ -1,5 +1,4 @@ - -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request import asyncio import async_timeout import aioredis @@ -9,6 +8,8 @@ # 定义事件消息模型 from pydantic import BaseModel + + class MessageEvent(BaseModel): username: str message: dict @@ -24,8 +25,10 @@ async def reader(channel: aioredis.client.PubSub): print("jiesh?ssssssssss", message) if message is not None: pass - message_event = MessageEvent.parse_raw(message["data"].decode('utf-8')) - print("订阅接收到消息为:",message_event) + message_event = MessageEvent.parse_raw( + message["data"].decode("utf-8") + ) + print("订阅接收到消息为:", message_event) await asyncio.sleep(0.01) except asyncio.TimeoutError: pass @@ -34,7 +37,7 @@ async def reader(channel: aioredis.client.PubSub): @app.on_event("startup") async def startup_event(): # 创建Redis对象 - redis:Redis = aioredis.from_url("redis://localhost") + redis: Redis = aioredis.from_url("redis://localhost") # 创建消息发布定义对象获取到发布订阅对象 pubsub = redis.pubsub() # 把当前的对象添加到全局APP上下中 @@ -43,7 +46,9 @@ async def startup_event(): # 开始订阅相关频道 await pubsub.subscribe("channel:1", "channel:2") # 消息模型的创建 - event = MessageEvent(username="xiaozhongtongxue", message={"msg": "在startup_event发布的事件消息"}) + event = MessageEvent( + username="xiaozhongtongxue", message={"msg": "在startup_event发布的事件消息"} + ) # 消息发布0发布到channel:1频道上 await redis.publish(channel="channel:1", message=event.json()) # 执行消息订阅循环监听 @@ -61,16 +66,21 @@ async def shutdown_event(): # 关闭redis连接 app.state.redis.close() -@app.get('/index') -async def get(re:Request): + +@app.get("/index") +async def get(re: Request): # 手动执行其他消息的发布 - event = MessageEvent(username="xiaozhongtongxue", message={"msg": "我是来自API接口发布的消息!"}) + event = MessageEvent( + username="xiaozhongtongxue", message={"msg": "我是来自API接口发布的消息!"} + ) await re.app.state.redis.publish(channel="channel:1", message=event.json()) return "ok" + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter08/databases_sql/main.py b/chapter08/databases_sql/main.py index 477a913..65b756c 100644 --- a/chapter08/databases_sql/main.py +++ b/chapter08/databases_sql/main.py @@ -5,14 +5,15 @@ async def startup(): # 创建数据库连接对象 from databases import Database - database = Database('sqlite+aiosqlite:///user.db') + + database = Database("sqlite+aiosqlite:///user.db") await database.connect() # 创建新的数据库表 - query = '''CREATE TABLE user + query = """CREATE TABLE user (id INT PRIMARY KEY NOT NULL, username TEXT NOT NULL, - password TEXT NOT NULL);''' + password TEXT NOT NULL);""" await database.execute(query=query) # 单条数据插入 @@ -22,17 +23,21 @@ async def startup(): # 批量数据插入 query = "INSERT INTO user(id,username,password) VALUES (:id,:username,:password)" values = [ - {"id":2,"username": "xiaozhong_1", "password": '123456-1'}, - {"id":3,"username": "xiaozhong_2", "password": '123456-2'}, - {"id":4,"username": "xiaozhong_3", "password": '123456-3'}, + {"id": 2, "username": "xiaozhong_1", "password": "123456-1"}, + {"id": 3, "username": "xiaozhong_2", "password": "123456-2"}, + {"id": 4, "username": "xiaozhong_3", "password": "123456-3"}, ] # # 批量执行数据插入 await database.execute_many(query=query, values=values) # # 执行查询全部数据 query = "SELECT * FROM user" - rows = await database.fetch_all(query=query,) - print('user listinfo:', rows) + rows = await database.fetch_all( + query=query, + ) + print("user listinfo:", rows) await database.disconnect() + import asyncio + asyncio.run(startup()) diff --git a/chapter08/databases_sqlalchemy/main.py b/chapter08/databases_sqlalchemy/main.py index 26b09fd..6499a68 100644 --- a/chapter08/databases_sqlalchemy/main.py +++ b/chapter08/databases_sqlalchemy/main.py @@ -8,15 +8,17 @@ metadata = sqlalchemy.MetaData() + class User(Base): # 指定本类映射到users表 - __tablename__ = 'users' + __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20)) nikename = Column(String(32)) password = Column(String(32)) email = Column(String(50)) + notes = sqlalchemy.Table( "notes", metadata, @@ -28,7 +30,7 @@ class User(Base): from databases import Database -database = Database('sqlite+aiosqlite:///user.db') +database = Database("sqlite+aiosqlite:///user.db") # Establish the connection pool await database.connect() @@ -37,4 +39,3 @@ class User(Base): query = notes.insert() values = {"text": "example1", "completed": True} await database.execute(query=query, values=values) - diff --git a/chapter08/fastapi_sqlalchemy/alembic/env.py b/chapter08/fastapi_sqlalchemy/alembic/env.py index ce0758e..908f13a 100644 --- a/chapter08/fastapi_sqlalchemy/alembic/env.py +++ b/chapter08/fastapi_sqlalchemy/alembic/env.py @@ -18,9 +18,11 @@ # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -import os,sys +import os, sys + sys.path.append(os.path.dirname(os.path.dirname(__file__))) from models import Base + target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, @@ -67,9 +69,7 @@ def run_migrations_online(): ) with connectable.connect() as connection: - context.configure( - connection=connection, target_metadata=target_metadata - ) + context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() diff --git a/chapter08/fastapi_sqlalchemy/alembic/versions/287a3cf31b84_shann.py b/chapter08/fastapi_sqlalchemy/alembic/versions/287a3cf31b84_shann.py index cd25554..3a30509 100644 --- a/chapter08/fastapi_sqlalchemy/alembic/versions/287a3cf31b84_shann.py +++ b/chapter08/fastapi_sqlalchemy/alembic/versions/287a3cf31b84_shann.py @@ -5,24 +5,25 @@ Create Date: 2022-04-04 12:26:15.416620 """ + from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '287a3cf31b84' -down_revision = '3328ff109aa7' +revision = "287a3cf31b84" +down_revision = "3328ff109aa7" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('users', 'addr') + op.drop_column("users", "addr") # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('users', sa.Column('addr', sa.VARCHAR(length=50), nullable=True)) + op.add_column("users", sa.Column("addr", sa.VARCHAR(length=50), nullable=True)) # ### end Alembic commands ### diff --git a/chapter08/fastapi_sqlalchemy/alembic/versions/3328ff109aa7_add_mobile.py b/chapter08/fastapi_sqlalchemy/alembic/versions/3328ff109aa7_add_mobile.py index 76b3867..3efa4fb 100644 --- a/chapter08/fastapi_sqlalchemy/alembic/versions/3328ff109aa7_add_mobile.py +++ b/chapter08/fastapi_sqlalchemy/alembic/versions/3328ff109aa7_add_mobile.py @@ -1,16 +1,17 @@ """add mobile Revision ID: 3328ff109aa7 -Revises: +Revises: Create Date: 2022-04-04 12:24:42.862656 """ + from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '3328ff109aa7' +revision = "3328ff109aa7" down_revision = None branch_labels = None depends_on = None @@ -18,11 +19,11 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('users', sa.Column('addr', sa.String(length=50), nullable=True)) + op.add_column("users", sa.Column("addr", sa.String(length=50), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('users', 'addr') + op.drop_column("users", "addr") # ### end Alembic commands ### diff --git a/chapter08/fastapi_sqlalchemy/api/__init__.py b/chapter08/fastapi_sqlalchemy/api/__init__.py index 937e99a..8b51fd3 100644 --- a/chapter08/fastapi_sqlalchemy/api/__init__.py +++ b/chapter08/fastapi_sqlalchemy/api/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter08/fastapi_sqlalchemy/api/user.py b/chapter08/fastapi_sqlalchemy/api/user.py index 35626e0..8414da5 100644 --- a/chapter08/fastapi_sqlalchemy/api/user.py +++ b/chapter08/fastapi_sqlalchemy/api/user.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -32,7 +32,7 @@ @文件功能描述:------ """ from fastapi import APIRouter -from schemas.user import UserCreate,UserUpdate +from schemas.user import UserCreate, UserUpdate from servies.user import UserServeries from db.database import AsyncSession from dependencies import get_db_session @@ -42,30 +42,32 @@ @router_uesr.post("/user/creat") -async def creat(user:UserCreate,db_session: AsyncSession = Depends(get_db_session)): - result= await UserServeries.create_user(db_session,**user.dict()) - return {"code": "200", "msg": "用户创建成功!","data":result} +async def creat(user: UserCreate, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.create_user(db_session, **user.dict()) + return {"code": "200", "msg": "用户创建成功!", "data": result} @router_uesr.get("/user/info") -async def info(user_id:int,db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.get_user(db_session,user_id=user_id) - return {"code": "200", "msg": "查询用户信息成功!","data":result} +async def info(user_id: int, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.get_user(db_session, user_id=user_id) + return {"code": "200", "msg": "查询用户信息成功!", "data": result} @router_uesr.get("/user/list") async def list(db_session: AsyncSession = Depends(get_db_session)): result = await UserServeries.get_users(db_session) - return {"code": "200", "msg": "查询用户列表信息成功!","data":result} + return {"code": "200", "msg": "查询用户列表信息成功!", "data": result} @router_uesr.put("/user/edit") -async def edit(user:UserUpdate,db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.update_user(db_session,user_id=user.id,name=user.name) - return {"code": "200", "msg": "修改用户信息成功!","data":None} +async def edit(user: UserUpdate, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.update_user( + db_session, user_id=user.id, name=user.name + ) + return {"code": "200", "msg": "修改用户信息成功!", "data": None} @router_uesr.delete("/user/delete") -async def delete(user_id:int,db_session: AsyncSession = Depends(get_db_session)): +async def delete(user_id: int, db_session: AsyncSession = Depends(get_db_session)): result = await UserServeries.delete_user(db_session, user_id=user_id) return {"code": "200", "msg": "删除用户信息成功!"} diff --git a/chapter08/fastapi_sqlalchemy/config/__init__.py b/chapter08/fastapi_sqlalchemy/config/__init__.py index 5f7693a..1efc88f 100644 --- a/chapter08/fastapi_sqlalchemy/config/__init__.py +++ b/chapter08/fastapi_sqlalchemy/config/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter08/fastapi_sqlalchemy/config/confiig.py b/chapter08/fastapi_sqlalchemy/config/confiig.py index bd11d4c..00259a9 100644 --- a/chapter08/fastapi_sqlalchemy/config/confiig.py +++ b/chapter08/fastapi_sqlalchemy/config/confiig.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -35,10 +35,12 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 定义连接数据库的URL地址 ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///user.db" + @lru_cache() def get_settings(): return Settings() diff --git a/chapter08/fastapi_sqlalchemy/db/__init__.py b/chapter08/fastapi_sqlalchemy/db/__init__.py index bd31053..707ab3b 100644 --- a/chapter08/fastapi_sqlalchemy/db/__init__.py +++ b/chapter08/fastapi_sqlalchemy/db/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter08/fastapi_sqlalchemy/db/database.py b/chapter08/fastapi_sqlalchemy/db/database.py index b109a73..90cec30 100644 --- a/chapter08/fastapi_sqlalchemy/db/database.py +++ b/chapter08/fastapi_sqlalchemy/db/database.py @@ -1,13 +1,15 @@ # 导入异步引擎的模块 from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import declarative_base, sessionmaker + # URL地址格式 from config.confiig import get_settings + # 创建异步引擎对象 async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) # 创建ORM模型基类 Base = declarative_base() # 创建异步的会话管理对象 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) - - +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) diff --git a/chapter08/fastapi_sqlalchemy/dependencies/__init__.py b/chapter08/fastapi_sqlalchemy/dependencies/__init__.py index c0f521b..ade4cb4 100644 --- a/chapter08/fastapi_sqlalchemy/dependencies/__init__.py +++ b/chapter08/fastapi_sqlalchemy/dependencies/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -35,6 +35,7 @@ from typing import AsyncGenerator from db.database import SessionLocal + async def get_db_session() -> AsyncGenerator[AsyncSession, None]: db_session = None try: diff --git a/chapter08/fastapi_sqlalchemy/main.py b/chapter08/fastapi_sqlalchemy/main.py index 826eb12..5fb6bf2 100644 --- a/chapter08/fastapi_sqlalchemy/main.py +++ b/chapter08/fastapi_sqlalchemy/main.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -35,20 +35,25 @@ from fastapi import FastAPI from servies.user import UserServeries -app = FastAPI(title='fastapi集成SQLAlchemy示例') +app = FastAPI(title="fastapi集成SQLAlchemy示例") + @app.on_event("startup") async def startup_event(): pass await UserServeries.init_create_table() + @app.on_event("shutdown") async def shutdown_event(): pass + from api.user import router_uesr + app.include_router(router_uesr) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) \ No newline at end of file + + uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True) diff --git a/chapter08/fastapi_sqlalchemy/models/__init__.py b/chapter08/fastapi_sqlalchemy/models/__init__.py index a1979ee..9f879f0 100644 --- a/chapter08/fastapi_sqlalchemy/models/__init__.py +++ b/chapter08/fastapi_sqlalchemy/models/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -31,4 +31,4 @@ @File: __init__.py.py @文件功能描述:------ """ -from .user import * \ No newline at end of file +from .user import * diff --git a/chapter08/fastapi_sqlalchemy/models/user.py b/chapter08/fastapi_sqlalchemy/models/user.py index b637274..240c98b 100644 --- a/chapter08/fastapi_sqlalchemy/models/user.py +++ b/chapter08/fastapi_sqlalchemy/models/user.py @@ -4,9 +4,10 @@ from db.database import Base from sqlalchemy import Column, Integer, String + class User(Base): # 指定本类映射到users表 - __tablename__ = 'users' + __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20)) nikename = Column(String(32)) diff --git a/chapter08/fastapi_sqlalchemy/schemas/__init__.py b/chapter08/fastapi_sqlalchemy/schemas/__init__.py index 9b25443..5eae624 100644 --- a/chapter08/fastapi_sqlalchemy/schemas/__init__.py +++ b/chapter08/fastapi_sqlalchemy/schemas/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter08/fastapi_sqlalchemy/schemas/user.py b/chapter08/fastapi_sqlalchemy/schemas/user.py index dc90d05..327956c 100644 --- a/chapter08/fastapi_sqlalchemy/schemas/user.py +++ b/chapter08/fastapi_sqlalchemy/schemas/user.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -34,22 +34,26 @@ from pydantic import BaseModel + class UserCreate(BaseModel): """ 创建新用户记录时候需要传递参数信息 """ + name: str password: str nikename: str email: str + class UserUpdate(BaseModel): """ Pydantic user schema containing attributes received via the API for updating user details. """ + id: int - name: str =None - password: str =None - nikename: str=None - email: str=None \ No newline at end of file + name: str = None + password: str = None + nikename: str = None + email: str = None diff --git a/chapter08/fastapi_sqlalchemy/servies/__init__.py b/chapter08/fastapi_sqlalchemy/servies/__init__.py index bd31053..707ab3b 100644 --- a/chapter08/fastapi_sqlalchemy/servies/__init__.py +++ b/chapter08/fastapi_sqlalchemy/servies/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter08/fastapi_sqlalchemy/servies/user.py b/chapter08/fastapi_sqlalchemy/servies/user.py index b1262c8..a447f36 100644 --- a/chapter08/fastapi_sqlalchemy/servies/user.py +++ b/chapter08/fastapi_sqlalchemy/servies/user.py @@ -1,10 +1,10 @@ #!/usr/bin/evn python # coding=utf-8 -from sqlalchemy import select,update,delete +from sqlalchemy import select, update, delete from sqlalchemy.ext.asyncio import AsyncSession from models.user import User -from db.database import async_engine,Base +from db.database import async_engine, Base class UserServeries: @@ -17,28 +17,17 @@ async def init_create_table(): @staticmethod async def get_user(async_session: AsyncSession, user_id: int): - result = await async_session.execute( - select(User) - .where(User.id == user_id) - ) + result = await async_session.execute(select(User).where(User.id == user_id)) return result.scalars().first() @staticmethod async def get_user_by_name(async_session: AsyncSession, name: str): - result = await async_session.execute( - select(User) - .where(User.name == name) - ) + result = await async_session.execute(select(User).where(User.name == name)) return result.scalars().first() @staticmethod - async def get_users( - async_session: AsyncSession, skip: int = 0, limit: int = 100 - ): - result = await async_session.execute( - select(User) - .order_by(User.id) - ) + async def get_users(async_session: AsyncSession, skip: int = 0, limit: int = 100): + result = await async_session.execute(select(User).order_by(User.id)) return result.scalars().fetchall() @staticmethod @@ -49,7 +38,7 @@ async def create_user(async_session: AsyncSession, **kwargs): return new_user @staticmethod - async def update_user(async_session: AsyncSession, user_id: int,**kwargs): + async def update_user(async_session: AsyncSession, user_id: int, **kwargs): response = update(User).where(User.id == user_id) result = await async_session.execute(response.values(**kwargs)) await async_session.commit() @@ -59,4 +48,4 @@ async def update_user(async_session: AsyncSession, user_id: int,**kwargs): async def delete_user(async_session: AsyncSession, user_id: int): response = await async_session.execute(delete(User).where(User.id == user_id)) await async_session.commit() - return response \ No newline at end of file + return response diff --git a/chapter08/lua_register_script/2mian.py b/chapter08/lua_register_script/2mian.py index c5fa06f..d9f9680 100644 --- a/chapter08/lua_register_script/2mian.py +++ b/chapter08/lua_register_script/2mian.py @@ -4,7 +4,10 @@ from redis import Redis # 创建连接客户端对象 -redis = Redis(host="localhost",port=6379,) +redis = Redis( + host="localhost", + port=6379, +) # 封装获取锁的值和删除锁操作的Lua脚本script内容 script = """ if redis.call('GET', KEYS[1]) == ARGV[1] then @@ -15,13 +18,15 @@ """ -def action(lock_name='pay_order',client_signature=str(uuid4())): +def action(lock_name="pay_order", client_signature=str(uuid4())): print(client_signature) - if redis.set(name=lock_name, value=client_signature, nx=True, ex=25): # 锁不存在才能上锁成功,过期时间应为业务时间的五倍,此处故意写小,模拟过期释放 - print('上锁') + if redis.set( + name=lock_name, value=client_signature, nx=True, ex=25 + ): # 锁不存在才能上锁成功,过期时间应为业务时间的五倍,此处故意写小,模拟过期释放 + print("上锁") try: - print('处理业务', client_signature) + print("处理业务", client_signature) time.sleep(10) except Exception as e: print(e) @@ -30,12 +35,12 @@ def action(lock_name='pay_order',client_signature=str(uuid4())): cmd = redis.register_script(script) res = cmd(keys=[lock_name], args=[client_signature]) # 执行脚本 if res: - print('锁已释放') + print("锁已释放") else: - print('不是自己的锁') + print("不是自己的锁") else: - print('锁已存在') + print("锁已存在") -if __name__ == '__main__': +if __name__ == "__main__": action() diff --git a/chapter08/lua_register_script/mian.py b/chapter08/lua_register_script/mian.py index eb8c046..18e0ea5 100644 --- a/chapter08/lua_register_script/mian.py +++ b/chapter08/lua_register_script/mian.py @@ -4,7 +4,7 @@ from redis import Redis # 创建连接客户端对象 -redis = Redis(host="localhost",port=6379) +redis = Redis(host="localhost", port=6379) # 封装获取锁的值和删除锁操作的Lua脚本script内容 script = """ if redis.call('GET', KEYS[1]) == ARGV[1] then @@ -15,10 +15,12 @@ """ -def action(lock_name='pay_order',client_signature=str(uuid4())): - if redis.set(name=lock_name, value=client_signature, nx=True, ex=25): # 锁不存在才能上锁成功,过期时间应为业务时间的五倍,此处故意写小,模拟过期释放 +def action(lock_name="pay_order", client_signature=str(uuid4())): + if redis.set( + name=lock_name, value=client_signature, nx=True, ex=25 + ): # 锁不存在才能上锁成功,过期时间应为业务时间的五倍,此处故意写小,模拟过期释放 try: - print('处理业务', client_signature) + print("处理业务", client_signature) time.sleep(10) except Exception as e: print(e) @@ -27,12 +29,12 @@ def action(lock_name='pay_order',client_signature=str(uuid4())): cmd = redis.register_script(script) res = cmd(keys=[lock_name], args=[client_signature]) # 执行脚本 if res: - print('锁已释放') + print("锁已释放") else: - print('不是自己的锁') + print("不是自己的锁") else: - print('锁已存在') + print("锁已存在") -if __name__ == '__main__': +if __name__ == "__main__": action() diff --git a/chapter08/sql_model/main.py b/chapter08/sql_model/main.py index ed47d2c..959888d 100644 --- a/chapter08/sql_model/main.py +++ b/chapter08/sql_model/main.py @@ -1,3 +1,4 @@ from sqlmodel import create_engine + ASYNC_DATABASE_URI = "sqlite+aiosqlite:///aiosqlite_user.db" -engine = create_engine(ASYNC_DATABASE_URI) \ No newline at end of file +engine = create_engine(ASYNC_DATABASE_URI) diff --git a/chapter08/sqlalchemy_async_sqlite3/main.py b/chapter08/sqlalchemy_async_sqlite3/main.py index 0471857..e4c0471 100644 --- a/chapter08/sqlalchemy_async_sqlite3/main.py +++ b/chapter08/sqlalchemy_async_sqlite3/main.py @@ -19,7 +19,7 @@ class User(Base): # 指定本类映射到users表 - __tablename__ = 'users' + __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20)) nikename = Column(String(32)) @@ -38,7 +38,9 @@ async def init_create(): asyncio.run(init_create()) # 创建异步会话查询 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) # 对模型类进行异步CRUD操作 from sqlalchemy import select @@ -46,18 +48,12 @@ async def init_create(): async def get_user(async_session: AsyncSession, user_id: int): - result = await async_session.execute( - select(User) - .where(User.id == user_id) - ) + result = await async_session.execute(select(User).where(User.id == user_id)) return result.scalars().first() async def get_user_by_name(async_session: AsyncSession, name: str): - result = await async_session.execute( - select(User) - .where(User.name == name) - ) + result = await async_session.execute(select(User).where(User.name == name)) return result.scalars().first() @@ -83,12 +79,17 @@ async def create_user(async_session: AsyncSession, name, nikename, email, passwo async def testrun(): async_session = SessionLocal() - result = await create_user(async_session=async_session, name='xiaozhong', nikename='Zyx', email='zyx@123.com', - password='123456') + result = await create_user( + async_session=async_session, + name="xiaozhong", + nikename="Zyx", + email="zyx@123.com", + password="123456", + ) print(result.name) await async_session.close() async_session = SessionLocal() - result = await get_user_by_name(async_session=async_session, name='xiaozhong') + result = await get_user_by_name(async_session=async_session, name="xiaozhong") print(result.name) await async_session.close() async_session = SessionLocal() @@ -101,12 +102,14 @@ async def testrun(): asyncio.run(testrun()) -#============================================================= -#============================================================= -#============================================================= -#============================================================= +# ============================================================= +# ============================================================= +# ============================================================= +# ============================================================= from contextlib import asynccontextmanager + + @asynccontextmanager async def get_db() -> AsyncGenerator: async_session = SessionLocal() @@ -122,9 +125,16 @@ async def get_db() -> AsyncGenerator: async def testrun(): async with get_db() as async_session: - result = await create_user(async_session=async_session, name='xiaozhong', nikename='Zyx', email='zyx@123.com',password='123456') + result = await create_user( + async_session=async_session, + name="xiaozhong", + nikename="Zyx", + email="zyx@123.com", + password="123456", + ) print(result.name) - result = await get_user_by_name(async_session=async_session, name='xiaozhong') + result = await get_user_by_name(async_session=async_session, name="xiaozhong") print(result.name) -asyncio.run(testrun()) \ No newline at end of file + +asyncio.run(testrun()) diff --git a/chapter08/sqlalchemy_sync_sqlite3/main.py b/chapter08/sqlalchemy_sync_sqlite3/main.py index d767860..6b43025 100644 --- a/chapter08/sqlalchemy_sync_sqlite3/main.py +++ b/chapter08/sqlalchemy_sync_sqlite3/main.py @@ -1,7 +1,7 @@ # 创建引擎对象 from sqlalchemy import create_engine -engine = create_engine('sqlite:///user.db') +engine = create_engine("sqlite:///user.db") # 定义数据库模型 from sqlalchemy.ext.declarative import declarative_base @@ -12,7 +12,7 @@ class User(Base): # 指定本类映射到users表 - __tablename__ = 'users' + __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20)) nikename = Column(String(32)) @@ -28,39 +28,44 @@ class User(Base): Session = sessionmaker(bind=engine) session = Session() # 对模型类进行CRUD操作 -_user = User(name='xiaozhong', nikename='Zyx', password='123456', email='zyx@qq.com') +_user = User(name="xiaozhong", nikename="Zyx", password="123456", email="zyx@qq.com") session.add(_user) session.commit() # 查询数据库记录 from typing import List -result:List[User]=session.query(User).filter_by(name='xiaozhong').all() + +result: List[User] = session.query(User).filter_by(name="xiaozhong").all() for item in result: - print(item.name,item.password,item.email) + print(item.name, item.password, item.email) # 仅仅查询提取模型中某些字段信息, -result1:List[User]=session.query(User.name,User.email,User.password).filter_by(name='xiaozhong').all() +result1: List[User] = ( + session.query(User.name, User.email, User.password) + .filter_by(name="xiaozhong") + .all() +) for item in result1: - print(item.name,item.password,item.email) + print(item.name, item.password, item.email) # 进行模糊匹配的查询 -result2:List[User]=session.query(User).filter(User.name.like("xiao%")).all() +result2: List[User] = session.query(User).filter(User.name.like("xiao%")).all() for item in result2: - print(item.name,item.password,item.email) -#字段正则表达式查询 -result3:List[User]=session.query(User).filter(User.name.op("regexp")("^xiao")).all() + print(item.name, item.password, item.email) +# 字段正则表达式查询 +result3: List[User] = session.query(User).filter(User.name.op("regexp")("^xiao")).all() for item in result2: - print(item.name,item.password,item.email) + print(item.name, item.password, item.email) # 查更新 -updata_user:User = session.query(User).filter_by(name='xiaozhong').first() -updata_user.email = 'zyx123@qq,com' +updata_user: User = session.query(User).filter_by(name="xiaozhong").first() +updata_user.email = "zyx123@qq,com" session.commit() -session.query(User).filter_by(name='xiaozhong').update({User.email: 'zyx123456@qq,com'}) +session.query(User).filter_by(name="xiaozhong").update({User.email: "zyx123456@qq,com"}) session.commit() # 查询并函数 -del_user:User = session.query(User).filter_by(name='xiaozhong').first() +del_user: User = session.query(User).filter_by(name="xiaozhong").first() if del_user: session.delete(del_user) session.commit() -session.query(User).filter_by(name='xiaozhong').delete() +session.query(User).filter_by(name="xiaozhong").delete() session.commit() # 或者 -session.query(User).filter(User.name=='xiaozhong').delete(synchronize_session=False) -session.commit() \ No newline at end of file +session.query(User).filter(User.name == "xiaozhong").delete(synchronize_session=False) +session.commit() diff --git a/chapter08/sqlite3_connect/main.py b/chapter08/sqlite3_connect/main.py index 460dfd0..e94811d 100644 --- a/chapter08/sqlite3_connect/main.py +++ b/chapter08/sqlite3_connect/main.py @@ -1,15 +1,19 @@ import sqlite3 -connection = sqlite3.connect('test.db') +connection = sqlite3.connect("test.db") # 创建游标 cursor = connection.cursor() # 创建表 -cursor.execute('''CREATE TABLE user +cursor.execute( + """CREATE TABLE user (id INT PRIMARY KEY NOT NULL, username TEXT NOT NULL, - password TEXT NOT NULL);''') + password TEXT NOT NULL);""" +) # 数据保存 -cursor.execute("INSERT INTO user (id,username,password) VALUES (1, 'xiaozhong', '123456')") +cursor.execute( + "INSERT INTO user (id,username,password) VALUES (1, 'xiaozhong', '123456')" +) cursor.execute("INSERT INTO user (id,username,password) VALUES (2, 'muyu', '123456')") # 数据查询 cursor = cursor.execute("SELECT id, username, password from user") diff --git a/chapter08/sqlmodel_async_sqlite3/main.py b/chapter08/sqlmodel_async_sqlite3/main.py index 2f57e4a..9ca780c 100644 --- a/chapter08/sqlmodel_async_sqlite3/main.py +++ b/chapter08/sqlmodel_async_sqlite3/main.py @@ -2,17 +2,20 @@ from typing import Optional from sqlalchemy.ext.asyncio import create_async_engine -from sqlmodel import SQLModel, Field +from sqlmodel import SQLModel, Field from sqlalchemy.orm import declarative_base, sessionmaker ASYNC_DATABASE_URI = "sqlite+aiosqlite:///aiosqlite_user.db" async_engine = create_async_engine(ASYNC_DATABASE_URI) + + class Users(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) - name:str - nikename:str - password :str - email:str + name: str + nikename: str + password: str + email: str + async def init_create(): async with async_engine.begin() as conn: @@ -20,49 +23,62 @@ async def init_create(): await conn.run_sync(SQLModel.metadata.create_all) - - import asyncio -asyncio.run(init_create()) +asyncio.run(init_create()) from sqlmodel.ext.asyncio.session import AsyncSession -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=async_engine, class_=AsyncSession, expire_on_commit=False) -from sqlmodel import select,update,delete +SessionLocal = sessionmaker( + autocommit=False, + autoflush=False, + bind=async_engine, + class_=AsyncSession, + expire_on_commit=False, +) + +from sqlmodel import select, update, delete + + # 创建用户 async def create(): async with SessionLocal() as async_session: pass - db_obj = Users(name='xiaozhong',nikename='zyx',password='123456',email='zyx@123.com') + db_obj = Users( + name="xiaozhong", nikename="zyx", password="123456", email="zyx@123.com" + ) async_session.add(db_obj) await async_session.commit() await async_session.refresh(db_obj) return db_obj + # 获取用户记录信息 async def get_user(user_id: int): async with SessionLocal() as async_session: response = await async_session.exec(select(Users).where(Users.id == user_id)) return response.first() + # 批量获取多条用户记录信息 async def get_user_multi(name: str): async with SessionLocal() as async_session: response = await async_session.exec(select(Users).where(Users.name == name)) return response.all() + # 批量用户更新 -async def update_user(name:str): +async def update_user(name: str): async with SessionLocal() as async_session: pass updateusers = update(Users).where(Users.name == name) - results = await async_session.exec(updateusers.values(email='xiaozhong@qw.com')) + results = await async_session.exec(updateusers.values(email="xiaozhong@qw.com")) await async_session.commit() + # 单独删除记录 -async def remove(user_id:int): +async def remove(user_id: int): async with SessionLocal() as async_session: pass response = await async_session.exec(select(Users).where(Users.id == id)) @@ -71,18 +87,19 @@ async def remove(user_id:int): await async_session.commit() return obj + # 批量删除 -async def removeall(name:str): +async def removeall(name: str): async with SessionLocal() as async_session: pass response = await async_session.exec(delete(Users).where(Users.name == name)) await async_session.commit() - import asyncio + asyncio.run(create()) -asyncio.run(update_user(name='xiaozhong')) +asyncio.run(update_user(name="xiaozhong")) asyncio.run(get_user(user_id=1)) -asyncio.run(get_user_multi(name='xiaozhong')) -asyncio.run(removeall(name='xiaozhong')) \ No newline at end of file +asyncio.run(get_user_multi(name="xiaozhong")) +asyncio.run(removeall(name="xiaozhong")) diff --git a/chapter08/sqlmodel_sync_sqlite3/main.py b/chapter08/sqlmodel_sync_sqlite3/main.py index 9422626..4de6014 100644 --- a/chapter08/sqlmodel_sync_sqlite3/main.py +++ b/chapter08/sqlmodel_sync_sqlite3/main.py @@ -1,34 +1,42 @@ # 创建引擎对象 from typing import Optional -from sqlmodel import Field, Session, SQLModel, create_engine,update,delete +from sqlmodel import Field, Session, SQLModel, create_engine, update, delete + engine = create_engine("sqlite:///user.db") from sqlmodel import Field, SQLModel + class Users(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) - name:str - nikename:str - password :str - email:str + name: str + nikename: str + password: str + email: str + + +from sqlmodel import Session, select -from sqlmodel import Session,select with Session(engine) as session: allusers = select(Users) results = session.exec(allusers) for user in results: print(user) - print('>'*5) + print(">" * 5) userresult = select(Users).where(Users.name == "xiaozhong1") user = session.exec(userresult).first() print(user) - print('>' * 5) - userresult = select(Users).where(Users.name == "xiaozhong1").where(Users.nikename == "zyx") + print(">" * 5) + userresult = ( + select(Users).where(Users.name == "xiaozhong1").where(Users.nikename == "zyx") + ) users = session.exec(userresult).all() print(users) - print('>' * 5) - userresult = select(Users).where(Users.name == "xiaozhong1",Users.nikename == "zyx") + print(">" * 5) + userresult = select(Users).where( + Users.name == "xiaozhong1", Users.nikename == "zyx" + ) users = session.exec(userresult).all() print(users) @@ -36,14 +44,14 @@ class Users(SQLModel, table=True): results = session.exec(select(Users).where(Users.name == "xiaozhong1")) user = results.first() print("user:", user) - user.email = 'zyx1232@qq.com' + user.email = "zyx1232@qq.com" session.add(user) session.commit() session.refresh(user) with Session(engine) as session: updateusers = update(Users).where(Users.name == "xiaozhong1") - results = session.exec(updateusers.values(email='xiaozhong@qw.com')) + results = session.exec(updateusers.values(email="xiaozhong@qw.com")) session.commit() with Session(engine) as session: @@ -53,4 +61,4 @@ class Users(SQLModel, table=True): with Session(engine) as session: user = session.exec(delete(Users).where(Users.name == "xiaozhong1")) - session.commit() \ No newline at end of file + session.commit() diff --git a/chapter09/api_key/main.py b/chapter09/api_key/main.py index 4abc144..1751c19 100644 --- a/chapter09/api_key/main.py +++ b/chapter09/api_key/main.py @@ -1,6 +1,6 @@ from fastapi import Depends from fastapi import FastAPI, Request -from fastapi.security import APIKeyCookie,APIKeyHeader,APIKeyQuery +from fastapi.security import APIKeyCookie, APIKeyHeader, APIKeyQuery from fastapi.params import Security from typing import Optional from fastapi.exceptions import HTTPException @@ -9,62 +9,74 @@ app = FastAPI( title="基于apikey的特定的密钥的方案", - description='基于apikey的特定的密钥的方案项目演示例子', - version='v1.1.0', + description="基于apikey的特定的密钥的方案项目演示例子", + version="v1.1.0", ) -class APIKey(): + +class APIKey: # APIKeyHeader的鉴权方式 API_KEY_HEADER = "XTOKEN" API_KEY_HEADER_NAME = "X-TOKEN" - api_key_header_token = APIKeyHeader(name=API_KEY_HEADER_NAME, scheme_name="API key header",auto_error=True) + api_key_header_token = APIKeyHeader( + name=API_KEY_HEADER_NAME, scheme_name="API key header", auto_error=True + ) API_KEY_QUERY = "XQUERY" API_KEY_QUERY_NAME = "X-QUERY" - api_key_query_token = APIKeyQuery(name=API_KEY_HEADER_NAME, scheme_name="API key query", auto_error=True) + api_key_query_token = APIKeyQuery( + name=API_KEY_HEADER_NAME, scheme_name="API key query", auto_error=True + ) API_KEY_Cookie = "XCOOKIE" API_KEY_COOKIE_NAME = "X-COOKIE" - api_key_cookie_token = APIKeyCookie(name=API_KEY_COOKIE_NAME, scheme_name="API key cookie", auto_error=False) + api_key_cookie_token = APIKeyCookie( + name=API_KEY_COOKIE_NAME, scheme_name="API key cookie", auto_error=False + ) - async def __call__(self, request: Request, - api_key_header: str = Security(api_key_header_token), - api_key_query: str = Security(api_key_query_token), - api_key_cookie: str = Security(api_key_cookie_token), - ) -> Optional[bool]: + async def __call__( + self, + request: Request, + api_key_header: str = Security(api_key_header_token), + api_key_query: str = Security(api_key_query_token), + api_key_cookie: str = Security(api_key_cookie_token), + ) -> Optional[bool]: if api_key_header != self.API_KEY_HEADER: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="APIKeyHeader的鉴权方式认证失败!" + detail="APIKeyHeader的鉴权方式认证失败!", ) if api_key_query != self.API_KEY_QUERY: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="APIKeyQuery的鉴权方式认证失败!" + detail="APIKeyQuery的鉴权方式认证失败!", ) if not api_key_cookie: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="APIKeyCookie中的cookie没有值!" + detail="APIKeyCookie中的cookie没有值!", ) if api_key_cookie != self.API_KEY_Cookie: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="APIKeyCookie的鉴权方式认证失败!" + detail="APIKeyCookie的鉴权方式认证失败!", ) return True + apikeiauth = APIKey() + @app.get("/apikey") async def digest(request: Request, auth: bool = Depends(apikeiauth)): # print(credentials) if auth: - return PlainTextResponse('登入成功') + return PlainTextResponse("登入成功") -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8000, debug=True, reload=True) \ No newline at end of file + + uvicorn.run("main:app", host="127.0.0.1", port=8000, debug=True, reload=True) diff --git a/chapter09/http_basic/main.py b/chapter09/http_basic/main.py index 3f7c38b..9c35281 100644 --- a/chapter09/http_basic/main.py +++ b/chapter09/http_basic/main.py @@ -7,27 +7,32 @@ app = FastAPI( title="HTTPBasic认证示例", - description='HTTPBasic认证示例项目演示例子', - version='v1.1.0', + description="HTTPBasic认证示例项目演示例子", + version="v1.1.0", ) security = HTTPBasic() + @app.get("/login") async def login(credentials: HTTPBasicCredentials = Depends(security)): - if credentials.username != "xiaozhongtongxue" or credentials.password != "xiaozhongtongxue": + if ( + credentials.username != "xiaozhongtongxue" + or credentials.password != "xiaozhongtongxue" + ): raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="用户名或密码错误", headers={"WWW-Authenticate": "Basic"}, ) else: - return PlainTextResponse('登入成功') + return PlainTextResponse("登入成功") if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) \ No newline at end of file + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter09/http_digest/main.py b/chapter09/http_digest/main.py index be3c3cf..a67a064 100644 --- a/chapter09/http_digest/main.py +++ b/chapter09/http_digest/main.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -34,8 +34,16 @@ from fastapi import Depends from fastapi import FastAPI, Request -from fastapi.security import HTTPBasic, HTTPBasicCredentials, HTTPAuthorizationCredentials -from fastapi.security.http import HTTPBase, HTTPBaseModel, get_authorization_scheme_param +from fastapi.security import ( + HTTPBasic, + HTTPBasicCredentials, + HTTPAuthorizationCredentials, +) +from fastapi.security.http import ( + HTTPBase, + HTTPBaseModel, + get_authorization_scheme_param, +) from fastapi.exceptions import HTTPException from fastapi.responses import PlainTextResponse from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN @@ -45,27 +53,25 @@ app = FastAPI( title="HTTPBasic认证示例", - description='HTTPBasic认证示例项目演示例子', - version='v1.1.0', + description="HTTPBasic认证示例项目演示例子", + version="v1.1.0", ) - - class HTTPDigest(HTTPBase): def __init__( - self, - *, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, - # 表示Web服务器中受保护文档的安全域(比如公司财务信息域和公司员工信息域),用来指示需要哪个域的用户名和密码 - realm: Optional[str] = None, - # 保护质量,包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略,(可以为空,但是)不推荐为空值 - qop: Optional[str] = "auth, auth-int", - # 由服务器指定的字符串,客户端在后续指向同一个受保护区间的请求中应该在 Authorization 头中原样返回,建议使用 base64 或者 16 进制数 - opaque: Optional[str] = None, + self, + *, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True, + # 表示Web服务器中受保护文档的安全域(比如公司财务信息域和公司员工信息域),用来指示需要哪个域的用户名和密码 + realm: Optional[str] = None, + # 保护质量,包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略,(可以为空,但是)不推荐为空值 + qop: Optional[str] = "auth, auth-int", + # 由服务器指定的字符串,客户端在后续指向同一个受保护区间的请求中应该在 Authorization 头中原样返回,建议使用 base64 或者 16 进制数 + opaque: Optional[str] = None, ): self.model = HTTPBaseModel(scheme="digest", description=description) self.scheme_name = scheme_name or self.__class__.__name__ @@ -81,15 +87,13 @@ def __init__( self.random = Random() def _generate_random(self): - return md5(str(self.random.random()).encode('utf-8')).hexdigest() + return md5(str(self.random.random()).encode("utf-8")).hexdigest() @property def default_generate_nonce(self): return self._generate_random() - async def __call__( - self, request: Request - ): + async def __call__(self, request: Request): authorization: str = request.headers.get("Authorization") scheme, credentials = get_authorization_scheme_param(authorization) @@ -101,9 +105,12 @@ async def __call__( if self.realm and self.qop: self.nonce = self.default_generate_nonce self.unauthorized_headers = { - "WWW-Authenticate": f'Digest realm="{self.realm}",qop="{self.qop}",nonce="{self.nonce}'} + "WWW-Authenticate": f'Digest realm="{self.realm}",qop="{self.qop}",nonce="{self.nonce}' + } else: - self.unauthorized_headers = {"WWW-Authenticate": f'Digest realm="{self.realm}",'} + self.unauthorized_headers = { + "WWW-Authenticate": f'Digest realm="{self.realm}",' + } raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="Unauthorized", @@ -119,9 +126,9 @@ async def __call__( detail="Invalid authentication credentials", ) self.request.state.auth_seeions = {} - self.request.state.auth_seeions['realm'] = self.realm - self.request.state.auth_seeions['qop'] = self.qop - self.request.state.auth_seeions['nonce'] = self.nonce + self.request.state.auth_seeions["realm"] = self.realm + self.request.state.auth_seeions["qop"] = self.qop + self.request.state.auth_seeions["nonce"] = self.nonce # self return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) @@ -130,28 +137,37 @@ async def __call__( def default_verify_password(password, credentials, request: Request): # 参数校验是否非法,如果非法的话,那么需要重新的发起一下需要重新的输入用户名称和密码 - realm = request.state.auth_seeions['realm'] - qop = request.state.auth_seeions['qop'] - nonce = request.state.auth_seeions['nonce'] + realm = request.state.auth_seeions["realm"] + qop = request.state.auth_seeions["qop"] + nonce = request.state.auth_seeions["nonce"] unauthorized_headers = { - "WWW-Authenticate": f'Digest realm="{realm}",qop="{qop}",nonce="{nonce}'} + "WWW-Authenticate": f'Digest realm="{realm}",qop="{qop}",nonce="{nonce}' + } raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="Unauthorized", headers=unauthorized_headers, ) - datas = {item[0]: item[1] for item in - [iten.split('=') for iten in credentials.replace('"', '').split(', ')]} + datas = { + item[0]: item[1] + for item in [ + iten.split("=") for iten in credentials.replace('"', "").split(", ") + ] + } # 验证值信息,验证账号密码信息,验证用户信息,验证报文信息 if datas: - ha1 = generate_ha1(username=datas.get('username'), realm=realm, password=password) + ha1 = generate_ha1( + username=datas.get("username"), realm=realm, password=password + ) ha2 = generate_ha2(request) # 计算摘要的公式MD5(MD5(A1):::::MD5(A2)) response = md5( f"{ha1}:{datas.get('nonce')}:{datas.get('nc')}:{datas.get('cnonce')}:{datas.get('qop')}:{ha2}".encode( - 'utf-8')).hexdigest() + "utf-8" + ) + ).hexdigest() - if response != datas.get('response'): + if response != datas.get("response"): raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="Unauthorized", @@ -169,13 +185,13 @@ def default_verify_password(password, credentials, request: Request): def generate_ha1(username, realm, password): a1 = username + ":" + realm + ":" + password - a1 = a1.encode('utf-8') + a1 = a1.encode("utf-8") return md5(a1).hexdigest() def generate_ha2(requet: Request): a2 = requet.method + ":" + requet.url.path - a2 = a2.encode('utf-8') + a2 = a2.encode("utf-8") return md5(a2).hexdigest() @@ -183,13 +199,17 @@ def generate_ha2(requet: Request): @app.get("/digest") -async def digest(request: Request, auth: HTTPAuthorizationCredentials = Depends(security)): +async def digest( + request: Request, auth: HTTPAuthorizationCredentials = Depends(security) +): # print(credentials) - if default_verify_password(password='123456', credentials=auth.credentials, request=request): - return PlainTextResponse('登入成功') + if default_verify_password( + password="123456", credentials=auth.credentials, request=request + ): + return PlainTextResponse("登入成功") -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main2:app', host="127.0.0.1", port=8000, debug=True, reload=True) + uvicorn.run("main2:app", host="127.0.0.1", port=8000, debug=True, reload=True) diff --git a/chapter09/jwt_use/main.py b/chapter09/jwt_use/main.py index 8ca9d56..98bf25f 100644 --- a/chapter09/jwt_use/main.py +++ b/chapter09/jwt_use/main.py @@ -22,15 +22,15 @@ def token_decode(token): data = { - 'iss ': "xiaozhong", - 'sub': 'xiaozhongtongxue', - 'name': 'superadmin', - 'admin': True, - 'exp': datetime.utcnow() + timedelta(minutes=15) + "iss ": "xiaozhong", + "sub": "xiaozhongtongxue", + "name": "superadmin", + "admin": True, + "exp": datetime.utcnow() + timedelta(minutes=15), } token = TokenUtils.token_encode(data=data) print(token) -payload = TokenUtils.token_decode(token =token) +payload = TokenUtils.token_decode(token=token) print(payload) diff --git a/chapter09/mode_client/main.py b/chapter09/mode_client/main.py index 7f40fba..6f24762 100644 --- a/chapter09/mode_client/main.py +++ b/chapter09/mode_client/main.py @@ -15,8 +15,8 @@ app = FastAPI( title="oauth2客户端模式", - description='oauth2客户端模式示例项目演示例子', - version='v1.1.0', + description="oauth2客户端模式示例项目演示例子", + version="v1.1.0", ) # 阿里云云存储服务商维护的第三方客户端数据表信息 @@ -55,12 +55,12 @@ def token_decode(token): class OAuth2ClientCredentialsBearer(OAuth2): def __init__( - self, - tokenUrl: str, - scheme_name: Optional[str] = None, - scopes: Optional[Dict[str, str]] = None, - description: Optional[str] = None, - auto_error: bool = True, + self, + tokenUrl: str, + scheme_name: Optional[str] = None, + scopes: Optional[Dict[str, str]] = None, + description: Optional[str] = None, + auto_error: bool = True, ): if not scopes: scopes = {} @@ -92,19 +92,21 @@ async def __call__(self, request: Request) -> Optional[str]: return param -oauth2_scheme = OAuth2ClientCredentialsBearer(tokenUrl="/oauth2/authorize",scheme_name="客户端模式",description="我是描述") +oauth2_scheme = OAuth2ClientCredentialsBearer( + tokenUrl="/oauth2/authorize", scheme_name="客户端模式", description="我是描述" +) class OAuth2ClientCredentialsRequestForm: def __init__( - self, - grant_type: str = Query(..., regex="client_credentials"), - scope: str = Query(""), - client_id: str = Query(...), - client_secret: str = Query(...), - username: Optional[str] = Query(None), - password: Optional[str] = Query(None), + self, + grant_type: str = Query(..., regex="client_credentials"), + scope: str = Query(""), + client_id: str = Query(...), + client_secret: str = Query(...), + username: Optional[str] = Query(None), + password: Optional[str] = Query(None), ): self.grant_type = grant_type self.scopes = scope.split() @@ -120,49 +122,67 @@ async def authorize(client_data: OAuth2ClientCredentialsRequestForm = Depends()) raise HTTPException(status_code=400, detail="请输入用户账号及密码等信息") if not client_data.client_id and not client_data.client_secret: - raise HTTPException(status_code=400, detail="请输入分配给第三方APPID及秘钥等信息") + raise HTTPException( + status_code=400, detail="请输入分配给第三方APPID及秘钥等信息" + ) clientinfo = fake_client_db.get(client_data.client_id) if client_data.client_id not in fake_client_db: - raise HTTPException(status_code=400, detail="非法第三方客户端APPID", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="非法第三方客户端APPID", + headers={"WWW-Authenticate": f"Bearer"}, + ) - if client_data.client_secret != clientinfo.get('client_secret'): + if client_data.client_secret != clientinfo.get("client_secret"): raise HTTPException(status_code=400, detail="第三方客户端部秘钥不正确!") data = { - 'iss ': 'client_id', - 'sub': 'xiaozhongtongxue', - 'client_id': client_data.client_id, - 'exp': datetime.utcnow() + timedelta(minutes=15) + "iss ": "client_id", + "sub": "xiaozhongtongxue", + "client_id": client_data.client_id, + "exp": datetime.utcnow() + timedelta(minutes=15), } token = TokenUtils.token_encode(data=data) - return {"access_token": token, "token_type": "bearer","exires_in":159,"scope":"all"} + return { + "access_token": token, + "token_type": "bearer", + "exires_in": 159, + "scope": "all", + } # 需要授权才可以 @app.get("/get/clientinfo", summary="请求用户信息地址(受保护资源)") async def get_clientinfo(token: str = Depends(oauth2_scheme)): - ''' + """ 定义API接口。改API接口需要token值并校验通过才可以访问 :param token: :return: - ''' + """ payload = TokenUtils.token_decode(token=token) # 定义认证异常信息 - client_id = payload.get('client_id') + client_id = payload.get("client_id") if client_id not in client_id: - raise HTTPException(status_code=400, detail="不存在client_id信息", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="不存在client_id信息", + headers={"WWW-Authenticate": f"Bearer"}, + ) clientinfo = fake_client_db.get(client_id) - return {'info': { - 'client_id': clientinfo.get('client_id'), - 'client_secret': clientinfo.get('client_secret') - }} + return { + "info": { + "client_id": clientinfo.get("client_id"), + "client_secret": clientinfo.get("client_secret"), + } + } if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter09/mode_code/get_token.py b/chapter09/mode_code/get_token.py index 248b6c0..2613357 100644 --- a/chapter09/mode_code/get_token.py +++ b/chapter09/mode_code/get_token.py @@ -7,12 +7,15 @@ @app.get("/get/access_token") async def access_token(code: str): import requests + # 第三方服务端请求授权服务器获取access_token的地址 - rsp = requests.get(f"http://127.0.0.1:8000/oauth2/authorize/access_token?client_id=xiaozhong&client_secret=123456&code={code}").json() - access_token = rsp.get('access_token') - refresh_token = rsp.get('refresh_token') - access_token_expires = rsp.get('expires_in') - username = rsp.get('userid') + rsp = requests.get( + f"http://127.0.0.1:8000/oauth2/authorize/access_token?client_id=xiaozhong&client_secret=123456&code={code}" + ).json() + access_token = rsp.get("access_token") + refresh_token = rsp.get("refresh_token") + access_token_expires = rsp.get("expires_in") + username = rsp.get("userid") return { "access_token": access_token, # access_token接口调用凭证超时时间 @@ -20,10 +23,11 @@ async def access_token(code: str): "refresh_token": refresh_token, "token_type": "bearer", "userid": username, - "scope": "SCOPE" + "scope": "SCOPE", } -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('get_token:app', host="127.0.0.1", port=8100, debug=True, reload=True) \ No newline at end of file + + uvicorn.run("get_token:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter09/mode_code/main.py b/chapter09/mode_code/main.py index 8ab220c..e12c233 100644 --- a/chapter09/mode_code/main.py +++ b/chapter09/mode_code/main.py @@ -1,7 +1,7 @@ from datetime import datetime, timedelta from typing import List, Optional from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import (SecurityScopes, OAuth2AuthorizationCodeBearer) +from fastapi.security import SecurityScopes, OAuth2AuthorizationCodeBearer from jose import JWTError, jwt from pydantic import BaseModel, ValidationError from fastapi.responses import RedirectResponse @@ -14,11 +14,11 @@ oauth2_scheme = OAuth2AuthorizationCodeBearer( # 授权认证的URL地址 - authorizationUrl='/oauth2/authorize', + authorizationUrl="/oauth2/authorize", # 配置授权的请求的是进行授权处理的接口地址 tokenUrl="/oauth2/authorize/access_token", # # 刷新获取新的token的地址 - refreshUrl='refreshUrl', + refreshUrl="refreshUrl", # 定义我们的操作文档显示授权码授权区域----这个和下面的授权的区域关联起来,表示某个接口需要的授权域 scopes={ "get_admin_info": "获取管理员用户信息", @@ -26,8 +26,7 @@ "get_user_info": "获取用户信息", "get_user_role": "获取用户所属角色信息", "get_user_permission": "获取用户相关的权限信息", - - } + }, ) # 用户信息表 @@ -107,12 +106,12 @@ def authenticate_client_id(fake_db, client_id: str): # 创建我们的授权之后,给用户签发的TOKEN def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): - ''' + """ 签发token :param data: data里面包含用户信息和签发授权的作用域信息 :param expires_delta: :return: - ''' + """ to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta @@ -123,7 +122,9 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): return encoded_jwt -async def get_current_user(security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)): +async def get_current_user( + security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) +): print("当前认证方案里面的作用域:", security_scopes.scope_str) if security_scopes.scopes: authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' @@ -172,7 +173,9 @@ async def get_current_user(security_scopes: SecurityScopes, token: str = Depends # 注意接口的也可以定义相关的权限的依赖!!!!或者组合的,比如我这里要是定义其他的话,依赖这个的接口,如果没有这个权限也无法访问! -async def get_current_active_user(current_user: User = Security(get_current_user, scopes=["get_admin_info"])): +async def get_current_active_user( + current_user: User = Security(get_current_user, scopes=["get_admin_info"]) +): # 判断用书是否已经被禁用了!!!如果没有则继续执行 if current_user.disabled: raise HTTPException(status_code=400, detail="Inactive user") @@ -187,22 +190,28 @@ async def access_token(client_id: str, client_secret: str, code: str): raise HTTPException(status_code=400, detail="合作方client不存在") if client.client_id not in fake_client_db: - raise HTTPException(status_code=400, detail="非法第三方客户端APPID", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="非法第三方客户端APPID", + headers={"WWW-Authenticate": f"Bearer"}, + ) if client.client_secret != client_secret: raise HTTPException(status_code=400, detail="第三方客户端部秘钥不正确!") access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - scopes = ['get_admin_info', 'del_admin_info'] + scopes = ["get_admin_info", "del_admin_info"] # print('当前写入的作用去scopes:', scopes) - username = 'xiaozhongtongxue' + username = "xiaozhongtongxue" access_token = create_access_token( data={"sub": username, "scopes": scopes}, expires_delta=access_token_expires, ) # 刷新refresh_token过期的时间 - refresh_access_token_expires = timedelta(minutes=REFRRSH_ACCESS_TOKEN_EXPIRE_MINUTES) + refresh_access_token_expires = timedelta( + minutes=REFRRSH_ACCESS_TOKEN_EXPIRE_MINUTES + ) # 刷新refresh_token refresh_token = create_access_token( data={"sub": client_id, "scopes": scopes}, @@ -216,14 +225,18 @@ async def access_token(client_id: str, client_secret: str, code: str): "refresh_token": refresh_token, "token_type": "bearer", "userid": username, - "scope": "SCOPE" + "scope": "SCOPE", } # 必须使用GET的请求才可以 @app.get("/oauth2/authorize") -async def authorizationUrl(client_id: Optional[str], redirect_uri: Optional[str], scopes: str = None, - response_type: Optional[str] = 'code'): +async def authorizationUrl( + client_id: Optional[str], + redirect_uri: Optional[str], + scopes: str = None, + response_type: Optional[str] = "code", +): # 开始对这个用户对应的信息验证处理,然后生产我们的code client = authenticate_client_id(fake_client_db, client_id) if not client: @@ -231,46 +244,71 @@ async def authorizationUrl(client_id: Optional[str], redirect_uri: Optional[str] # 重定向到授权服务器自身的内部的用户登入授权接口,这里使用HTTPBasic来实现 # 开始进行回调 redirect_uri = "http://127.0.0.1:8100/get/access_token" - return RedirectResponse(url=f'/oauth2/authorize/user/agent?redirect_uri={redirect_uri}') + return RedirectResponse( + url=f"/oauth2/authorize/user/agent?redirect_uri={redirect_uri}" + ) security = HTTPBasic() @app.get("/oauth2/authorize/user/agent") -async def user_agent(*, credentials: HTTPBasicCredentials = Depends(security), redirect_uri: str): +async def user_agent( + *, credentials: HTTPBasicCredentials = Depends(security), redirect_uri: str +): userinfo = fake_users_db.get(credentials.username) if credentials.username not in fake_users_db: - raise HTTPException(status_code=400, detail="不存在此用户信息", headers={"WWW-Authenticate": f"Bearer"}) - if credentials.password != userinfo.get('password'): - raise HTTPException(status_code=401, detail="用户密码不对", headers={"WWW-Authenticate": "Basic"}, ) + raise HTTPException( + status_code=400, + detail="不存在此用户信息", + headers={"WWW-Authenticate": f"Bearer"}, + ) + if credentials.password != userinfo.get("password"): + raise HTTPException( + status_code=401, + detail="用户密码不对", + headers={"WWW-Authenticate": "Basic"}, + ) import random - code = random.sample('abcdefghijklmnopqrstuvwxyz', 16) - return RedirectResponse(url=redirect_uri + "?code=" + ''.join(code)) + + code = random.sample("abcdefghijklmnopqrstuvwxyz", 16) + return RedirectResponse(url=redirect_uri + "?code=" + "".join(code)) @app.get("/api/v1/get_admin_info", response_model=User) -async def get_admin_info(current_user: User = Security(get_current_active_user, scopes=["get_admin_info"])): +async def get_admin_info( + current_user: User = Security(get_current_active_user, scopes=["get_admin_info"]) +): return current_user @app.get("/api/v1/del_admin_info", response_model=User) -async def del_admin_info(current_user: User = Security(get_current_active_user, scopes=["del_admin_info"])): +async def del_admin_info( + current_user: User = Security(get_current_active_user, scopes=["del_admin_info"]) +): return current_user @app.get("/api/v1/get_user_info", response_model=User) -async def get_user_info(current_user: User = Security(get_current_active_user, scopes=["get_user_info"])): +async def get_user_info( + current_user: User = Security(get_current_active_user, scopes=["get_user_info"]) +): return current_user @app.get("/api/v1/get_user_role", response_model=User) -async def get_user_role(current_user: User = Security(get_current_active_user, scopes=["get_user_role"])): +async def get_user_role( + current_user: User = Security(get_current_active_user, scopes=["get_user_role"]) +): return current_user @app.get("/api/v1/get_user_permission", response_model=User) -async def get_user_role(current_user: User = Security(get_current_active_user, scopes=["get_user_permission"])): +async def get_user_role( + current_user: User = Security( + get_current_active_user, scopes=["get_user_permission"] + ) +): return current_user @@ -280,4 +318,4 @@ async def get_user_role(current_user: User = Security(get_current_active_user, s app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter09/mode_password/main.py b/chapter09/mode_password/main.py index dc1fcd4..0ad4d02 100644 --- a/chapter09/mode_password/main.py +++ b/chapter09/mode_password/main.py @@ -9,8 +9,8 @@ app = FastAPI( title="oauth2密码模式", - description='oauth2密码模式示例项目演示例子', - version='v1.1.0', + description="oauth2密码模式示例项目演示例子", + version="v1.1.0", ) # 微信资源服务器上用户数据表信息 @@ -67,28 +67,38 @@ async def login(user_form_data: OAuth2PasswordRequestForm = Depends()): raise HTTPException(status_code=400, detail="请输入用户账号及密码等信息") if not user_form_data.client_id and not user_form_data.client_secret: - raise HTTPException(status_code=400, detail="请输入分配给第三方APPID及秘钥等信息") + raise HTTPException( + status_code=400, detail="请输入分配给第三方APPID及秘钥等信息" + ) userinfo = fake_users_db.get(user_form_data.username) if user_form_data.username not in fake_users_db: - raise HTTPException(status_code=400, detail="不存在此用户信息", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="不存在此用户信息", + headers={"WWW-Authenticate": f"Bearer"}, + ) - if user_form_data.password != userinfo.get('password'): + if user_form_data.password != userinfo.get("password"): raise HTTPException(status_code=400, detail="用户密码不对") clientinfo = fake_client_db.get(user_form_data.client_id) if user_form_data.client_id not in fake_client_db: - raise HTTPException(status_code=400, detail="非法第三方客户端APPID", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="非法第三方客户端APPID", + headers={"WWW-Authenticate": f"Bearer"}, + ) - if user_form_data.client_secret != clientinfo.get('client_secret'): + if user_form_data.client_secret != clientinfo.get("client_secret"): raise HTTPException(status_code=400, detail="第三方客户端部秘钥不正确!") data = { - 'iss ': user_form_data.username, - 'sub': 'xiaozhongtongxue', - 'username': user_form_data.username, - 'admin': True, - 'exp': datetime.utcnow() + timedelta(minutes=15) + "iss ": user_form_data.username, + "sub": "xiaozhongtongxue", + "username": user_form_data.username, + "admin": True, + "exp": datetime.utcnow() + timedelta(minutes=15), } token = TokenUtils.token_encode(data=data) @@ -101,20 +111,23 @@ async def login(user_form_data: OAuth2PasswordRequestForm = Depends()): async def get_user_password(token: str = Depends(oauth2_scheme)): payload = TokenUtils.token_decode(token=token) # 定义认证异常信息 - username = payload.get('username') + username = payload.get("username") if username not in fake_users_db: - raise HTTPException(status_code=400, detail="不存在此用户信息", headers={"WWW-Authenticate": f"Bearer"}) + raise HTTPException( + status_code=400, + detail="不存在此用户信息", + headers={"WWW-Authenticate": f"Bearer"}, + ) userinfo = fake_users_db.get(username) - return {'info': { - 'username': username, - 'password': userinfo.get('password') - }} + return {"info": {"username": username, "password": userinfo.get("password")}} + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter10/shorr_url_pro/api/__init__.py b/chapter10/shorr_url_pro/api/__init__.py index 937e99a..8b51fd3 100644 --- a/chapter10/shorr_url_pro/api/__init__.py +++ b/chapter10/shorr_url_pro/api/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter10/shorr_url_pro/api/short.py b/chapter10/shorr_url_pro/api/short.py index d8392a3..da97525 100644 --- a/chapter10/shorr_url_pro/api/short.py +++ b/chapter10/shorr_url_pro/api/short.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends,BackgroundTasks +from fastapi import APIRouter, Depends, BackgroundTasks from fastapi.responses import RedirectResponse, PlainTextResponse from dependencies import get_db_session from db.database import AsyncSession @@ -7,11 +7,21 @@ router_short = APIRouter(tags=["短链访问"]) -@router_short.get('/{short_tag}') -async def short_redirect(*,short_tag: str, db_session: AsyncSession = Depends(get_db_session),taks:BackgroundTasks): +@router_short.get("/{short_tag}") +async def short_redirect( + *, + short_tag: str, + db_session: AsyncSession = Depends(get_db_session), + taks: BackgroundTasks +): data = await ShortServeries.get_short_url(db_session, short_tag) if not data: return PlainTextResponse("没有对应短链信息记录") - data.visits_count=data.visits_count+1 - taks.add_task(ShortServeries.update_short_url,db_session,short_url_id=data.id,visits_count=data.visits_count) - return RedirectResponse(url=data.long_url) \ No newline at end of file + data.visits_count = data.visits_count + 1 + taks.add_task( + ShortServeries.update_short_url, + db_session, + short_url_id=data.id, + visits_count=data.visits_count, + ) + return RedirectResponse(url=data.long_url) diff --git a/chapter10/shorr_url_pro/api/user.py b/chapter10/shorr_url_pro/api/user.py index 35626e0..8414da5 100644 --- a/chapter10/shorr_url_pro/api/user.py +++ b/chapter10/shorr_url_pro/api/user.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -32,7 +32,7 @@ @文件功能描述:------ """ from fastapi import APIRouter -from schemas.user import UserCreate,UserUpdate +from schemas.user import UserCreate, UserUpdate from servies.user import UserServeries from db.database import AsyncSession from dependencies import get_db_session @@ -42,30 +42,32 @@ @router_uesr.post("/user/creat") -async def creat(user:UserCreate,db_session: AsyncSession = Depends(get_db_session)): - result= await UserServeries.create_user(db_session,**user.dict()) - return {"code": "200", "msg": "用户创建成功!","data":result} +async def creat(user: UserCreate, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.create_user(db_session, **user.dict()) + return {"code": "200", "msg": "用户创建成功!", "data": result} @router_uesr.get("/user/info") -async def info(user_id:int,db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.get_user(db_session,user_id=user_id) - return {"code": "200", "msg": "查询用户信息成功!","data":result} +async def info(user_id: int, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.get_user(db_session, user_id=user_id) + return {"code": "200", "msg": "查询用户信息成功!", "data": result} @router_uesr.get("/user/list") async def list(db_session: AsyncSession = Depends(get_db_session)): result = await UserServeries.get_users(db_session) - return {"code": "200", "msg": "查询用户列表信息成功!","data":result} + return {"code": "200", "msg": "查询用户列表信息成功!", "data": result} @router_uesr.put("/user/edit") -async def edit(user:UserUpdate,db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.update_user(db_session,user_id=user.id,name=user.name) - return {"code": "200", "msg": "修改用户信息成功!","data":None} +async def edit(user: UserUpdate, db_session: AsyncSession = Depends(get_db_session)): + result = await UserServeries.update_user( + db_session, user_id=user.id, name=user.name + ) + return {"code": "200", "msg": "修改用户信息成功!", "data": None} @router_uesr.delete("/user/delete") -async def delete(user_id:int,db_session: AsyncSession = Depends(get_db_session)): +async def delete(user_id: int, db_session: AsyncSession = Depends(get_db_session)): result = await UserServeries.delete_user(db_session, user_id=user_id) return {"code": "200", "msg": "删除用户信息成功!"} diff --git a/chapter10/shorr_url_pro/config/__init__.py b/chapter10/shorr_url_pro/config/__init__.py index 5f7693a..1efc88f 100644 --- a/chapter10/shorr_url_pro/config/__init__.py +++ b/chapter10/shorr_url_pro/config/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter10/shorr_url_pro/config/config.py b/chapter10/shorr_url_pro/config/config.py index 8284195..3c7c826 100644 --- a/chapter10/shorr_url_pro/config/config.py +++ b/chapter10/shorr_url_pro/config/config.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -35,12 +35,14 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 定义连接异步引擎数据库的URL地址 ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///short.db" # 定义TOEKN的签名信息值 - TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' + TOKEN_SIGN_SECRET: str = "ZcjT6Rcp1yIFQoS7" + @lru_cache() def get_settings(): - return Settings() \ No newline at end of file + return Settings() diff --git a/chapter10/shorr_url_pro/db/__init__.py b/chapter10/shorr_url_pro/db/__init__.py index bd31053..707ab3b 100644 --- a/chapter10/shorr_url_pro/db/__init__.py +++ b/chapter10/shorr_url_pro/db/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter10/shorr_url_pro/db/database.py b/chapter10/shorr_url_pro/db/database.py index 30aa653..e84b19e 100644 --- a/chapter10/shorr_url_pro/db/database.py +++ b/chapter10/shorr_url_pro/db/database.py @@ -1,11 +1,15 @@ # 导入异步引擎的模块 from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import declarative_base, sessionmaker + # URL地址格式 from config.config import get_settings + # 创建异步引擎对象 async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) # 创建ORM模型基类 Base = declarative_base() # 创建异步的会话管理对象 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) diff --git a/chapter10/shorr_url_pro/dependencies/__init__.py b/chapter10/shorr_url_pro/dependencies/__init__.py index c0f521b..ade4cb4 100644 --- a/chapter10/shorr_url_pro/dependencies/__init__.py +++ b/chapter10/shorr_url_pro/dependencies/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -35,6 +35,7 @@ from typing import AsyncGenerator from db.database import SessionLocal + async def get_db_session() -> AsyncGenerator[AsyncSession, None]: db_session = None try: diff --git a/chapter10/shorr_url_pro/main.py b/chapter10/shorr_url_pro/main.py index 877fb90..457820d 100644 --- a/chapter10/shorr_url_pro/main.py +++ b/chapter10/shorr_url_pro/main.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -33,28 +33,35 @@ """ - from fastapi import FastAPI -app = FastAPI(title='fastapi集成短链实战案例') + +app = FastAPI(title="fastapi集成短链实战案例") + @app.on_event("startup") async def startup_event(): pass from db.database import async_engine, Base - from models.model import User,ShortUrl + from models.model import User, ShortUrl + async def init_create_table(): async with async_engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.create_all) + await init_create_table() + @app.on_event("shutdown") async def shutdown_event(): pass + from api.user import router_uesr + app.include_router(router_uesr) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) \ No newline at end of file + + uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True) diff --git a/chapter10/shorr_url_pro/models/__init__.py b/chapter10/shorr_url_pro/models/__init__.py index 8809e4e..9ebe08a 100644 --- a/chapter10/shorr_url_pro/models/__init__.py +++ b/chapter10/shorr_url_pro/models/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -33,4 +33,4 @@ """ -from .model import User \ No newline at end of file +from .model import User diff --git a/chapter10/shorr_url_pro/models/model.py b/chapter10/shorr_url_pro/models/model.py index 20bf742..11edcc2 100644 --- a/chapter10/shorr_url_pro/models/model.py +++ b/chapter10/shorr_url_pro/models/model.py @@ -7,7 +7,7 @@ class User(Base): # 指定本类映射到users表 - __tablename__ = 'user' + __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) # 用户姓名 username = Column(String(20)) @@ -16,21 +16,22 @@ class User(Base): # 用户创建时间 created_at = Column(DateTime(), default=func.now()) + class ShortUrl(Base): # 指定本类映射到users表 - __tablename__ = 'short_url' + __tablename__ = "short_url" id = Column(Integer, primary_key=True, autoincrement=True) # 短链标签 - short_tag = Column(String(20),nullable=False) + short_tag = Column(String(20), nullable=False) # 短连接地址 short_url = Column(String(20)) # 长链接地址 long_url = Column(String, nullable=False) # 访问次数 - visits_count= Column(Integer, nullable=True) + visits_count = Column(Integer, nullable=True) # 短链创建时间 created_at = Column(DateTime(), default=func.now()) # 短链创建时间 created_by = Column(String(20)) # 短信内容 - msg_context = Column(String, nullable=False) \ No newline at end of file + msg_context = Column(String, nullable=False) diff --git a/chapter10/shorr_url_pro/schemas/__init__.py b/chapter10/shorr_url_pro/schemas/__init__.py index 9b25443..5eae624 100644 --- a/chapter10/shorr_url_pro/schemas/__init__.py +++ b/chapter10/shorr_url_pro/schemas/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter10/shorr_url_pro/schemas/user.py b/chapter10/shorr_url_pro/schemas/user.py index dc90d05..327956c 100644 --- a/chapter10/shorr_url_pro/schemas/user.py +++ b/chapter10/shorr_url_pro/schemas/user.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -34,22 +34,26 @@ from pydantic import BaseModel + class UserCreate(BaseModel): """ 创建新用户记录时候需要传递参数信息 """ + name: str password: str nikename: str email: str + class UserUpdate(BaseModel): """ Pydantic user schema containing attributes received via the API for updating user details. """ + id: int - name: str =None - password: str =None - nikename: str=None - email: str=None \ No newline at end of file + name: str = None + password: str = None + nikename: str = None + email: str = None diff --git a/chapter10/shorr_url_pro/servies/__init__.py b/chapter10/shorr_url_pro/servies/__init__.py index bd31053..707ab3b 100644 --- a/chapter10/shorr_url_pro/servies/__init__.py +++ b/chapter10/shorr_url_pro/servies/__init__.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ diff --git a/chapter10/shorr_url_pro/servies/short.py b/chapter10/shorr_url_pro/servies/short.py index 0f17a05..3f7ee27 100644 --- a/chapter10/shorr_url_pro/servies/short.py +++ b/chapter10/shorr_url_pro/servies/short.py @@ -8,7 +8,9 @@ class ShortServeries: @staticmethod async def get_short_url(async_session: AsyncSession, short_tag: str): - result = await async_session.execute(select(ShortUrl).where(ShortUrl.short_tag == short_tag)) + result = await async_session.execute( + select(ShortUrl).where(ShortUrl.short_tag == short_tag) + ) return result.scalars().first() @staticmethod @@ -19,7 +21,9 @@ async def create_short_url(async_session: AsyncSession, **kwargs): return new_short_url @staticmethod - async def update_short_url(async_session: AsyncSession, short_url_id: int, **kwargs): + async def update_short_url( + async_session: AsyncSession, short_url_id: int, **kwargs + ): response = update(ShortUrl).where(ShortUrl.id == short_url_id) result = await async_session.execute(response.values(**kwargs)) await async_session.commit() @@ -27,7 +31,9 @@ async def update_short_url(async_session: AsyncSession, short_url_id: int, **kwa @staticmethod async def delete_short_url(async_session: AsyncSession, short_url_id: int): - response = await async_session.execute(delete(ShortUrl).where(ShortUrl.id == short_url_id)) + response = await async_session.execute( + delete(ShortUrl).where(ShortUrl.id == short_url_id) + ) await async_session.commit() return response @@ -35,4 +41,4 @@ async def delete_short_url(async_session: AsyncSession, short_url_id: int): async def create_batch_short_url(async_session: AsyncSession, short_urls: List): async_session.add_all(short_urls) await async_session.commit() - return short_urls \ No newline at end of file + return short_urls diff --git a/chapter10/shorr_url_pro/servies/user.py b/chapter10/shorr_url_pro/servies/user.py index 0c5a20c..fe96e88 100644 --- a/chapter10/shorr_url_pro/servies/user.py +++ b/chapter10/shorr_url_pro/servies/user.py @@ -42,4 +42,4 @@ async def update_user(async_session: AsyncSession, user_id: int, **kwargs): async def delete_user(async_session: AsyncSession, user_id: int): response = await async_session.execute(delete(User).where(User.id == user_id)) await async_session.commit() - return response \ No newline at end of file + return response diff --git a/chapter10/short_url_pro/api/short.py b/chapter10/short_url_pro/api/short.py index 2f1d55d..541a8ef 100644 --- a/chapter10/short_url_pro/api/short.py +++ b/chapter10/short_url_pro/api/short.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends,BackgroundTasks +from fastapi import APIRouter, Depends, BackgroundTasks from fastapi.responses import RedirectResponse, PlainTextResponse from dependencies import get_db_session @@ -8,13 +8,21 @@ router_short = APIRouter(tags=["短链访问"]) -@router_short.get('/{short_tag}') -async def short_redirect(*,short_tag: str, db_session: AsyncSession = Depends(get_db_session),taks:BackgroundTasks): +@router_short.get("/{short_tag}") +async def short_redirect( + *, + short_tag: str, + db_session: AsyncSession = Depends(get_db_session), + taks: BackgroundTasks +): data = await ShortServeries.get_short_url(db_session, short_tag) if not data: return PlainTextResponse("没有对应短链信息记录") - data.visits_count=data.visits_count+1 - taks.add_task(ShortServeries.update_short_url,db_session,short_url_id=data.id,visits_count=data.visits_count) + data.visits_count = data.visits_count + 1 + taks.add_task( + ShortServeries.update_short_url, + db_session, + short_url_id=data.id, + visits_count=data.visits_count, + ) return RedirectResponse(url=data.long_url) - - diff --git a/chapter10/short_url_pro/api/user.py b/chapter10/short_url_pro/api/user.py index 9e89d11..eb0b4ce 100644 --- a/chapter10/short_url_pro/api/user.py +++ b/chapter10/short_url_pro/api/user.py @@ -18,13 +18,20 @@ @router_uesr.post("/oauth2/authorize", summary="请求授权URL地址") -async def login(user_data: OAuth2PasswordRequestForm = Depends(), db_session: AsyncSession = Depends(get_db_session)): +async def login( + user_data: OAuth2PasswordRequestForm = Depends(), + db_session: AsyncSession = Depends(get_db_session), +): if not user_data: raise HTTPException(status_code=400, detail="请输入用户账号及密码等信息") # 查询用户是否存在 userinfo = await UserServeries.get_user_by_name(db_session, user_data.username) if not userinfo: - raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="不存在此用户信息", headers={"WWW-Authenticate": "Basic"}) + raise HTTPException( + status_code=HTTP_401_UNAUTHORIZED, + detail="不存在此用户信息", + headers={"WWW-Authenticate": "Basic"}, + ) # 验证用户密码和哈希密码值是否保持一直 if not PasslibHelper.verity_password(user_data.password, userinfo.password): @@ -32,11 +39,11 @@ async def login(user_data: OAuth2PasswordRequestForm = Depends(), db_session: As # 签发JWT有效负载信息 data = { - 'iss ': userinfo.username, - 'sub': 'xiaozhongtongxue', - 'username': userinfo.username, - 'admin': True, - 'exp': datetime.utcnow() + timedelta(minutes=15) + "iss ": userinfo.username, + "sub": "xiaozhongtongxue", + "username": userinfo.username, + "admin": True, + "exp": datetime.utcnow() + timedelta(minutes=15), } # 生成Token token = AuthToeknHelper.token_encode(data=data) @@ -45,30 +52,36 @@ async def login(user_data: OAuth2PasswordRequestForm = Depends(), db_session: As @router_uesr.post("/creat/single/short", summary="创建单一短链请求") -async def creat_single(creatinfo: SingleShortUrlCreate, token: str = Depends(oauth2_scheme), - db_session: AsyncSession = Depends(get_db_session)): +async def creat_single( + creatinfo: SingleShortUrlCreate, + token: str = Depends(oauth2_scheme), + db_session: AsyncSession = Depends(get_db_session), +): payload = AuthToeknHelper.token_decode(token=token) # 定义认证异常信息 - username = payload.get('username') + username = payload.get("username") creatinfo.short_tag = generate_short_url() creatinfo.short_url = f"{creatinfo.short_url}{creatinfo.short_tag}" creatinfo.created_by = username - creatinfo.msg_context = f"{creatinfo.msg_context},了解详情请点击 {creatinfo.short_url} !" + creatinfo.msg_context = ( + f"{creatinfo.msg_context},了解详情请点击 {creatinfo.short_url} !" + ) result = await ShortServeries.create_short_url(db_session, **creatinfo.dict()) - return {"code": 200, "msg": "创建短链成功", "data": { - "short_url": result.short_url - }} + return {"code": 200, "msg": "创建短链成功", "data": {"short_url": result.short_url}} @router_uesr.post("/creat/batch/short", summary="通过上传文件方式,批量创建短链") -async def creat_batch(*, file: UploadFile = File(...), - token: str = Depends(oauth2_scheme), - db_session: AsyncSession = Depends(get_db_session)): +async def creat_batch( + *, + file: UploadFile = File(...), + token: str = Depends(oauth2_scheme), + db_session: AsyncSession = Depends(get_db_session), +): payload = AuthToeknHelper.token_decode(token=token) # 定义认证异常信息 - username = payload.get('username') + username = payload.get("username") contents = await file.read() - shorl_msg = contents.decode(encoding='utf-8').split("\n") + shorl_msg = contents.decode(encoding="utf-8").split("\n") def make_short_url(item): split_item = item.split("#") @@ -79,8 +92,10 @@ def make_short_url(item): short_tag=short_tag, short_url=short_url, created_by=username, - msg_context=f"{split_item[1].replace('chanename', split_item[0]).replace('url', 'short_url')}") - - result = await ShortServeries.create_batch_short_url(db_session, [make_short_url(item) for item in shorl_msg]) - return {"code": 200, "msg": "批量创建短链成功", "data":None} + msg_context=f"{split_item[1].replace('chanename', split_item[0]).replace('url', 'short_url')}", + ) + result = await ShortServeries.create_batch_short_url( + db_session, [make_short_url(item) for item in shorl_msg] + ) + return {"code": 200, "msg": "批量创建短链成功", "data": None} diff --git a/chapter10/short_url_pro/app.py b/chapter10/short_url_pro/app.py index 6af2742..4c61b5b 100644 --- a/chapter10/short_url_pro/app.py +++ b/chapter10/short_url_pro/app.py @@ -1,29 +1,37 @@ from fastapi import FastAPI from api.short import router_short from api.user import router_uesr -app = FastAPI(title='fastapi集成短链实战案例') + +app = FastAPI(title="fastapi集成短链实战案例") + @app.on_event("startup") async def startup_event(): pass from db.database import async_engine, Base - from models.model import User,ShortUrl + from models.model import User, ShortUrl + async def init_create_table(): async with async_engine.begin() as conn: # await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.create_all) + await init_create_table() + @app.on_event("shutdown") async def shutdown_event(): pass + from api.short import router_short from api.user import router_uesr + app.include_router(router_short) app.include_router(router_uesr) -print('启动!') -if __name__ == '__main__': +print("启动!") +if __name__ == "__main__": import uvicorn - uvicorn.run(app='app:app', host="127.0.0.1", port=8000, reload=True) \ No newline at end of file + + uvicorn.run(app="app:app", host="127.0.0.1", port=8000, reload=True) diff --git a/chapter10/short_url_pro/config/config.py b/chapter10/short_url_pro/config/config.py index c894158..bf3fda3 100644 --- a/chapter10/short_url_pro/config/config.py +++ b/chapter10/short_url_pro/config/config.py @@ -1,11 +1,13 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 定义连接异步引擎数据库的URL地址 ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///short.db" # 定义TOEKN的签名信息值 - TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' + TOKEN_SIGN_SECRET: str = "ZcjT6Rcp1yIFQoS7" + @lru_cache() def get_settings(): diff --git a/chapter10/short_url_pro/db/database.py b/chapter10/short_url_pro/db/database.py index 34968dd..e84b19e 100644 --- a/chapter10/short_url_pro/db/database.py +++ b/chapter10/short_url_pro/db/database.py @@ -1,11 +1,15 @@ # 导入异步引擎的模块 from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import declarative_base, sessionmaker + # URL地址格式 from config.config import get_settings + # 创建异步引擎对象 async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) # 创建ORM模型基类 Base = declarative_base() # 创建异步的会话管理对象 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) \ No newline at end of file +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) diff --git a/chapter10/short_url_pro/dependencies/__init__.py b/chapter10/short_url_pro/dependencies/__init__.py index 2acf671..9dd082c 100644 --- a/chapter10/short_url_pro/dependencies/__init__.py +++ b/chapter10/short_url_pro/dependencies/__init__.py @@ -3,6 +3,7 @@ from typing import AsyncGenerator from db.database import SessionLocal + async def get_db_session() -> AsyncGenerator[AsyncSession, None]: db_session = None try: @@ -11,7 +12,10 @@ async def get_db_session() -> AsyncGenerator[AsyncSession, None]: finally: await db_session.close() + from contextlib import asynccontextmanager + + @asynccontextmanager async def get_db_session_asynccont() -> AsyncGenerator: async_session = SessionLocal() @@ -22,4 +26,4 @@ async def get_db_session_asynccont() -> AsyncGenerator: await async_session.rollback() raise ex finally: - await async_session.close() \ No newline at end of file + await async_session.close() diff --git a/chapter10/short_url_pro/main.py b/chapter10/short_url_pro/main.py index d3d6e4e..e6cb23a 100644 --- a/chapter10/short_url_pro/main.py +++ b/chapter10/short_url_pro/main.py @@ -1,5 +1,6 @@ from app import app -if __name__ == '__main__': + +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=8000) \ No newline at end of file + uvicorn.run(app="main:app", host="127.0.0.1", port=8000) diff --git a/chapter10/short_url_pro/models/model.py b/chapter10/short_url_pro/models/model.py index 1c66dda..951c48c 100644 --- a/chapter10/short_url_pro/models/model.py +++ b/chapter10/short_url_pro/models/model.py @@ -1,9 +1,10 @@ from db.database import Base -from sqlalchemy import Column, String, DateTime, func,Integer#Integer +from sqlalchemy import Column, String, DateTime, func, Integer # Integer + class User(Base): # 指定本类映射到users表 - __tablename__ = 'user' + __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) # 用户姓名 username = Column(String(20)) @@ -12,21 +13,22 @@ class User(Base): # 用户创建时间 created_at = Column(DateTime(), default=func.now()) + class ShortUrl(Base): # 指定本类映射到users表 - __tablename__ = 'short_url' + __tablename__ = "short_url" id = Column(Integer, primary_key=True, autoincrement=True) # 短链标签 - short_tag = Column(String(20),nullable=False) + short_tag = Column(String(20), nullable=False) # 短连接地址 short_url = Column(String(20)) # 长链接地址 long_url = Column(String, nullable=False) # 访问次数 - visits_count= Column(Integer, nullable=True) + visits_count = Column(Integer, nullable=True) # 短链创建时间 created_at = Column(DateTime(), default=func.now()) # 短链创建时间 created_by = Column(String(20)) # 短信内容 - msg_context = Column(String, nullable=False) \ No newline at end of file + msg_context = Column(String, nullable=False) diff --git a/chapter10/short_url_pro/schemas/__init__.py b/chapter10/short_url_pro/schemas/__init__.py index 26071d4..4aefae7 100644 --- a/chapter10/short_url_pro/schemas/__init__.py +++ b/chapter10/short_url_pro/schemas/__init__.py @@ -1,19 +1,20 @@ from pydantic import BaseModel + class SingleShortUrlCreate(BaseModel): """ 创建新短链记录时候需要传递参数信息 """ + # 需要生成长链接地址 - long_url:str + long_url: str # 群发短信内容 - msg_context:str + msg_context: str # 短连接生成前缀 - short_url:str = "http://127.0.0.1:8000/" + short_url: str = "http://127.0.0.1:8000/" # 访问次数-默认值是0 - visits_count:int = 0 + visits_count: int = 0 # 短链标签-默认可以不传 - short_tag:str = "" + short_tag: str = "" # 默认不传-通常后端进行生成处理 created_by = "" - diff --git a/chapter10/short_url_pro/servies/short.py b/chapter10/short_url_pro/servies/short.py index 1756701..8c700b5 100644 --- a/chapter10/short_url_pro/servies/short.py +++ b/chapter10/short_url_pro/servies/short.py @@ -5,6 +5,7 @@ from typing import List from schemas import SingleShortUrlCreate + class ShortServeries: @staticmethod @@ -14,8 +15,10 @@ async def init_create_table(): await conn.run_sync(Base.metadata.create_all) @staticmethod - async def get_short_url(async_session: AsyncSession, short_tag: str)->ShortUrl: - result = await async_session.execute(select(ShortUrl).where(ShortUrl.short_tag == short_tag)) + async def get_short_url(async_session: AsyncSession, short_tag: str) -> ShortUrl: + result = await async_session.execute( + select(ShortUrl).where(ShortUrl.short_tag == short_tag) + ) return result.scalars().first() @staticmethod @@ -26,7 +29,9 @@ async def create_short_url(async_session: AsyncSession, **kwargs): return new_short_url @staticmethod - async def update_short_url(async_session: AsyncSession, short_url_id: int, **kwargs): + async def update_short_url( + async_session: AsyncSession, short_url_id: int, **kwargs + ): response = update(ShortUrl).where(ShortUrl.id == short_url_id) result = await async_session.execute(response.values(**kwargs)) await async_session.commit() @@ -34,14 +39,17 @@ async def update_short_url(async_session: AsyncSession, short_url_id: int, **kwa @staticmethod async def delete_short_url(async_session: AsyncSession, short_url_id: int): - response = await async_session.execute(delete(ShortUrl).where(ShortUrl.id == short_url_id)) + response = await async_session.execute( + delete(ShortUrl).where(ShortUrl.id == short_url_id) + ) await async_session.commit() return response - @staticmethod - async def create_batch_short_url(async_session: AsyncSession, short_urls:List[SingleShortUrlCreate]): - short_urls= [ShortUrl(**item.dict()) for item in short_urls] + async def create_batch_short_url( + async_session: AsyncSession, short_urls: List[SingleShortUrlCreate] + ): + short_urls = [ShortUrl(**item.dict()) for item in short_urls] async_session.add_all(short_urls) await async_session.commit() - return short_urls \ No newline at end of file + return short_urls diff --git a/chapter10/short_url_pro/servies/user.py b/chapter10/short_url_pro/servies/user.py index d519dcf..c668608 100644 --- a/chapter10/short_url_pro/servies/user.py +++ b/chapter10/short_url_pro/servies/user.py @@ -1,4 +1,4 @@ -from sqlalchemy import select, update, delete,func +from sqlalchemy import select, update, delete, func from sqlalchemy.ext.asyncio import AsyncSession from models.model import User @@ -21,7 +21,9 @@ async def get_user(async_session: AsyncSession, user_id: int): @staticmethod async def get_user_by_name(async_session: AsyncSession, username: str) -> User: - result = await async_session.execute(select(User).where(User.username == username)) + result = await async_session.execute( + select(User).where(User.username == username) + ) return result.scalars().first() @staticmethod @@ -50,15 +52,19 @@ async def delete_user(async_session: AsyncSession, user_id: int): return response -if __name__ == '__main__': +if __name__ == "__main__": import asyncio print(PasslibHelper.hash_password("123456")) from dependencies import get_db_session_asynccont + async def create_admin_user(): async with get_db_session_asynccont() as async_session: - await UserServeries.create_user(async_session, username="admin", - password=(PasslibHelper.hash_password("123456")), - created_at=func.now() - ) + await UserServeries.create_user( + async_session, + username="admin", + password=(PasslibHelper.hash_password("123456")), + created_at=func.now(), + ) + asyncio.run(create_admin_user()) diff --git a/chapter10/short_url_pro/utils/auth_helper.py b/chapter10/short_url_pro/utils/auth_helper.py index cb1efab..5c377d9 100644 --- a/chapter10/short_url_pro/utils/auth_helper.py +++ b/chapter10/short_url_pro/utils/auth_helper.py @@ -1,5 +1,4 @@ - -from fastapi import HTTPException,status +from fastapi import HTTPException, status from jose import JWTError, jwt from pydantic import BaseModel, ValidationError from jose import jwt @@ -8,7 +7,6 @@ ALGORITHM = "HS256" - class AuthToeknHelper: @staticmethod @@ -30,6 +28,7 @@ def token_decode(token): raise credentials_exception return payload -if __name__ == '__main__': - print(AuthToeknHelper.token_encode({"user":"XZSD"})) - print(AuthToeknHelper.token_decode(AuthToeknHelper.token_encode({"user":"XZSD"}))) \ No newline at end of file + +if __name__ == "__main__": + print(AuthToeknHelper.token_encode({"user": "XZSD"})) + print(AuthToeknHelper.token_decode(AuthToeknHelper.token_encode({"user": "XZSD"}))) diff --git a/chapter10/short_url_pro/utils/passlib_hepler.py b/chapter10/short_url_pro/utils/passlib_hepler.py index 852dd4e..3081736 100644 --- a/chapter10/short_url_pro/utils/passlib_hepler.py +++ b/chapter10/short_url_pro/utils/passlib_hepler.py @@ -17,5 +17,6 @@ def verity_password(plain_password: str, hashed_password: str): def hash_password(password: str) -> str: return pwd_context.hash(password) -if __name__ == '__main__': - print(PasslibHelper.hash_password("123456")) \ No newline at end of file + +if __name__ == "__main__": + print(PasslibHelper.hash_password("123456")) diff --git a/chapter10/short_url_pro/utils/random_helper.py b/chapter10/short_url_pro/utils/random_helper.py index d57a7ac..3d005ee 100644 --- a/chapter10/short_url_pro/utils/random_helper.py +++ b/chapter10/short_url_pro/utils/random_helper.py @@ -2,8 +2,7 @@ import random - def generate_short_url(size=7) -> str: letters = string.ascii_letters + string.digits - short_tag = ''.join(random.choice(letters) for i in range(size)) - return short_tag \ No newline at end of file + short_tag = "".join(random.choice(letters) for i in range(size)) + return short_tag diff --git a/chapter11/distributed_websocket/api/room.py b/chapter11/distributed_websocket/api/room.py index e9a157d..7bd821c 100644 --- a/chapter11/distributed_websocket/api/room.py +++ b/chapter11/distributed_websocket/api/room.py @@ -9,7 +9,7 @@ from utils.room_connection_helper_distributed import RoomConnectionManager from faker import Faker -fake = Faker(locale='zh_CN') +fake = Faker(locale="zh_CN") router_char = APIRouter(tags=["聊天室"]) @@ -28,11 +28,10 @@ def __init__(self, *args, **kwargs): # 用户登入授权的token self.curr_user: Optional[UserDistribute] = None - - async def curr_user_login_init(self, websocket:WebSocket): + async def curr_user_login_init(self, websocket: WebSocket): # 当前房间对象 - token = websocket.query_params.get('token') + token = websocket.query_params.get("token") if not token: # 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, @@ -42,13 +41,17 @@ async def curr_user_login_init(self, websocket:WebSocket): AuthToeknHelper.token_decode(token) payload = AuthToeknHelper.token_decode(token=token) # 解析token信息 - phone_number = payload.get('phone_number') - username = payload.get('username') + phone_number = payload.get("phone_number") + username = payload.get("username") # 初始化当前连接用户信息 - self.curr_user = UserDistribute(phone_number=phone_number, username=username) + self.curr_user = UserDistribute( + phone_number=phone_number, username=username + ) except: pass - await self.close_clean_user_websocket(code=status.WS_1000_NORMAL_CLOSURE,websocket=websocket) + await self.close_clean_user_websocket( + code=status.WS_1000_NORMAL_CLOSURE, websocket=websocket + ) if self.room.check_user_logic(self.curr_user): # 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, @@ -62,7 +65,7 @@ async def check_user_in_logic(self): async def on_connect(self, _websocket): # 初始化当前连接到服务端的用户信息 - self.room =_websocket.app.state.room_connection + self.room = _websocket.app.state.room_connection # 确认链接 await _websocket.accept() # 初始化当前用户信息 @@ -70,12 +73,12 @@ async def on_connect(self, _websocket): # 把用户加入到当前用户列表中, self.room.user_add_login_room(self.curr_user) # 把客户端连接添加到列表中 - self.room.websocket_add_login_room(self.curr_user,_websocket) + self.room.websocket_add_login_room(self.curr_user, _websocket) # 添加连接 # 广播用户加入聊天室的消息 await self.room.pubsub_room_user_login(self.curr_user) - async def close_clean_user_websocket(self,code,websocket): + async def close_clean_user_websocket(self, code, websocket): # 资源释放处理 await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA) if self.room: @@ -96,19 +99,21 @@ async def on_receive(self, _websocket: WebSocket, msg: str): if self.curr_user is None: # 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, # await _websocket.close(code=status.WS_1008_POLICY_VIOLATION) - await self.close_clean_user_websocket(code=status.WS_1008_POLICY_VIOLATION,websocket=_websocket) - + await self.close_clean_user_websocket( + code=status.WS_1008_POLICY_VIOLATION, websocket=_websocket + ) if not isinstance(msg, str): # 由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据). # await _websocket.close(code=status.WS_1003_UNSUPPORTED_DATA) - await self.close_clean_user_websocket(code=status.WS_1003_UNSUPPORTED_DATA, websocket=_websocket) + await self.close_clean_user_websocket( + code=status.WS_1003_UNSUPPORTED_DATA, websocket=_websocket + ) # 广播消息 - await self.room.pubsub_user_send_message(self.curr_user,message=msg) + await self.room.pubsub_user_send_message(self.curr_user, message=msg) # await self.room.broadcast_user_send_message(self.curr_user, msg) - async def on_disconnect(self, _websocket: WebSocket, _close_code: int): pass # 要及时删除已关闭的连接 @@ -118,11 +123,9 @@ async def on_disconnect(self, _websocket: WebSocket, _close_code: int): await self.room.pubsub_room_user_logout(self.curr_user, message=None) - # # 广播某用户退出房间的消息 # await self.room.broadcast_room_user_logout(self.curr_user) # # 更新在线用户列表信息 # await self.room.broadcast_system_room_update_userlist() # 删除引用 del self.curr_user - diff --git a/chapter11/distributed_websocket/api/user.py b/chapter11/distributed_websocket/api/user.py index 808ab35..22b25b8 100644 --- a/chapter11/distributed_websocket/api/user.py +++ b/chapter11/distributed_websocket/api/user.py @@ -19,7 +19,10 @@ async def index(): @router_uesr.get("/register_action") -async def register(user: RegisterAaction = Depends(), db_session: AsyncSession = Depends(get_db_session)): +async def register( + user: RegisterAaction = Depends(), + db_session: AsyncSession = Depends(get_db_session), +): # 判断是否已经注册 result = await UserServeries.get_user_by_phone_number(db_session, user.phone_number) if not result: @@ -36,22 +39,27 @@ async def login(): @router_uesr.get("/login_action") -async def login_action(user: LoginAaction = Depends(), db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.check_user_phone_number_and_password(db_session, password=user.password, - phone_number=user.phone_number) +async def login_action( + user: LoginAaction = Depends(), db_session: AsyncSession = Depends(get_db_session) +): + result = await UserServeries.check_user_phone_number_and_password( + db_session, password=user.password, phone_number=user.phone_number + ) if result: # 生成一个TOKEN值,签发JWT有效负载信息 data = { - 'iss ': user.phone_number, - 'sub': 'xiaozhongtongxue', - 'phone_number': user.phone_number, - 'username': result.username, + "iss ": user.phone_number, + "sub": "xiaozhongtongxue", + "phone_number": user.phone_number, + "username": result.username, # 设置token的哟有效期 - 'exp': datetime.utcnow() + timedelta(days=2) + "exp": datetime.utcnow() + timedelta(days=2), } # 生成Token token = AuthToeknHelper.token_encode(data=data) # 登入成功,跳转到聊天室中 - return RedirectResponse(f"http://127.0.0.1:8000/api/v1/room/online?token={token}") + return RedirectResponse( + f"http://127.0.0.1:8000/api/v1/room/online?token={token}" + ) else: return PlainTextResponse("用户没注册过了!或密码错误,请重新输入账号信息!") diff --git a/chapter11/distributed_websocket/app.py b/chapter11/distributed_websocket/app.py index 8e554c5..9a490e0 100644 --- a/chapter11/distributed_websocket/app.py +++ b/chapter11/distributed_websocket/app.py @@ -14,6 +14,7 @@ async def startup_event(): pass from db.database import async_engine, Base + async def init_create_table(): async with async_engine.begin() as conn: # await conn.run_sync(Base.metadata.drop_all) @@ -27,8 +28,6 @@ async def init_create_table(): # 开始订阅相关的频道消息 await app.state.room_connection.do_listacton() - - @app.on_event("shutdown") async def shutdown_event(): @@ -41,7 +40,5 @@ async def shutdown_event(): app.include_router(room.router_char) - - def creat_app(): return app diff --git a/chapter11/distributed_websocket/config/config.py b/chapter11/distributed_websocket/config/config.py index 610c190..0d80293 100644 --- a/chapter11/distributed_websocket/config/config.py +++ b/chapter11/distributed_websocket/config/config.py @@ -1,11 +1,13 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 定义连接异步引擎数据库的URL地址 ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///chat.db" # 定义TOEKN的签名信息值 - TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' + TOKEN_SIGN_SECRET: str = "ZcjT6Rcp1yIFQoS7" + @lru_cache() def get_settings(): diff --git a/chapter11/distributed_websocket/db/database.py b/chapter11/distributed_websocket/db/database.py index 34968dd..e84b19e 100644 --- a/chapter11/distributed_websocket/db/database.py +++ b/chapter11/distributed_websocket/db/database.py @@ -1,11 +1,15 @@ # 导入异步引擎的模块 from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import declarative_base, sessionmaker + # URL地址格式 from config.config import get_settings + # 创建异步引擎对象 async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) # 创建ORM模型基类 Base = declarative_base() # 创建异步的会话管理对象 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) \ No newline at end of file +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) diff --git a/chapter11/distributed_websocket/dependencies/__init__.py b/chapter11/distributed_websocket/dependencies/__init__.py index 3491f5d..bb06624 100644 --- a/chapter11/distributed_websocket/dependencies/__init__.py +++ b/chapter11/distributed_websocket/dependencies/__init__.py @@ -2,10 +2,11 @@ from typing import AsyncGenerator from db.database import SessionLocal + async def get_db_session() -> AsyncGenerator[AsyncSession, None]: db_session = None try: db_session = SessionLocal() yield db_session finally: - await db_session.close() \ No newline at end of file + await db_session.close() diff --git a/chapter11/distributed_websocket/main.py b/chapter11/distributed_websocket/main.py index fcfdf4d..465994b 100644 --- a/chapter11/distributed_websocket/main.py +++ b/chapter11/distributed_websocket/main.py @@ -1,6 +1,7 @@ - from app import creat_app -app =creat_app() -if __name__ == '__main__': + +app = creat_app() +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) + + uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True) diff --git a/chapter11/distributed_websocket/models/model.py b/chapter11/distributed_websocket/models/model.py index 6ec8be0..2a77272 100644 --- a/chapter11/distributed_websocket/models/model.py +++ b/chapter11/distributed_websocket/models/model.py @@ -1,9 +1,10 @@ from db.database import Base -from sqlalchemy import Column, String, DateTime, func,Integer#Integer +from sqlalchemy import Column, String, DateTime, func, Integer # Integer + class User(Base): # 指定本类映射到users表 - __tablename__ = 'user' + __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) # 用户号码 phone_number = Column(String(20)) @@ -13,5 +14,3 @@ class User(Base): password = Column(String(32)) # 用户创建时间 created_at = Column(DateTime(), default=func.now()) - - diff --git a/chapter11/distributed_websocket/schemas/__init__.py b/chapter11/distributed_websocket/schemas/__init__.py index 2b5cf2b..e1578fe 100644 --- a/chapter11/distributed_websocket/schemas/__init__.py +++ b/chapter11/distributed_websocket/schemas/__init__.py @@ -2,11 +2,12 @@ from pydantic import BaseModel from starlette.websockets import WebSocket + @dataclass class User: phone_number: str username: str - websocket:WebSocket + websocket: WebSocket class RegisterAaction(BaseModel): @@ -14,17 +15,18 @@ class RegisterAaction(BaseModel): username: str password: str + class LoginAaction(BaseModel): phone_number: str password: str - @dataclass -class UserDistribute : +class UserDistribute: phone_number: str username: str + @dataclass -class WebSocketDistribute : - websocket:WebSocket +class WebSocketDistribute: + websocket: WebSocket diff --git a/chapter11/distributed_websocket/servies/user.py b/chapter11/distributed_websocket/servies/user.py index b2483ac..2fa28b3 100644 --- a/chapter11/distributed_websocket/servies/user.py +++ b/chapter11/distributed_websocket/servies/user.py @@ -18,15 +18,23 @@ async def get_user(async_session: AsyncSession, user_id: int): return result.scalars().first() @staticmethod - async def get_user_by_phone_number(async_session: AsyncSession, phone_number: str) -> User: - result = await async_session.execute(select(User).where(User.phone_number == phone_number)) + async def get_user_by_phone_number( + async_session: AsyncSession, phone_number: str + ) -> User: + result = await async_session.execute( + select(User).where(User.phone_number == phone_number) + ) return result.scalars().first() @staticmethod - async def check_user_phone_number_and_password(async_session: AsyncSession, password: str, - phone_number: str) -> User: + async def check_user_phone_number_and_password( + async_session: AsyncSession, password: str, phone_number: str + ) -> User: result = await async_session.execute( - select(User).where(User.phone_number == phone_number, User.password == password)) + select(User).where( + User.phone_number == phone_number, User.password == password + ) + ) return result.scalars().first() @staticmethod diff --git a/chapter11/distributed_websocket/utils/auth_helper.py b/chapter11/distributed_websocket/utils/auth_helper.py index 9b753e8..174792e 100644 --- a/chapter11/distributed_websocket/utils/auth_helper.py +++ b/chapter11/distributed_websocket/utils/auth_helper.py @@ -1,5 +1,4 @@ - -from fastapi import HTTPException,status +from fastapi import HTTPException, status from jose import JWTError, jwt from pydantic import BaseModel, ValidationError from jose import jwt @@ -8,7 +7,6 @@ ALGORITHM = "HS256" - class AuthToeknHelper: @staticmethod diff --git a/chapter11/distributed_websocket/utils/passlib_hepler.py b/chapter11/distributed_websocket/utils/passlib_hepler.py index 852dd4e..3081736 100644 --- a/chapter11/distributed_websocket/utils/passlib_hepler.py +++ b/chapter11/distributed_websocket/utils/passlib_hepler.py @@ -17,5 +17,6 @@ def verity_password(plain_password: str, hashed_password: str): def hash_password(password: str) -> str: return pwd_context.hash(password) -if __name__ == '__main__': - print(PasslibHelper.hash_password("123456")) \ No newline at end of file + +if __name__ == "__main__": + print(PasslibHelper.hash_password("123456")) diff --git a/chapter11/distributed_websocket/utils/random_helper.py b/chapter11/distributed_websocket/utils/random_helper.py index d57a7ac..3d005ee 100644 --- a/chapter11/distributed_websocket/utils/random_helper.py +++ b/chapter11/distributed_websocket/utils/random_helper.py @@ -2,8 +2,7 @@ import random - def generate_short_url(size=7) -> str: letters = string.ascii_letters + string.digits - short_tag = ''.join(random.choice(letters) for i in range(size)) - return short_tag \ No newline at end of file + short_tag = "".join(random.choice(letters) for i in range(size)) + return short_tag diff --git a/chapter11/distributed_websocket/utils/room_connection_helper.py b/chapter11/distributed_websocket/utils/room_connection_helper.py index 6a1cc86..06faced 100644 --- a/chapter11/distributed_websocket/utils/room_connection_helper.py +++ b/chapter11/distributed_websocket/utils/room_connection_helper.py @@ -7,7 +7,7 @@ import datetime from faker import Faker -fake = Faker(locale='zh_CN') +fake = Faker(locale="zh_CN") class RoomConnectionManager: @@ -33,25 +33,45 @@ def check_user_logic(self, userlogin: User): async def broadcast_system_room_update_userlist(self): # 循环调用用户里面的连接对象发送广播 - user_online_list = [f"{user.username}({user.phone_number})" for userid, user in self._users_socket.items()] + user_online_list = [ + f"{user.username}({user.phone_number})" + for userid, user in self._users_socket.items() + ] for userid, user in self._users_socket.items(): await user.websocket.send_json( - {"type": "system_room_update_userlist", "data": {'users_list': user_online_list}}) + { + "type": "system_room_update_userlist", + "data": {"users_list": user_online_list}, + } + ) async def broadcast_room_user_login(self, curr_user: User): # 循环调用用户里面的连接对象发送广播 for userid, user in self._users_socket.items(): # 广播当前登入的用户的信息 await user.websocket.send_json( - {"type": "system_msg_user_login", - "data": {'phone_number': self._users_socket[curr_user.phone_number].phone_number, - 'username': self._users_socket[curr_user.phone_number].username}}) + { + "type": "system_msg_user_login", + "data": { + "phone_number": self._users_socket[ + curr_user.phone_number + ].phone_number, + "username": self._users_socket[curr_user.phone_number].username, + }, + } + ) async def broadcast_room_user_logout(self, leave_user): for userid, user in self._users_socket.items(): - await user.websocket.send_json({"type": "system_msg_user_logout", - "data": {'phone_number': leave_user.phone_number, - 'username': leave_user.username}}) + await user.websocket.send_json( + { + "type": "system_msg_user_logout", + "data": { + "phone_number": leave_user.phone_number, + "username": leave_user.username, + }, + } + ) async def broadcast_user_send_message(self, leave_user: User, msg: str): for userid, user in self._users_socket.items(): @@ -61,6 +81,15 @@ async def broadcast_user_send_message(self, leave_user: User, msg: str): else: sendmsg = f"{leave_user.username}说:{msg}" await user.websocket.send_json( - {"type": "user_send_msg", - "data": {'phone_number': leave_user.phone_number, 'username': leave_user.username, "msg": sendmsg, - "datetime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}}) + { + "type": "user_send_msg", + "data": { + "phone_number": leave_user.phone_number, + "username": leave_user.username, + "msg": sendmsg, + "datetime": datetime.datetime.now().strftime( + "%Y-%m-%d %H:%M:%S" + ), + }, + } + ) diff --git a/chapter11/distributed_websocket/utils/room_connection_helper_distributed.py b/chapter11/distributed_websocket/utils/room_connection_helper_distributed.py index c516b4e..3a385ec 100644 --- a/chapter11/distributed_websocket/utils/room_connection_helper_distributed.py +++ b/chapter11/distributed_websocket/utils/room_connection_helper_distributed.py @@ -6,6 +6,7 @@ import async_timeout import asyncio import datetime + # from faker import Faker from typing import List from fastapi import WebSocket @@ -38,52 +39,65 @@ def __init__(self): async def register_pubsub(self): # 监听频道消息 if not self.redis: - self.redis: Redis = aioredis.from_url("redis://localhost", encoding="utf-8", decode_responses=True) + self.redis: Redis = aioredis.from_url( + "redis://localhost", encoding="utf-8", decode_responses=True + ) # 返回发布/订阅对象,使用pubsub才可以订阅频道并收听发布到的消息 self.pubsub = self.redis.pubsub() async def do_listacton(self): - await self.pubsub.subscribe("chat:system_room_update_userlist", - "chat:system_msg_user_login", - "chat:system_msg_user_logout", - "chat:user_send_msg" - ) + await self.pubsub.subscribe( + "chat:system_room_update_userlist", + "chat:system_msg_user_login", + "chat:system_msg_user_logout", + "chat:user_send_msg", + ) async def reader(channel: aioredis.client.PubSub): while True: try: async with async_timeout.timeout(1): - message = await channel.get_message(ignore_subscribe_messages=True) + message = await channel.get_message( + ignore_subscribe_messages=True + ) if message is not None: pass - message_event: MessageEvent = MessageEvent.parse_raw(message["data"]) + message_event: MessageEvent = MessageEvent.parse_raw( + message["data"] + ) # 判断消息频道=====根据不同的频道 - if message_event.channel == 'chat:system_msg_user_login': + if message_event.channel == "chat:system_msg_user_login": # 广播用户在线列表信息 await self.broadcast_system_room_update_userlist() # 广播有用加入信息UserDistribute - await self.broadcast_room_user_login(curr_user=message_event.user) - if message_event.channel == 'chat:system_msg_user_logout': + await self.broadcast_room_user_login( + curr_user=message_event.user + ) + if message_event.channel == "chat:system_msg_user_logout": pass # await self.broadcast_user_send_message(self.curr_user, msg) # # 更新在线用户列表信息 # # 广播某用户退出房间的消息 - await self.broadcast_room_user_logout(leave_user=message_event.user) + await self.broadcast_room_user_logout( + leave_user=message_event.user + ) await self.broadcast_system_room_update_userlist() - if message_event.channel == 'chat:user_send_msg': + if message_event.channel == "chat:user_send_msg": pass - await self.broadcast_user_send_message(curr_user=message_event.user,msg=message_event.message) + await self.broadcast_user_send_message( + curr_user=message_event.user, + msg=message_event.message, + ) await asyncio.sleep(0.01) except asyncio.TimeoutError: pass - # await asyncio.create_task(reader(self.pubsub)) asyncio.create_task(reader(self.pubsub)) @@ -123,50 +137,83 @@ def check_user_logic(self, userlogin: UserDistribute): # # 发布消息新增用户进入房间的消息 # await self.redis.publish("chat:system_room_update_userlist", enevt.json()) - async def pubsub_room_user_login(self, user: UserDistribute, channel: str = "chat:system_msg_user_login"): + async def pubsub_room_user_login( + self, user: UserDistribute, channel: str = "chat:system_msg_user_login" + ): pass if self.redis: - enevt = MessageEvent(user=user, channel=channel,message=None) + enevt = MessageEvent(user=user, channel=channel, message=None) # print("消息了吗?", enevt) # 发布消息新增用户进入房间的消息 await self.redis.publish(channel=channel, message=enevt.json()) - async def pubsub_room_user_logout(self, user: UserDistribute, channel: str="chat:system_msg_user_logout",message:str=None): + async def pubsub_room_user_logout( + self, + user: UserDistribute, + channel: str = "chat:system_msg_user_logout", + message: str = None, + ): pass if self.redis: - enevt = MessageEvent(user=user, channel=channel,message=message) + enevt = MessageEvent(user=user, channel=channel, message=message) # 发布消息新增用户进入房间的消息 await self.redis.publish(channel=channel, message=enevt.json()) - async def pubsub_user_send_message(self, user: UserDistribute, channel: str="chat:user_send_msg",message:str=None): + async def pubsub_user_send_message( + self, + user: UserDistribute, + channel: str = "chat:user_send_msg", + message: str = None, + ): if self.redis: - enevt = MessageEvent(user=user, channel="chat:user_send_msg",message=message) + enevt = MessageEvent( + user=user, channel="chat:user_send_msg", message=message + ) # 发布消息新增用户进入房间的消息 await self.redis.publish(channel=channel, message=enevt.json()) async def broadcast_system_room_update_userlist(self): # 循环调用用户里面的连接对象发送广播 - user_online_list = [f"{user.username}({user.phone_number})" for userid, user in self._users_socket.items()] + user_online_list = [ + f"{user.username}({user.phone_number})" + for userid, user in self._users_socket.items() + ] # for key,websocket in self.active_connections.items(): for websocket in self.active_connections: await websocket.send_json( - {"type": "system_room_update_userlist", - "data": {'users_list': user_online_list}}) + { + "type": "system_room_update_userlist", + "data": {"users_list": user_online_list}, + } + ) async def broadcast_room_user_login(self, curr_user: UserDistribute): # 循环调用用户里面的连接对象发送广播 for websocket in self.active_connections: # 广播当前登入的用户的信息 await websocket.send_json( - {"type": "system_msg_user_login", - "data": {'phone_number': self._users_socket[curr_user.phone_number].phone_number, - 'username': self._users_socket[curr_user.phone_number].username}}) + { + "type": "system_msg_user_login", + "data": { + "phone_number": self._users_socket[ + curr_user.phone_number + ].phone_number, + "username": self._users_socket[curr_user.phone_number].username, + }, + } + ) async def broadcast_room_user_logout(self, leave_user): for websocket in self.active_connections: await websocket.send_json( - {"type": "system_msg_user_logout", "data": {'phone_number': leave_user.phone_number, - 'username': leave_user.username}}) + { + "type": "system_msg_user_logout", + "data": { + "phone_number": leave_user.phone_number, + "username": leave_user.username, + }, + } + ) async def broadcast_user_send_message(self, curr_user: UserDistribute, msg: str): # 提取是否属于我自己的发言信息 @@ -174,6 +221,15 @@ async def broadcast_user_send_message(self, curr_user: UserDistribute, msg: str) # 判断处理是否我自己发出的消息 sendmsg = f"{curr_user.username}说:{msg}" await websocket.send_json( - {"type": "user_send_msg", "data": {'phone_number': curr_user.phone_number, - 'username': curr_user.username, "msg": sendmsg, - "datetime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}}) + { + "type": "user_send_msg", + "data": { + "phone_number": curr_user.phone_number, + "username": curr_user.username, + "msg": sendmsg, + "datetime": datetime.datetime.now().strftime( + "%Y-%m-%d %H:%M:%S" + ), + }, + } + ) diff --git a/chapter11/websocket/api/room.py b/chapter11/websocket/api/room.py index f872e5a..9343ce7 100644 --- a/chapter11/websocket/api/room.py +++ b/chapter11/websocket/api/room.py @@ -13,12 +13,13 @@ from utils.room_connection_helper import RoomConnectionManager -fake = Faker(locale='zh_CN') +fake = Faker(locale="zh_CN") router_char = APIRouter(tags=["聊天室"]) # 实例化房间连接管理类 room = RoomConnectionManager() + @router_char.get("/api/v1/room/online") def index(): return FileResponse("templates/room.html") @@ -36,7 +37,7 @@ def __init__(self, *args, **kwargs): async def curr_user_login_init(self, websocket): - token = websocket.query_params.get('token') + token = websocket.query_params.get("token") if not token: # 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, await websocket.close(code=status.WS_1008_POLICY_VIOLATION) @@ -44,10 +45,12 @@ async def curr_user_login_init(self, websocket): if not self.curr_user and token: payload = AuthToeknHelper.token_decode(token=token) # 解析token信息 - phone_number = payload.get('phone_number') - username = payload.get('username') + phone_number = payload.get("phone_number") + username = payload.get("username") # 初始化当前连接用户信息 - self.curr_user = User(phone_number=phone_number, username=username, websocket=websocket) + self.curr_user = User( + phone_number=phone_number, username=username, websocket=websocket + ) if room.check_user_logic(self.curr_user): # 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, diff --git a/chapter11/websocket/api/user.py b/chapter11/websocket/api/user.py index 808ab35..22b25b8 100644 --- a/chapter11/websocket/api/user.py +++ b/chapter11/websocket/api/user.py @@ -19,7 +19,10 @@ async def index(): @router_uesr.get("/register_action") -async def register(user: RegisterAaction = Depends(), db_session: AsyncSession = Depends(get_db_session)): +async def register( + user: RegisterAaction = Depends(), + db_session: AsyncSession = Depends(get_db_session), +): # 判断是否已经注册 result = await UserServeries.get_user_by_phone_number(db_session, user.phone_number) if not result: @@ -36,22 +39,27 @@ async def login(): @router_uesr.get("/login_action") -async def login_action(user: LoginAaction = Depends(), db_session: AsyncSession = Depends(get_db_session)): - result = await UserServeries.check_user_phone_number_and_password(db_session, password=user.password, - phone_number=user.phone_number) +async def login_action( + user: LoginAaction = Depends(), db_session: AsyncSession = Depends(get_db_session) +): + result = await UserServeries.check_user_phone_number_and_password( + db_session, password=user.password, phone_number=user.phone_number + ) if result: # 生成一个TOKEN值,签发JWT有效负载信息 data = { - 'iss ': user.phone_number, - 'sub': 'xiaozhongtongxue', - 'phone_number': user.phone_number, - 'username': result.username, + "iss ": user.phone_number, + "sub": "xiaozhongtongxue", + "phone_number": user.phone_number, + "username": result.username, # 设置token的哟有效期 - 'exp': datetime.utcnow() + timedelta(days=2) + "exp": datetime.utcnow() + timedelta(days=2), } # 生成Token token = AuthToeknHelper.token_encode(data=data) # 登入成功,跳转到聊天室中 - return RedirectResponse(f"http://127.0.0.1:8000/api/v1/room/online?token={token}") + return RedirectResponse( + f"http://127.0.0.1:8000/api/v1/room/online?token={token}" + ) else: return PlainTextResponse("用户没注册过了!或密码错误,请重新输入账号信息!") diff --git a/chapter11/websocket/app.py b/chapter11/websocket/app.py index 6666bf1..0da5eba 100644 --- a/chapter11/websocket/app.py +++ b/chapter11/websocket/app.py @@ -12,6 +12,7 @@ async def startup_event(): pass from db.database import async_engine, Base from models.model import User + async def init_create_table(): async with async_engine.begin() as conn: # await conn.run_sync(Base.metadata.drop_all) diff --git a/chapter11/websocket/config/config.py b/chapter11/websocket/config/config.py index 610c190..0d80293 100644 --- a/chapter11/websocket/config/config.py +++ b/chapter11/websocket/config/config.py @@ -1,11 +1,13 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 定义连接异步引擎数据库的URL地址 ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///chat.db" # 定义TOEKN的签名信息值 - TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' + TOKEN_SIGN_SECRET: str = "ZcjT6Rcp1yIFQoS7" + @lru_cache() def get_settings(): diff --git a/chapter11/websocket/db/database.py b/chapter11/websocket/db/database.py index 34968dd..e84b19e 100644 --- a/chapter11/websocket/db/database.py +++ b/chapter11/websocket/db/database.py @@ -1,11 +1,15 @@ # 导入异步引擎的模块 from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import declarative_base, sessionmaker + # URL地址格式 from config.config import get_settings + # 创建异步引擎对象 async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) # 创建ORM模型基类 Base = declarative_base() # 创建异步的会话管理对象 -SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) \ No newline at end of file +SessionLocal = sessionmaker( + bind=async_engine, expire_on_commit=False, class_=AsyncSession +) diff --git a/chapter11/websocket/dependencies/__init__.py b/chapter11/websocket/dependencies/__init__.py index 3491f5d..bb06624 100644 --- a/chapter11/websocket/dependencies/__init__.py +++ b/chapter11/websocket/dependencies/__init__.py @@ -2,10 +2,11 @@ from typing import AsyncGenerator from db.database import SessionLocal + async def get_db_session() -> AsyncGenerator[AsyncSession, None]: db_session = None try: db_session = SessionLocal() yield db_session finally: - await db_session.close() \ No newline at end of file + await db_session.close() diff --git a/chapter11/websocket/main.py b/chapter11/websocket/main.py index fcfdf4d..465994b 100644 --- a/chapter11/websocket/main.py +++ b/chapter11/websocket/main.py @@ -1,6 +1,7 @@ - from app import creat_app -app =creat_app() -if __name__ == '__main__': + +app = creat_app() +if __name__ == "__main__": import uvicorn - uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) + + uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True) diff --git a/chapter11/websocket/models/model.py b/chapter11/websocket/models/model.py index 6ec8be0..2a77272 100644 --- a/chapter11/websocket/models/model.py +++ b/chapter11/websocket/models/model.py @@ -1,9 +1,10 @@ from db.database import Base -from sqlalchemy import Column, String, DateTime, func,Integer#Integer +from sqlalchemy import Column, String, DateTime, func, Integer # Integer + class User(Base): # 指定本类映射到users表 - __tablename__ = 'user' + __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) # 用户号码 phone_number = Column(String(20)) @@ -13,5 +14,3 @@ class User(Base): password = Column(String(32)) # 用户创建时间 created_at = Column(DateTime(), default=func.now()) - - diff --git a/chapter11/websocket/schemas/__init__.py b/chapter11/websocket/schemas/__init__.py index 2b5cf2b..e1578fe 100644 --- a/chapter11/websocket/schemas/__init__.py +++ b/chapter11/websocket/schemas/__init__.py @@ -2,11 +2,12 @@ from pydantic import BaseModel from starlette.websockets import WebSocket + @dataclass class User: phone_number: str username: str - websocket:WebSocket + websocket: WebSocket class RegisterAaction(BaseModel): @@ -14,17 +15,18 @@ class RegisterAaction(BaseModel): username: str password: str + class LoginAaction(BaseModel): phone_number: str password: str - @dataclass -class UserDistribute : +class UserDistribute: phone_number: str username: str + @dataclass -class WebSocketDistribute : - websocket:WebSocket +class WebSocketDistribute: + websocket: WebSocket diff --git a/chapter11/websocket/servies/user.py b/chapter11/websocket/servies/user.py index b2483ac..2fa28b3 100644 --- a/chapter11/websocket/servies/user.py +++ b/chapter11/websocket/servies/user.py @@ -18,15 +18,23 @@ async def get_user(async_session: AsyncSession, user_id: int): return result.scalars().first() @staticmethod - async def get_user_by_phone_number(async_session: AsyncSession, phone_number: str) -> User: - result = await async_session.execute(select(User).where(User.phone_number == phone_number)) + async def get_user_by_phone_number( + async_session: AsyncSession, phone_number: str + ) -> User: + result = await async_session.execute( + select(User).where(User.phone_number == phone_number) + ) return result.scalars().first() @staticmethod - async def check_user_phone_number_and_password(async_session: AsyncSession, password: str, - phone_number: str) -> User: + async def check_user_phone_number_and_password( + async_session: AsyncSession, password: str, phone_number: str + ) -> User: result = await async_session.execute( - select(User).where(User.phone_number == phone_number, User.password == password)) + select(User).where( + User.phone_number == phone_number, User.password == password + ) + ) return result.scalars().first() @staticmethod diff --git a/chapter11/websocket/utils/auth_helper.py b/chapter11/websocket/utils/auth_helper.py index 9b753e8..174792e 100644 --- a/chapter11/websocket/utils/auth_helper.py +++ b/chapter11/websocket/utils/auth_helper.py @@ -1,5 +1,4 @@ - -from fastapi import HTTPException,status +from fastapi import HTTPException, status from jose import JWTError, jwt from pydantic import BaseModel, ValidationError from jose import jwt @@ -8,7 +7,6 @@ ALGORITHM = "HS256" - class AuthToeknHelper: @staticmethod diff --git a/chapter11/websocket/utils/passlib_hepler.py b/chapter11/websocket/utils/passlib_hepler.py index 852dd4e..3081736 100644 --- a/chapter11/websocket/utils/passlib_hepler.py +++ b/chapter11/websocket/utils/passlib_hepler.py @@ -17,5 +17,6 @@ def verity_password(plain_password: str, hashed_password: str): def hash_password(password: str) -> str: return pwd_context.hash(password) -if __name__ == '__main__': - print(PasslibHelper.hash_password("123456")) \ No newline at end of file + +if __name__ == "__main__": + print(PasslibHelper.hash_password("123456")) diff --git a/chapter11/websocket/utils/random_helper.py b/chapter11/websocket/utils/random_helper.py index d57a7ac..3d005ee 100644 --- a/chapter11/websocket/utils/random_helper.py +++ b/chapter11/websocket/utils/random_helper.py @@ -2,8 +2,7 @@ import random - def generate_short_url(size=7) -> str: letters = string.ascii_letters + string.digits - short_tag = ''.join(random.choice(letters) for i in range(size)) - return short_tag \ No newline at end of file + short_tag = "".join(random.choice(letters) for i in range(size)) + return short_tag diff --git a/chapter11/websocket/utils/room_connection_helper.py b/chapter11/websocket/utils/room_connection_helper.py index 6a1cc86..06faced 100644 --- a/chapter11/websocket/utils/room_connection_helper.py +++ b/chapter11/websocket/utils/room_connection_helper.py @@ -7,7 +7,7 @@ import datetime from faker import Faker -fake = Faker(locale='zh_CN') +fake = Faker(locale="zh_CN") class RoomConnectionManager: @@ -33,25 +33,45 @@ def check_user_logic(self, userlogin: User): async def broadcast_system_room_update_userlist(self): # 循环调用用户里面的连接对象发送广播 - user_online_list = [f"{user.username}({user.phone_number})" for userid, user in self._users_socket.items()] + user_online_list = [ + f"{user.username}({user.phone_number})" + for userid, user in self._users_socket.items() + ] for userid, user in self._users_socket.items(): await user.websocket.send_json( - {"type": "system_room_update_userlist", "data": {'users_list': user_online_list}}) + { + "type": "system_room_update_userlist", + "data": {"users_list": user_online_list}, + } + ) async def broadcast_room_user_login(self, curr_user: User): # 循环调用用户里面的连接对象发送广播 for userid, user in self._users_socket.items(): # 广播当前登入的用户的信息 await user.websocket.send_json( - {"type": "system_msg_user_login", - "data": {'phone_number': self._users_socket[curr_user.phone_number].phone_number, - 'username': self._users_socket[curr_user.phone_number].username}}) + { + "type": "system_msg_user_login", + "data": { + "phone_number": self._users_socket[ + curr_user.phone_number + ].phone_number, + "username": self._users_socket[curr_user.phone_number].username, + }, + } + ) async def broadcast_room_user_logout(self, leave_user): for userid, user in self._users_socket.items(): - await user.websocket.send_json({"type": "system_msg_user_logout", - "data": {'phone_number': leave_user.phone_number, - 'username': leave_user.username}}) + await user.websocket.send_json( + { + "type": "system_msg_user_logout", + "data": { + "phone_number": leave_user.phone_number, + "username": leave_user.username, + }, + } + ) async def broadcast_user_send_message(self, leave_user: User, msg: str): for userid, user in self._users_socket.items(): @@ -61,6 +81,15 @@ async def broadcast_user_send_message(self, leave_user: User, msg: str): else: sendmsg = f"{leave_user.username}说:{msg}" await user.websocket.send_json( - {"type": "user_send_msg", - "data": {'phone_number': leave_user.phone_number, 'username': leave_user.username, "msg": sendmsg, - "datetime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}}) + { + "type": "user_send_msg", + "data": { + "phone_number": leave_user.phone_number, + "username": leave_user.username, + "msg": sendmsg, + "datetime": datetime.datetime.now().strftime( + "%Y-%m-%d %H:%M:%S" + ), + }, + } + ) diff --git a/chapter12/booking_system/apis/doctor/api/__init__.py b/chapter12/booking_system/apis/doctor/api/__init__.py index 3159d25..61c5882 100644 --- a/chapter12/booking_system/apis/doctor/api/__init__.py +++ b/chapter12/booking_system/apis/doctor/api/__init__.py @@ -1,3 +1,6 @@ from fastapi import APIRouter -router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) -from ..api import doctor_api \ No newline at end of file + +router_docrot = APIRouter( + prefix="/api/v1", tags=["医生信息模块"], include_in_schema=True +) +from ..api import doctor_api diff --git a/chapter12/booking_system/apis/doctor/api/doctor_api.py b/chapter12/booking_system/apis/doctor/api/doctor_api.py index c3993ed..ae96995 100644 --- a/chapter12/booking_system/apis/doctor/api/doctor_api.py +++ b/chapter12/booking_system/apis/doctor/api/doctor_api.py @@ -8,19 +8,22 @@ from utils.datatime_helper import diff_days_for_now_time -@router_docrot.get("/doctor_list", summary='获取可以预约医生列表信息') +@router_docrot.get("/doctor_list", summary="获取可以预约医生列表信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): - ''' + """ 获取可以预约医生列表信息\n\n :param db_session: 数据库连接依赖注入对象\n\n :return: 返回可以预约医生列表信息\n\n - ''' + """ info = await DoctorServeries.get_doctor_list_infos(db_session) return Success(result=info) -@router_docrot.get("/doctor_scheduling_info", summary='获取医生排班信息') -async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = Depends(depends_get_db_session)): +@router_docrot.get("/doctor_scheduling_info", summary="获取医生排班信息") +async def callbadk( + forms: SchedulingInfo = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), +): # 当前系统日期对比,判断当前是否是否已操作系统时间,超过系统时间预约信息则无法查询 if forms.start_time: try: @@ -30,25 +33,26 @@ async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = except: return Fail(message="当前日期无效,日期格式错误!") # 查询排班信息 - doctor_result, doctor_scheduling_result = await DoctorServeries.get_doctor_scheduling_info(db_session, - dno=forms.dno, - start_time=forms.start_time) + doctor_result, doctor_scheduling_result = ( + await DoctorServeries.get_doctor_scheduling_info( + db_session, dno=forms.dno, start_time=forms.start_time + ) + ) scheduling_info = {} for item in doctor_scheduling_result: - if item.ampm == 'am': - if 'am' not in scheduling_info: - scheduling_info['am'] = [] - scheduling_info['am'].append(item) + if item.ampm == "am": + if "am" not in scheduling_info: + scheduling_info["am"] = [] + scheduling_info["am"].append(item) else: - scheduling_info['am'].append(item) - if item.ampm == 'pm': - if 'pm' not in scheduling_info: - scheduling_info['pm'] = [] - scheduling_info['pm'].append(item) + scheduling_info["am"].append(item) + if item.ampm == "pm": + if "pm" not in scheduling_info: + scheduling_info["pm"] = [] + scheduling_info["pm"].append(item) else: - scheduling_info['pm'].append(item) - backinfo = { - 'doctor': doctor_result, - 'scheduling_info': scheduling_info - } - return Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + scheduling_info["pm"].append(item) + backinfo = {"doctor": doctor_result, "scheduling_info": scheduling_info} + return ( + Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + ) diff --git a/chapter12/booking_system/apis/doctor/repository/__init__.py b/chapter12/booking_system/apis/doctor/repository/__init__.py index b0f4153..2753d20 100644 --- a/chapter12/booking_system/apis/doctor/repository/__init__.py +++ b/chapter12/booking_system/apis/doctor/repository/__init__.py @@ -1,6 +1,6 @@ from sqlalchemy import select, update, delete from sqlalchemy.ext.asyncio import AsyncSession -from db.models import Doctorinfo, DoctorScheduling,DoctorSubscribeinfo +from db.models import Doctorinfo, DoctorScheduling, DoctorSubscribeinfo from typing import Optional from utils.datatime_helper import str_to_datatime, datatime_to_str, datetime @@ -13,73 +13,118 @@ async def get_doctor_list_infos(async_session: AsyncSession, enable: int = 1): # query =select(Doctor).with_only_columns(Doctor.dno,Doctor.dnname,Doctor.fee,Doctor.pic,Doctor.rank) # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.fee, Doctorinfo.pic, Doctorinfo.rank) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.fee, + Doctorinfo.pic, + Doctorinfo.rank, + ) _result = await async_session.execute(query.where(Doctorinfo.enable == enable)) # 调用.scalars()这样会返回的是标量值,不是ROW== return _result.all() @staticmethod - async def get_doctor_scheduling_info(async_session: AsyncSession, dno, enable: int = 1, start_time=None): - ''' + async def get_doctor_scheduling_info( + async_session: AsyncSession, dno, enable: int = 1, start_time=None + ): + """ 返回预约医生的排班信息 :param async_session: :param enable: :param start_time: 当前医生的排班时间起点 默认查询当天的时间排班 :param end_time: 当前医生的排班截止时间点 默认查询当天的时间排班 :return: - ''' + """ # 获取排班信息 # 查询出当前医生的信息 - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.destag, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.describe) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.destag, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.describe, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_scheduling_result = [] if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.nsnum, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.tiempm, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.nsnum, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.tiempm, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno) + query = query.where( + DoctorScheduling.enable == enable, DoctorScheduling.dno == dno + ) if start_time: # 格式化时间处理 start_time = str_to_datatime(start_time) - end_time = str_to_datatime(datatime_to_str((start_time + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str((start_time + datetime.timedelta(days=1))) + ) else: # 格式化时间处理 start_time = str_to_datatime(datatime_to_str(datetime.datetime.now())) - end_time = str_to_datatime(datatime_to_str((datetime.datetime.now() + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str( + (datetime.datetime.now() + datetime.timedelta(days=1)) + ) + ) - - query = query.where(DoctorScheduling.dnotime >= start_time, DoctorScheduling.dnotime < end_time) + query = query.where( + DoctorScheduling.dnotime >= start_time, + DoctorScheduling.dnotime < end_time, + ) _result = await async_session.execute(query) doctor_scheduling_result = _result.all() return doctor_result, doctor_scheduling_result @staticmethod - async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, dno, nsindex, enable: int = 1): - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.addr,Doctorinfo.fee) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + async def get_doctor_curr_nsindex_scheduling_info( + async_session: AsyncSession, dno, nsindex, enable: int = 1 + ): + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.addr, + Doctorinfo.fee, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_nsnuminfo_result: Optional[DoctorScheduling] = None if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.nsnum, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiempm, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.nsnum, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiempm, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno, - DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.enable == enable, + DoctorScheduling.dno == dno, + DoctorScheduling.nsindex == nsindex, + ) _result = await async_session.execute(query) doctor_nsnuminfo_result = _result.first() @@ -87,11 +132,19 @@ async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, d return doctor_result, doctor_nsnuminfo_result @staticmethod - async def updata_nusnum_info_dno(async_session: AsyncSession, dno, nsindex,isup=True): - response = update(DoctorSubscribeinfo).where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + async def updata_nusnum_info_dno( + async_session: AsyncSession, dno, nsindex, isup=True + ): + response = update(DoctorSubscribeinfo).where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) if isup: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum + 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum + 1) + ) else: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum - 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum - 1) + ) await async_session.commit() return result.rowcount diff --git a/chapter12/booking_system/apis/hospital/api/__init__.py b/chapter12/booking_system/apis/hospital/api/__init__.py index c4f3dac..51d08b3 100644 --- a/chapter12/booking_system/apis/hospital/api/__init__.py +++ b/chapter12/booking_system/apis/hospital/api/__init__.py @@ -1,4 +1,5 @@ from fastapi import APIRouter -router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) + +router_hospital = APIRouter(prefix="/api/v1", tags=["医院信息模块"]) # 導入模塊 -from apis.hospital.api import get_hospital_info \ No newline at end of file +from apis.hospital.api import get_hospital_info diff --git a/chapter12/booking_system/apis/hospital/api/get_hospital_info.py b/chapter12/booking_system/apis/hospital/api/get_hospital_info.py index 64dd0dc..c01c2cb 100644 --- a/chapter12/booking_system/apis/hospital/api/get_hospital_info.py +++ b/chapter12/booking_system/apis/hospital/api/get_hospital_info.py @@ -6,7 +6,7 @@ from ..api import router_hospital -@router_hospital.get("/hospital_info", summary='获取医院信息') +@router_hospital.get("/hospital_info", summary="获取医院信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): info = await HospitalServeries.get_hospital_info(db_session, id=1) return Success(result=info) diff --git a/chapter12/booking_system/apis/hospital/repository/__init__.py b/chapter12/booking_system/apis/hospital/repository/__init__.py index 2c5bacd..56c2393 100644 --- a/chapter12/booking_system/apis/hospital/repository/__init__.py +++ b/chapter12/booking_system/apis/hospital/repository/__init__.py @@ -9,7 +9,10 @@ class HospitalServeries: @staticmethod async def get_hospital_info(async_session: AsyncSession, id: int): _result = await async_session.execute( - select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) + select( + Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages + ).where(Hospitalinfo.id == id) + ) scalars_result = _result.first() # scalars_result = _result.scalars().first() return scalars_result diff --git a/chapter12/booking_system/apis/payorders/api/__init__.py b/chapter12/booking_system/apis/payorders/api/__init__.py index 2b58ff6..df56d75 100644 --- a/chapter12/booking_system/apis/payorders/api/__init__.py +++ b/chapter12/booking_system/apis/payorders/api/__init__.py @@ -1,7 +1,8 @@ from fastapi import APIRouter -router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) + +router_payorders = APIRouter(prefix="/api/v1", tags=["支付订单模块"]) from apis.payorders.api import doctor_reserve_order from apis.payorders.api import payback_reserve_order from apis.payorders.api import reserve_order_info from apis.payorders.api import doctor_reserve_reorder -from apis.payorders.api import doctor_order_check \ No newline at end of file +from apis.payorders.api import doctor_order_check diff --git a/chapter12/booking_system/apis/payorders/api/doctor_order_check.py b/chapter12/booking_system/apis/payorders/api/doctor_order_check.py index c5a7c3f..b9536b5 100644 --- a/chapter12/booking_system/apis/payorders/api/doctor_order_check.py +++ b/chapter12/booking_system/apis/payorders/api/doctor_order_check.py @@ -15,19 +15,28 @@ from apis.payorders.repository import PayOrderServeries -@router_payorders.post("/doctor_order_check", summary='订单状态查询') -async def callbadk(forms: SubscribeOrderCheckForm=Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): - +@router_payorders.post("/doctor_order_check", summary="订单状态查询") +async def callbadk( + forms: SubscribeOrderCheckForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(db_session,forms.dno, - forms.visit_uopenid, - forms.orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, forms.dno, forms.visit_uopenid, forms.orderid + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") - return Success(api_code=200, result={'status': doctor_nsnum_info_result.statue}, - message='查询成功') if doctor_nsnum_info_result else Fail(api_code=200, result=None, - message='无排班记录信息,或已过有效期') + return ( + Success( + api_code=200, + result={"status": doctor_nsnum_info_result.statue}, + message="查询成功", + ) + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无排班记录信息,或已过有效期") + ) diff --git a/chapter12/booking_system/apis/payorders/api/doctor_reserve_order.py b/chapter12/booking_system/apis/payorders/api/doctor_reserve_order.py index 7d7e810..91826ec 100644 --- a/chapter12/booking_system/apis/payorders/api/doctor_reserve_order.py +++ b/chapter12/booking_system/apis/payorders/api/doctor_reserve_order.py @@ -8,60 +8,79 @@ from apis.payorders.api import router_payorders from apis.payorders.schemas import PayReserveOrderForm from utils.datatime_helper import datetime -from utils import ordernum_helper,json_helper +from utils import ordernum_helper, json_helper from exts.wechatpy.pay import WeChatPay, WeChatPayException from config.config import get_settings from apis.payorders.dependencies import get_client_ip + # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client from exts.async_rabbit import async_rabbit_client import decimal from asgiref.sync import sync_to_async -@router_payorders.post("/doctor_reserve_order", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + +@router_payorders.post( + "/doctor_reserve_order", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -72,7 +91,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -80,118 +99,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 60 * 15 - order_exchange_name = 'xz-order-exchange' - order_routing_key = 'order_handler' - sync_rabbit_client.send_basic_publish(exchange_name=order_exchange_name, routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange" + order_routing_key = "order_handler" + sync_rabbit_client.send_basic_publish( + exchange_name=order_exchange_name, + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -202,7 +258,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -210,122 +266,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async_as_tarn", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async_as_tarn", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - - - - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -336,7 +425,8 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 - pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)(trade_type='JSAPI', + pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)( + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -344,7 +434,8 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid) + out_trade_no=orderid, + ) # pay_wx_res_result = wx_pay.order.create( # trade_type='JSAPI', @@ -360,64 +451,83 @@ async def callbadk(forms: PayReserveOrderForm, pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter12/booking_system/apis/payorders/api/doctor_reserve_reorder.py b/chapter12/booking_system/apis/payorders/api/doctor_reserve_reorder.py index 2df8b1f..b098b40 100644 --- a/chapter12/booking_system/apis/payorders/api/doctor_reserve_reorder.py +++ b/chapter12/booking_system/apis/payorders/api/doctor_reserve_reorder.py @@ -12,70 +12,96 @@ import decimal -@router_payorders.get("/doctor_reserve_order", summary='未支付订单重新发起支付') -async def callbadk(forms: PayCancelPayOrderForm = Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): +@router_payorders.get("/doctor_reserve_order", summary="未支付订单重新发起支付") +async def callbadk( + forms: PayCancelPayOrderForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 获取预约详情信息列表 - doctor_order_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_order_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) print(doctor_order_info_result.dno) # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) # 先查询出上次下单的记录到的信息 if not doctor_order_info_result: - return Fail(api_code=200, result=None, message='无此订单记录信息!') + return Fail(api_code=200, result=None, message="无此订单记录信息!") if doctor_order_info_result.statue == 4: - return Fail(api_code=200, result=None, message='订单已超时未支付!建议取消重新下单!') + return Fail( + api_code=200, result=None, message="订单已超时未支付!建议取消重新下单!" + ) # 对订单信息进行校验,只有未付款的清单信息才可以继续下一步的支付的操作 if doctor_order_info_result.statue != 1: - return Fail(api_code=200, result=None, message='订单信息状态异常信息!无法继续支付!建议取消重新下单!') + return Fail( + api_code=200, + result=None, + message="订单信息状态异常信息!无法继续支付!建议取消重新下单!", + ) # 查询当前预约时段 nsindex = doctor_order_info_result.nsindex # 查询排班信息 - doctor_nsnum_info_result = await PayOrderServeries.get_doctor_scheduling_info_info_order(db_session, dno=forms.dno, - nsindex=nsindex) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_doctor_scheduling_info_info_order( + db_session, dno=forms.dno, nsindex=nsindex + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='无排班记录信息!') + return Fail(api_code=200, result=None, message="无排班记录信息!") # 对比当前的预约时段是否有效 - print('doctor_nsnum_info_result.tiempm', doctor_nsnum_info_result.tiempm) + print("doctor_nsnum_info_result.tiempm", doctor_nsnum_info_result.tiempm) if not datatime_helper.effectiveness_tiempm(str(doctor_nsnum_info_result.tiempm)): - return Fail(api_code=200, result=None, message='当前预约时段无效!请更换另一个时段进行预约!') + return Fail( + api_code=200, + result=None, + message="当前预约时段无效!请更换另一个时段进行预约!", + ) order_info = { - 'dno': forms.dno, - 'nsindex': nsindex, - 'orderid': doctor_order_info_result.orderid if doctor_order_info_result.orderid else None, - 'visit_uphone': doctor_order_info_result.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': doctor_order_info_result.visittime + "dno": forms.dno, + "nsindex": nsindex, + "orderid": ( + doctor_order_info_result.orderid + if doctor_order_info_result.orderid + else None + ), + "visit_uphone": doctor_order_info_result.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": doctor_order_info_result.visittime, } # 新手支付生成 try: - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, - mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) orderid = doctor_order_info_result.orderid order_info_json = json_helper.dict_to_json(order_info) payfee = doctor_order_info_result.payfee visittime = doctor_order_info_result.visittime # ================= - doctor_info_result = await PayOrderServeries.get_doctor_info(db_session, dno=forms.dno) + doctor_info_result = await PayOrderServeries.get_doctor_info( + db_session, dno=forms.dno + ) dnname = doctor_info_result.dnname # 解决办法:01商户订单号重复 问题 # 保证再次支付下单时发起的请求参数和第一次一样。 # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -86,7 +112,7 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), attach = f"{forms.dno}|{orderid}|{nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -94,49 +120,72 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.errmsg'] = wcpayex.errmsg - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}') + order_info["wcpayex.errmsg"] = wcpayex.errmsg + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}", + ) except Exception: import traceback + traceback.print_exc() - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(datatime_helper.get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) # 更新当前支付的订单信息 # 更新没有支付的成功的订单的,状态! - doctor_nsnum_info_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, - dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=1, - ) + doctor_nsnum_info_result = ( + await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=1, + ) + ) if doctor_nsnum_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, - message='您已提交订单,请尽快支付哟!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="您已提交订单,请尽快支付哟!", + ) else: - order_info['creat_order_info_error'] = '创建订单到数据库的时候异常' - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["creat_order_info_error"] = "创建订单到数据库的时候异常" + return Fail( + api_code=200, + result=None, + message="微信服务请求处理异常,请稍后重试!!", + ) else: # 记录请求异常回调信息 - order_info['wx_return_code'] = pay_wx_res_result.get('return_code') - order_info['wx_return_msg'] = pay_wx_res_result.get('return_msg') - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["wx_return_code"] = pay_wx_res_result.get("return_code") + order_info["wx_return_msg"] = pay_wx_res_result.get("return_msg") + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter12/booking_system/apis/payorders/api/payback_reserve_order.py b/chapter12/booking_system/apis/payorders/api/payback_reserve_order.py index 7089a56..8edef4c 100644 --- a/chapter12/booking_system/apis/payorders/api/payback_reserve_order.py +++ b/chapter12/booking_system/apis/payorders/api/payback_reserve_order.py @@ -10,60 +10,80 @@ from exts.wechatpy.client import WeChatClient - -@router_payorders.post("/payback_reserve_order", summary='支付订单回调处理') -async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_get_db_session)): - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) +@router_payorders.post("/payback_reserve_order", summary="支付订单回调处理") +async def callbadk( + request: Request, db_session: AsyncSession = Depends(depends_get_db_session) +): + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) body = await request.body() try: _result = wx_pay.parse_payment_result(body) except InvalidSignatureException as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - out_trade_no = _result.get('out_trade_no') + out_trade_no = _result.get("out_trade_no") # 微信要求的回复的模式 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="application/xml") except Exception as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") if _result: # 返回状态码信息 - return_code = _result.get('return_code') + return_code = _result.get("return_code") # 处理状态码 - if return_code != 'SUCCESS': + if return_code != "SUCCESS": # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 业务错误处理结果 - result_code = _result.get('result_code') + result_code = _result.get("result_code") # 业务支付成功处理 - if result_code == 'SUCCESS': + if result_code == "SUCCESS": pass - wx_gzx_id = _result.get('appid') - attach = _result.get('attach') - bank_type = _result.get('bank_type') - cash_fee = _result.get('cash_fee') - fee_type = _result.get('fee_type') - is_subscribe = _result.get('is_subscribe') - wx_mch_id = _result.get('mch_id') - nonce_str = _result.get('nonce_str') - openid = _result.get('openid') - out_trade_no = _result.get('out_trade_no') - time_end = _result.get('time_end') - total_fee = _result.get('total_fee') - trade_type = _result.get('trade_type') - transaction_id = _result.get('transaction_id') + wx_gzx_id = _result.get("appid") + attach = _result.get("attach") + bank_type = _result.get("bank_type") + cash_fee = _result.get("cash_fee") + fee_type = _result.get("fee_type") + is_subscribe = _result.get("is_subscribe") + wx_mch_id = _result.get("mch_id") + nonce_str = _result.get("nonce_str") + openid = _result.get("openid") + out_trade_no = _result.get("out_trade_no") + time_end = _result.get("time_end") + total_fee = _result.get("total_fee") + trade_type = _result.get("trade_type") + transaction_id = _result.get("transaction_id") # 回调透传信息 attach-在查询API和支付通知中原样返回,可作为自定义参数使用。 - #attach = f"{forms.dno}|{orderid}|{forms.nsindex}" + # attach = f"{forms.dno}|{orderid}|{forms.nsindex}" attach_info = attach.split("|") attach_dno = attach_info[0] attach_orderid = attach_info[1] @@ -71,73 +91,103 @@ async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_ attach_nsindex = attach_info[2] # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_byorder_dno_state(db_session, attach_dno, - attach_orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_byorder_dno_state( + db_session, attach_dno, attach_orderid + ) + ) if not doctor_nsnum_info_result: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 订单信息存在 # 更新支付的成功状态! # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) if doctor_nsnum_info_result.statue == 2: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") - isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, dno=attach_dno, - orderid=attach_orderid, - visit_uopenid=attach_visit_uopenid, - updata={ - 'statue': 2, - # 标记已支付,待就诊! - 'visit_statue': 1, - 'notify_callback_time': 'now()', - 'is_subscribe': is_subscribe, - } - ) + isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=attach_dno, + orderid=attach_orderid, + visit_uopenid=attach_visit_uopenid, + updata={ + "statue": 2, + # 标记已支付,待就诊! + "visit_statue": 1, + "notify_callback_time": "now()", + "is_subscribe": is_subscribe, + }, + ) # 设置具体的点击通知URL地址为,查询订单详情页信息地址 visittime = doctor_nsnum_info_result.visittime visitday = doctor_nsnum_info_result.visitday # 模板订单跳转地址详情信息 - template_url = f'http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}' + template_url = f"http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}" if isok: # 开发发送预约成功的模板通知信息 - client = WeChatClient(appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET) + client = WeChatClient( + appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET + ) # client.session = sync_redis_client - resulst = client.message.send_template(to_user_openid=attach_visit_uopenid, - template_id='XXXXXXXXXXXXXXXXXXXXXX', - url=template_url, - data={ - "first": { - "value": f"您预约挂号{visitday}{visittime}成功!", - "color": "#173177" - }, - # 科室 - "keyword2": { - "value": "中医科", - "color": "#173177" - }, - # 就诊地址 - "keyword3": { - "value": "XXXXXXXXXXXXXX中医馆", - "color": "#173177" - }, - # 备注信息 - "remark": { - "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", - "color": "#173177" - } - } - ) + resulst = client.message.send_template( + to_user_openid=attach_visit_uopenid, + template_id="XXXXXXXXXXXXXXXXXXXXXX", + url=template_url, + data={ + "first": { + "value": f"您预约挂号{visitday}{visittime}成功!", + "color": "#173177", + }, + # 科室 + "keyword2": {"value": "中医科", "color": "#173177"}, + # 就诊地址 + "keyword3": { + "value": "XXXXXXXXXXXXXX中医馆", + "color": "#173177", + }, + # 备注信息 + "remark": { + "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", + "color": "#173177", + }, + }, + ) # 响应微信支付回调处理 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") diff --git a/chapter12/booking_system/apis/payorders/api/reserve_order_info.py b/chapter12/booking_system/apis/payorders/api/reserve_order_info.py index e5f9139..2f621e0 100644 --- a/chapter12/booking_system/apis/payorders/api/reserve_order_info.py +++ b/chapter12/booking_system/apis/payorders/api/reserve_order_info.py @@ -9,13 +9,17 @@ from utils.datatime_helper import diff_days_for_now_time - -@router_payorders.post("/reserve_order_info", summary='获取预约订单信息') -async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_payorders.post("/reserve_order_info", summary="获取预约订单信息") +async def callbadk( + forms: MakeReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 查询预约信息 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_result: return Fail(message="当前医生信息不存在!") if not doctor_nsnuminfo_result: @@ -28,11 +32,15 @@ async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depen if is_limt_start_time < 0: return Fail(message="当前日期无效,无排班信息!") backresult = { - 'dnotime': str(doctor_nsnuminfo_result.dnotime), - 'dnoampm_tag': '{} {} {}'.format( + "dnotime": str(doctor_nsnuminfo_result.dnotime), + "dnoampm_tag": "{} {} {}".format( num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', - doctor_nsnuminfo_result.tiemampmstr - ) + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + doctor_nsnuminfo_result.tiemampmstr, + ), } - return Success(result={**doctor_result, **backresult}) if doctor_result else Fail(message="无当前医生排班信息") \ No newline at end of file + return ( + Success(result={**doctor_result, **backresult}) + if doctor_result + else Fail(message="无当前医生排班信息") + ) diff --git a/chapter12/booking_system/apis/payorders/dependencies/__init__.py b/chapter12/booking_system/apis/payorders/dependencies/__init__.py index 3d64412..60365ca 100644 --- a/chapter12/booking_system/apis/payorders/dependencies/__init__.py +++ b/chapter12/booking_system/apis/payorders/dependencies/__init__.py @@ -1,5 +1,6 @@ from starlette.requests import Request + def get_client_ip(request: Request): """ 获取客户端真实ip @@ -9,4 +10,4 @@ def get_client_ip(request: Request): forwarded = request.headers.get("X-Forwarded-For") if forwarded: return forwarded.split(",")[0] - return request.client.host \ No newline at end of file + return request.client.host diff --git a/chapter12/booking_system/apis/payorders/repository/__init__.py b/chapter12/booking_system/apis/payorders/repository/__init__.py index 26c9bda..f853035 100644 --- a/chapter12/booking_system/apis/payorders/repository/__init__.py +++ b/chapter12/booking_system/apis/payorders/repository/__init__.py @@ -4,78 +4,91 @@ from typing import Optional from db.async_database import async_context_get_db + class PayOrderServeries: @staticmethod - async def get_order_info_dno_orderid_visituopenid_state(async_session: AsyncSession, dno, visit_uopenid, - orderid)->DoctorSubscribeinfo: + async def get_order_info_dno_orderid_visituopenid_state( + async_session: AsyncSession, dno, visit_uopenid, orderid + ) -> DoctorSubscribeinfo: query = select(DoctorSubscribeinfo) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) _result = await async_session.execute(query) # 如果查询时整个模型的需要.scalar() # 如果是查询指定选择某些字段的是则不需要.scalar() # .scalar() 和 _result.scalars().first() 是一样效果 return _result.scalars().first() - - @staticmethod - async def get_doctor_info(async_session: AsyncSession, dno)->Doctorinfo: - - query = select( Doctorinfo.dnname, - Doctorinfo.pic, - Doctorinfo.dno, - Doctorinfo.rank, - Doctorinfo.fee, - Doctorinfo.destag, - Doctorinfo.describe) + async def get_doctor_info(async_session: AsyncSession, dno) -> Doctorinfo: + + query = select( + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.dno, + Doctorinfo.rank, + Doctorinfo.fee, + Doctorinfo.destag, + Doctorinfo.describe, + ) # 查询当前医生排班信息归属 query = query.where(Doctorinfo.dno == dno) _result = await async_session.execute(query) return _result.first() - - @staticmethod - async def get_doctor_scheduling_info_info_order(async_session: AsyncSession, dno, nsindex) -> DoctorScheduling: - query = select(DoctorScheduling.dnotime, - DoctorScheduling.ampm, - DoctorScheduling.tiempm, - DoctorScheduling.dnotime, - DoctorScheduling.tiemampmstr, - ) + async def get_doctor_scheduling_info_info_order( + async_session: AsyncSession, dno, nsindex + ) -> DoctorScheduling: + query = select( + DoctorScheduling.dnotime, + DoctorScheduling.ampm, + DoctorScheduling.tiempm, + DoctorScheduling.dnotime, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) _result = await async_session.execute(query) return _result.first() @staticmethod - async def get_order_info_byvisit_uopenid_state(async_session: AsyncSession, visit_uopenid, statue=1): - ''' + async def get_order_info_byvisit_uopenid_state( + async_session: AsyncSession, visit_uopenid, statue=1 + ): + """ 判断是否存在存在未支付的订单 :param async_session: 数据库会话对象 :param visit_uopenid: 当前用户opendi :param statue: 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 :return: - ''' + """ # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = select(DoctorSubscribeinfo.id) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.statue == statue, DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.statue == statue, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) _result = await async_session.execute(query) return _result.first() @staticmethod async def creat_order_info(async_session: AsyncSession, **kwargs): - ''' + """ 开始创建订单内容,并添加到数据库 :param async_session: :param kwargs: :return: - ''' + """ new_order = DoctorSubscribeinfo(**kwargs) async_session.add(new_order) await async_session.commit() @@ -83,40 +96,57 @@ async def creat_order_info(async_session: AsyncSession, **kwargs): return new_order @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno(async_session: AsyncSession, dno, orderid, visit_uopenid, **updata): + async def updata_order_info_byorder_dno( + async_session: AsyncSession, dno, orderid, visit_uopenid, **updata + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = update(DoctorSubscribeinfo) - query = query.where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) result = await async_session.execute(query.values(updata)) await async_session.commit() # result.rowcount 1:更新成功 0 更新失败 return result.rowcount -if __name__ == '__main__': +if __name__ == "__main__": import asyncio + async def sdsdf(): async with async_context_get_db() as session: - asdas = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(session, - dno='10001', - visit_uopenid='orE7I56mAt_dvtRoXkMw-hY8FkwM', - orderid='2207081548588935269') + asdas = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + session, + dno="10001", + visit_uopenid="orE7I56mAt_dvtRoXkMw-hY8FkwM", + orderid="2207081548588935269", + ) + ) print(asdas.orderid) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter12/booking_system/apis/payorders/schemas/__init__.py b/chapter12/booking_system/apis/payorders/schemas/__init__.py index f9db523..d79c74a 100644 --- a/chapter12/booking_system/apis/payorders/schemas/__init__.py +++ b/chapter12/booking_system/apis/payorders/schemas/__init__.py @@ -6,7 +6,7 @@ class SchedulingInfo(BaseModel): # 预约医生编号 dno: str # 预约时间 - start_time:str = None + start_time: str = None class MakeReserveOrderForm(BaseModel): @@ -16,16 +16,13 @@ class MakeReserveOrderForm(BaseModel): nsindex: str - class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") - - class PayReserveOrderForm(BaseModel): # 预约医生编号 dno: str @@ -34,18 +31,18 @@ class PayReserveOrderForm(BaseModel): # 预约人信息 visit_uname: str visit_uphone: str - visit_uopenid:str =None - visit_usex:str - visit_uage:str + visit_uopenid: str = None + visit_usex: str + visit_uage: str class PayCancelPayOrderForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - orderid:str + orderid: str # 预约医生的编号 - dno:str - + dno: str diff --git a/chapter12/booking_system/apis/userorders/api/__init__.py b/chapter12/booking_system/apis/userorders/api/__init__.py index 5cf6f5a..1226a32 100644 --- a/chapter12/booking_system/apis/userorders/api/__init__.py +++ b/chapter12/booking_system/apis/userorders/api/__init__.py @@ -1,4 +1,10 @@ from fastapi import APIRouter -router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) -from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ - wxauth_login + +router_userorders = APIRouter(prefix="/api/v1", tags=["用户订单模块"]) +from apis.userorders.api import ( + refund_reserve_order, + unpay_reserve_order, + user_order_info, + user_order_list, + wxauth_login, +) diff --git a/chapter12/booking_system/apis/userorders/api/refund_reserve_order.py b/chapter12/booking_system/apis/userorders/api/refund_reserve_order.py index dd9f94f..4d7b772 100644 --- a/chapter12/booking_system/apis/userorders/api/refund_reserve_order.py +++ b/chapter12/booking_system/apis/userorders/api/refund_reserve_order.py @@ -10,54 +10,78 @@ import time -@router_userorders.put("/refund_reserve_order", summary='订单退款申请') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/refund_reserve_order", summary="订单退款申请") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 1: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单还为支付!无法申请退款!') + return Fail(api_code=200, result=None, message="该订单还为支付!无法申请退款!") if doctor_nsnum_info_result.statue == 5: pass - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该已超时未支付,订单已过有效期!不可操作!') + return Fail( + api_code=200, + result=None, + message="该已超时未支付,订单已过有效期!不可操作!", + ) # 已经支付的订单信息 if doctor_nsnum_info_result.statue == 2: pass # 来获取时间差中的秒数。注意,seconds获得的秒只是时间差中的小时、分钟和秒部分的和,并没有包含时间差的天数(既是两个时间点不是同一天,失效) - today = time.strftime('%Y%m%d %H:%M:%S', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 - datiem = (currday_time_info_tochane_datetime(doctor_nsnum_info_result.visitday) - datetime.timedelta(days=1)) - subscribe_times = datetime.datetime.strptime(f"{str(datiem).replace('00:00:00', '')}23:59:59", - "%Y-%m-%d %H:%M:%S") + today = time.strftime("%Y%m%d %H:%M:%S", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 + datiem = currday_time_info_tochane_datetime( + doctor_nsnum_info_result.visitday + ) - datetime.timedelta(days=1) + subscribe_times = datetime.datetime.strptime( + f"{str(datiem).replace('00:00:00', '')}23:59:59", "%Y-%m-%d %H:%M:%S" + ) # 当前时间小于预约时间的最后截止时间之后就不可以预约 if todaydate >= subscribe_times: - return Fail(api_code=200, result=None, message='非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!') - - isok = Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - updata={ - 'statue': 5, - 'refund_statue': 1, - 'apply_refund_time': 'now()' - } - ) - return Success(api_code=200, result=None, message='申请退款成功!已提交审核!') if isok else Fail(api_code=200, result=None, - message='申请退款失败!') + return Fail( + api_code=200, + result=None, + message="非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!", + ) + + isok = Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + updata={"statue": 5, "refund_statue": 1, "apply_refund_time": "now()"}, + ) + return ( + Success(api_code=200, result=None, message="申请退款成功!已提交审核!") + if isok + else Fail(api_code=200, result=None, message="申请退款失败!") + ) diff --git a/chapter12/booking_system/apis/userorders/api/unpay_reserve_order.py b/chapter12/booking_system/apis/userorders/api/unpay_reserve_order.py index 871cc7f..3534acf 100644 --- a/chapter12/booking_system/apis/userorders/api/unpay_reserve_order.py +++ b/chapter12/booking_system/apis/userorders/api/unpay_reserve_order.py @@ -7,40 +7,57 @@ from ..repository import Serveries -@router_userorders.put("/unpay_reserve_order", summary='取消订单支付') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/unpay_reserve_order", summary="取消订单支付") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已过有效期!不可操作!') + return Fail(api_code=200, result=None, message="订单已过有效期!不可操作!") if doctor_nsnum_info_result.statue == 2: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已支付成功!如需取消,请申请操作退款!') + return Fail( + api_code=200, + result=None, + message="该订单已支付成功!如需取消,请申请操作退款!", + ) if doctor_nsnum_info_result.statue == 5: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) # 更新没有支付的成功的订单的,状态! - isok = await Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=3 - ) - - return Success(api_code=200, result=None, message='订单取消成功') if isok else Fail(api_code=200, result=None, - message='订单取消失败') + isok = await Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=3, + ) + + return ( + Success(api_code=200, result=None, message="订单取消成功") + if isok + else Fail(api_code=200, result=None, message="订单取消失败") + ) diff --git a/chapter12/booking_system/apis/userorders/api/user_order_info.py b/chapter12/booking_system/apis/userorders/api/user_order_info.py index 8db523d..4c3b182 100644 --- a/chapter12/booking_system/apis/userorders/api/user_order_info.py +++ b/chapter12/booking_system/apis/userorders/api/user_order_info.py @@ -10,15 +10,23 @@ import time -@router_userorders.post("/user_order_info", summary='用户订单详情查看') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.post("/user_order_info", summary="用户订单详情查看") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 获取预约详情信息列表 - doctor_nsnum_info_result = await Serveries.get_order_info_list_by_visit_uopenid_detailt( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_nsnum_info_result = ( + await Serveries.get_order_info_list_by_visit_uopenid_detailt( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=doctor_nsnum_info_result, message='查询成功') if doctor_nsnum_info_result else Fail( - api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=doctor_nsnum_info_result, message="查询成功") + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter12/booking_system/apis/userorders/api/user_order_list.py b/chapter12/booking_system/apis/userorders/api/user_order_list.py index fd87bf8..d4a574b 100644 --- a/chapter12/booking_system/apis/userorders/api/user_order_list.py +++ b/chapter12/booking_system/apis/userorders/api/user_order_list.py @@ -6,10 +6,20 @@ from ..schemas import UserOrderIonfoListForm from ..repository import Serveries -@router_userorders.post("/user_order_list", summary='用户自己订单列表') -async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): + +@router_userorders.post("/user_order_list", summary="用户自己订单列表") +async def callbadk( + forms: UserOrderIonfoListForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测用户的有消息 # 判断当前用户是否已经被拉黑啦,禁用了! - result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) + result = await Serveries.get_order_info_list_by_visit_uopenid_select( + db_session, visit_uopenid=forms.visit_uopenid, statue=forms.statue + ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=result, message="查询成功") + if result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter12/booking_system/apis/userorders/api/wxauth_login.py b/chapter12/booking_system/apis/userorders/api/wxauth_login.py index fda5814..e7e2ca3 100644 --- a/chapter12/booking_system/apis/userorders/api/wxauth_login.py +++ b/chapter12/booking_system/apis/userorders/api/wxauth_login.py @@ -3,42 +3,58 @@ from ..api import router_userorders from ..schemas import WxCodeForm from config.config import get_settings -from exts.wechatpy import WeChatClient, WeChatOAuth, WeChatOAuthException, WeChatException +from exts.wechatpy import ( + WeChatClient, + WeChatOAuth, + WeChatOAuthException, + WeChatException, +) def getWeChatOAuth(redirect_url): - return WeChatOAuth(get_settings().GZX_ID, get_settings().GZX_SECRET, redirect_url, 'snsapi_userinfo') + return WeChatOAuth( + get_settings().GZX_ID, + get_settings().GZX_SECRET, + redirect_url, + "snsapi_userinfo", + ) -@router_userorders.get("/login", summary='微信授权登入') +@router_userorders.get("/login", summary="微信授权登入") async def callbadk(*, forms: WxCodeForm = Depends(WxCodeForm)): wechat_oauth = None try: CODE = forms.code.strip() - wechat_oauth = getWeChatOAuth(redirect_url='') + wechat_oauth = getWeChatOAuth(redirect_url="") # 第二步:通过code换取网页授权access_token res_openid = wechat_oauth.fetch_access_token(CODE) except WeChatOAuthException as wcpayex: if not wcpayex.errcode: pass - return Fail(api_code=200, result=None, message='授权处理失败,原因:{}'.format(str(wcpayex.errmsg))) + return Fail( + api_code=200, + result=None, + message="授权处理失败,原因:{}".format(str(wcpayex.errmsg)), + ) except Exception as ex: - return Fail(api_code=200, result=None, message='授权处理失败,原因:未知异常的错误信息') + return Fail( + api_code=200, result=None, message="授权处理失败,原因:未知异常的错误信息" + ) user_info = wechat_oauth.get_user_info() # 正常的获取到用户信息 - openid = user_info.get('openid') - avatar_url = user_info.get('headimgurl') - city = user_info.get('city') - coutry = user_info.get('country') - nick_name = user_info.get('nickname') - province = user_info.get('province') - sex = '男' if user_info.get('sex') == 1 else '女' + openid = user_info.get("openid") + avatar_url = user_info.get("headimgurl") + city = user_info.get("city") + coutry = user_info.get("country") + nick_name = user_info.get("nickname") + province = user_info.get("province") + sex = "男" if user_info.get("sex") == 1 else "女" data = { "openid": openid, "nick_name": nick_name, "avatar_url": avatar_url, - "usex": sex + "usex": sex, } - return Success(api_code=200, result=data, message='获取成功') + return Success(api_code=200, result=data, message="获取成功") diff --git a/chapter12/booking_system/apis/userorders/repository/__init__.py b/chapter12/booking_system/apis/userorders/repository/__init__.py index fcb74e6..cbd7ed0 100644 --- a/chapter12/booking_system/apis/userorders/repository/__init__.py +++ b/chapter12/booking_system/apis/userorders/repository/__init__.py @@ -7,62 +7,86 @@ from typing import Optional - - - - class Serveries: @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno_olny(async_session: AsyncSession, dno, visit_uopenid, orderid, **updata): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny( + async_session: AsyncSession, dno, visit_uopenid, orderid, **updata + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(updata)) await async_session.commit() return result.rowcount @staticmethod - async def updata_order_info_byorder_dno_olny_dict(async_session: AsyncSession, dno, visit_uopenid, orderid, - updata={}): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny_dict( + async_session: AsyncSession, dno, visit_uopenid, orderid, updata={} + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(**updata)) await async_session.commit() return result.rowcount @staticmethod - async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSession, visit_uopenid, statue=1) -> list: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.dnname, - Doctorinfo.addr, - Doctorinfo.rank, - Doctorinfo.pic - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.statue == statue, - ) - - _subscribe_info_result:AsyncResult = await async_session.execute(query_subscribe_info) + async def get_order_info_list_by_visit_uopenid_select( + async_session: AsyncSession, visit_uopenid, statue=1 + ) -> list: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.dnname, + Doctorinfo.addr, + Doctorinfo.rank, + Doctorinfo.pic, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.statue == statue, + ) + ) + + _subscribe_info_result: AsyncResult = await async_session.execute( + query_subscribe_info + ) _rows = _subscribe_info_result.mappings() return [_row for _row in _rows] @@ -77,35 +101,41 @@ async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSessio # _rows = _subscribe_info_result.all() # return [item._mapping for item in _rows] - - - @staticmethod - async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSession, visit_uopenid, orderid, - dno) -> dict: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.addr, - Doctorinfo.dnname, - Doctorinfo.rank, - Doctorinfo.pic, - DoctorSubscribeinfo.create_time, - DoctorSubscribeinfo.visit_uname, - DoctorSubscribeinfo.visit_uphone, - DoctorSubscribeinfo.visit_usex, - DoctorSubscribeinfo.visit_uage, - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.dno == dno - ) + async def get_order_info_list_by_visit_uopenid_detailt( + async_session: AsyncSession, visit_uopenid, orderid, dno + ) -> dict: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.addr, + Doctorinfo.dnname, + Doctorinfo.rank, + Doctorinfo.pic, + DoctorSubscribeinfo.create_time, + DoctorSubscribeinfo.visit_uname, + DoctorSubscribeinfo.visit_uphone, + DoctorSubscribeinfo.visit_usex, + DoctorSubscribeinfo.visit_uage, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.dno == dno, + ) + ) _subscribe_info_result = await async_session.execute(query_subscribe_info) _row = _subscribe_info_result.first() return {} if not _row else _row._mapping @@ -129,14 +159,15 @@ async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSessi # } -if __name__ == '__main__': +if __name__ == "__main__": + async def sdsdf(): async with async_context_get_db() as session: - asdas = await Serveries.get_order_info_list_by_visit_uopenid_select(session, - visit_uopenid='orE7I59UwXdWzfSK9QGK2fHGtPZ8') + asdas = await Serveries.get_order_info_list_by_visit_uopenid_select( + session, visit_uopenid="orE7I59UwXdWzfSK9QGK2fHGtPZ8" + ) print(asdas) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter12/booking_system/apis/userorders/schemas/__init__.py b/chapter12/booking_system/apis/userorders/schemas/__init__.py index ad3861b..fb1607c 100644 --- a/chapter12/booking_system/apis/userorders/schemas/__init__.py +++ b/chapter12/booking_system/apis/userorders/schemas/__init__.py @@ -1,4 +1,3 @@ - from pydantic import BaseModel from fastapi import Depends, Query from pydantic.dataclasses import dataclass @@ -6,35 +5,38 @@ class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") + class UserOrderIonfoListForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - statue:int = None + statue: int = None class WxCodeForm(BaseModel): - code: str = Query(..., min_length=1,description="微信CODE") + code: str = Query(..., min_length=1, description="微信CODE") @dataclass class GetOrderinfos(BaseModel): - ''' + """ 连表查询出来的位置要字段要保持一致信息 - ''' + """ + orderid: str - statue:int - dno:str - visittime:str - visitday:str - visit_statue:int - dnname:str - addr:str - rank:str - pic:str + statue: int + dno: str + visittime: str + visitday: str + visit_statue: int + dnname: str + addr: str + rank: str + pic: str diff --git a/chapter12/booking_system/app.py b/chapter12/booking_system/app.py index 594183e..aaac432 100644 --- a/chapter12/booking_system/app.py +++ b/chapter12/booking_system/app.py @@ -2,20 +2,29 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) try: - app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") + app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" + ) except: pass -@app.get('/docs', include_in_schema=False) + +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -23,8 +32,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -50,33 +61,49 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.async_rabbit import async_rabbit_client + # 启动成功的后的回调 from exts.rabbit import sync_rabbit_client + async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange1' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue1' - order_dead_letter_routing_key = 'xz-dead-letter-queue1' - await async_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) + order_dead_letter_exchange_name = "xz-dead-letter-exchange1" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue1" + order_dead_letter_routing_key = "xz-dead-letter-queue1" + await async_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_dead_letter_queue_name + ) - await async_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - routing_key=order_dead_letter_routing_key) + await async_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange1' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue1' - order_routing_key = 'order_handler1' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await async_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await async_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, routing_key=order_routing_key) + order_exchange_name = "xz-order-exchange1" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue1" + order_routing_key = "order_handler1" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await async_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await async_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, routing_key=order_routing_key + ) + # async_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) @@ -86,32 +113,45 @@ def startup_callback_init_data_sync(): # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' - sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" + sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) - sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - queue_name = order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) + sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name,queue_name=order_queue_name,routing_key=order_routing_key) -#try: -# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) -#except: -# pass + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) +# try: +# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) +# except: +# pass def creat_app(): diff --git a/chapter12/booking_system/app_sync.py b/chapter12/booking_system/app_sync.py index 7b50432..4c20432 100644 --- a/chapter12/booking_system/app_sync.py +++ b/chapter12/booking_system/app_sync.py @@ -2,17 +2,25 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") -app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) +app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" +) -@app.get('/docs', include_in_schema=False) +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -20,8 +28,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -29,8 +39,11 @@ async def custom_swagger_ui_html(): # app.router.route_class = ContextLogerRoute # app.add_middleware(BindContextvarMiddleware) -from middlewares.loger.middleware import LogerMiddleware -app.add_middleware(LogerMiddleware,log_pro_path=os.path.split(os.path.realpath(__file__))[0]) +from middlewares.loger.middleware import LogerMiddleware + +app.add_middleware( + LogerMiddleware, log_pro_path=os.path.split(os.path.realpath(__file__))[0] +) from apis.hospital.api import router_hospital @@ -46,34 +59,55 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client + + # 启动成功的后的回调 async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" # 创建交换机 - await sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) # 设置队列 await sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) # 绑定交换机和队列 - await sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name,queue_name=order_dead_letter_queue_name,routing_key=order_dead_letter_routing_key) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, queue_name=order_queue_name, routing_key=order_routing_key) - -sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) + + +sync_rabbit_client.init_app( + app=app, rabbitconf=get_settings(), startup_callback=startup_callback_init_data +) + def creat_app(): return app diff --git a/chapter12/booking_system/config/config.py b/chapter12/booking_system/config/config.py index fa4cbb0..6fe2db1 100644 --- a/chapter12/booking_system/config/config.py +++ b/chapter12/booking_system/config/config.py @@ -1,6 +1,7 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # database = PostgresqlDatabase('guahaoxitong', **{'host': '47.99.189.42', 'port': 5432, @@ -26,25 +27,27 @@ class Settings(BaseSettings): DB_POOL_SIZE: int = 60 DB_MAX_OVERFLOW: int = 0 - #公众号-开发者ID(AppID) - GZX_ID: str = 'wx91df1c5a300ddc3d' # 微信公众号ID - #公众号-开发者密码 - GZX_SECRET:str = '1f484aa3403b7c867d13a5e10c193191' - GZX_PAY_KEY: str = '0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh' # 微信支付秘钥 - MCH_ID: str = '1613748420' # 微信支付ID - NOTIFY_URL = 'http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback' #支付回调 + # 公众号-开发者ID(AppID) + GZX_ID: str = "wx91df1c5a300ddc3d" # 微信公众号ID + # 公众号-开发者密码 + GZX_SECRET: str = "1f484aa3403b7c867d13a5e10c193191" + GZX_PAY_KEY: str = "0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh" # 微信支付秘钥 + MCH_ID: str = "1613748420" # 微信支付ID + NOTIFY_URL = ( + "http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback" # 支付回调 + ) # 没有值的情况下的默认值--默认情况下读取的环境变量的值 # 链接用户名 - RABBIT_USERNAME: str = 'admin' + RABBIT_USERNAME: str = "admin" # 链接密码 - RABBIT_PASSWORD: str = 'admin' + RABBIT_PASSWORD: str = "admin" # 链接的主机 - RABBIT_HOST: str = 'rabbit' + RABBIT_HOST: str = "rabbit" # 链接端口 RABBIT_PORT: int = 5672 # 要链接租户空间名称 - VIRTUAL_HOST: str = 'yuyueguahao' + VIRTUAL_HOST: str = "yuyueguahao" # 心跳检测 RABBIT_HEARTBEAT = 5 diff --git a/chapter12/booking_system/db/async_database.py b/chapter12/booking_system/db/async_database.py index 0f9517b..998bd26 100644 --- a/chapter12/booking_system/db/async_database.py +++ b/chapter12/booking_system/db/async_database.py @@ -8,27 +8,39 @@ from contextlib import asynccontextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings # 创建异步引擎对象 settings = get_settings() -async_engine = create_async_engine(url=URL.create(settings.ASYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +async_engine = create_async_engine( + url=URL.create( + settings.ASYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) # 创建异步的会话管理对象 -AsyncSessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession,autocommit=False,autoflush=False, future=False) +AsyncSessionLocal = sessionmaker( + bind=async_engine, + expire_on_commit=False, + class_=AsyncSession, + autocommit=False, + autoflush=False, + future=False, +) async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: @@ -48,7 +60,7 @@ async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: # 需要使用这个来装饰一下,才可以使用with @asynccontextmanager async def async_context_get_db() -> AsyncGenerator: - ''' + """ async def init() -> None: pass async with get_db() as session: @@ -60,7 +72,7 @@ async def init() -> None: # loop = asyncio.get_event_loop() # loop.run_until_complete(init()) :return: - ''' + """ session = AsyncSessionLocal() try: yield session diff --git a/chapter12/booking_system/db/models.py b/chapter12/booking_system/db/models.py index 4749ca8..1bf4496 100644 --- a/chapter12/booking_system/db/models.py +++ b/chapter12/booking_system/db/models.py @@ -1,76 +1,157 @@ # coding: utf-8 -from sqlalchemy import Column, Date, DateTime, Integer, SmallInteger, Text, UniqueConstraint, text,DECIMAL,Numeric +from sqlalchemy import ( + Column, + Date, + DateTime, + Integer, + SmallInteger, + Text, + UniqueConstraint, + text, + DECIMAL, + Numeric, +) from sqlalchemy.dialects.postgresql import TIMESTAMP from db.async_database import Base + metadata = Base.metadata class DoctorScheduling(Base): - __tablename__ = 'doctor_scheduling' - __table_args__ = {'comment': '医生排班信息表'} + __tablename__ = "doctor_scheduling" + __table_args__ = {"comment": "医生排班信息表"} + + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + nsnum = Column(Integer, comment="号源总数") + nsnumstock = Column(Integer, comment="号源库存数") + nsindex = Column( + Text, unique=True, server_default=text("''::text"), comment="号源编号" + ) + dnotime = Column(Date, comment="排班日期,年-月-日") + tiemampmstr = Column( + Text, server_default=text("''::text"), comment="号源时段字符串显示" + ) + ampm = Column( + Text, server_default=text("''::text"), comment="医生工作日:上午 还是 下午" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + enable = Column(Integer, comment="是否可用(1:是 0 否)") + tiempm = Column( + TIMESTAMP(precision=6), comment="医生工作日:号源时段(年-月-日 时:分)" + ) - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - nsnum = Column(Integer, comment='号源总数') - nsnumstock = Column(Integer, comment='号源库存数') - nsindex = Column(Text, unique=True, server_default=text("''::text"), comment='号源编号') - dnotime = Column(Date, comment='排班日期,年-月-日') - tiemampmstr = Column(Text, server_default=text("''::text"), comment='号源时段字符串显示') - ampm = Column(Text, server_default=text("''::text"), comment='医生工作日:上午 还是 下午') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - tiempm = Column(TIMESTAMP(precision=6), comment='医生工作日:号源时段(年-月-日 时:分)') class DoctorSubscribeinfo(Base): - __tablename__ = 'doctor_subscribeinfo' - __table_args__ = {'comment': '预约信息详情表'} + __tablename__ = "doctor_subscribeinfo" + __table_args__ = {"comment": "预约信息详情表"} - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - orderid = Column(Text, index=True, server_default=text("''::text"), comment='订单编号') - nsindex = Column(Text, server_default=text("''::text"), comment='订单编号') - statue = Column(Integer, server_default=text("1"), comment='订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单') - visitday = Column(Text, server_default=text("''::text"), comment='就诊日期') - visittime = Column(Text, server_default=text("''::text"), comment='就诊时段') - payfee = Column(Text, server_default=text("''::text"), comment='支付诊费') - visit_uopenid = Column(Text, server_default=text("''::text"), comment='就诊人微信ID') - visit_uname = Column(Text, server_default=text("''::text"), comment='就诊人姓名') - visit_uphone = Column(Text, server_default=text("''::text"), comment='就诊人联系电话') - visit_usex = Column(Text, server_default=text("''::text"), comment='就诊人性别') - visit_uage = Column(Text, server_default=text("''::text"), comment='就诊人年龄') - visit_statue = Column(Integer, server_default=text("1"), comment='订单所属-就诊状态(1:待就诊 2:已就诊)') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - notify_callback_time = Column(TIMESTAMP(precision=0), comment='支付回调时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + orderid = Column( + Text, index=True, server_default=text("''::text"), comment="订单编号" + ) + nsindex = Column(Text, server_default=text("''::text"), comment="订单编号") + statue = Column( + Integer, + server_default=text("1"), + comment="订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单", + ) + visitday = Column(Text, server_default=text("''::text"), comment="就诊日期") + visittime = Column(Text, server_default=text("''::text"), comment="就诊时段") + payfee = Column(Text, server_default=text("''::text"), comment="支付诊费") + visit_uopenid = Column( + Text, server_default=text("''::text"), comment="就诊人微信ID" + ) + visit_uname = Column(Text, server_default=text("''::text"), comment="就诊人姓名") + visit_uphone = Column( + Text, server_default=text("''::text"), comment="就诊人联系电话" + ) + visit_usex = Column(Text, server_default=text("''::text"), comment="就诊人性别") + visit_uage = Column(Text, server_default=text("''::text"), comment="就诊人年龄") + visit_statue = Column( + Integer, + server_default=text("1"), + comment="订单所属-就诊状态(1:待就诊 2:已就诊)", + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + notify_callback_time = Column(TIMESTAMP(precision=0), comment="支付回调时间") class Doctorinfo(Base): - __tablename__ = 'doctorinfo' - __table_args__ = {'comment': '医生信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('doctorinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, unique=True, server_default=text("''::text"), comment='医生编号') - dnname = Column(Text, server_default=text("''::text"), comment='医生名称') - dnmobile = Column(Text, server_default=text("''::text"), comment='医生号码') - sex = Column(Integer, comment='医生性别:1: 男 2: 女 3:保密') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - rank = Column(Text, server_default=text("''::text"), comment='职称') - fee = Column(Numeric, comment='医生诊费') - grade = Column(Text, server_default=text("''::text"), comment='等级') - destag = Column(Text, server_default=text("''::text"), comment='专业擅长标签') - addr = Column(Text, server_default=text("''::text"), comment='开诊地点') - pic = Column(Text, server_default=text("''::text"), comment='医生图片') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - describe = Column(Text, comment='说明信息') + __tablename__ = "doctorinfo" + __table_args__ = {"comment": "医生信息表"} -class Hospitalinfo(Base): - __tablename__ = 'hospitalinfo' - __table_args__ = {'comment': '医院信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), comment='主键Id') - name = Column(Text, server_default=text("''::text"), comment='医院名称') - describe = Column(Text, server_default=text("''::text"), comment='医院描述') - describeimages = Column(Text, server_default=text("''::text"), comment='describeimages') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctorinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + unique=True, + server_default=text("''::text"), + comment="医生编号", + ) + dnname = Column(Text, server_default=text("''::text"), comment="医生名称") + dnmobile = Column(Text, server_default=text("''::text"), comment="医生号码") + sex = Column(Integer, comment="医生性别:1: 男 2: 女 3:保密") + enable = Column(Integer, comment="是否可用(1:是 0 否)") + rank = Column(Text, server_default=text("''::text"), comment="职称") + fee = Column(Numeric, comment="医生诊费") + grade = Column(Text, server_default=text("''::text"), comment="等级") + destag = Column(Text, server_default=text("''::text"), comment="专业擅长标签") + addr = Column(Text, server_default=text("''::text"), comment="开诊地点") + pic = Column(Text, server_default=text("''::text"), comment="医生图片") + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + describe = Column(Text, comment="说明信息") +class Hospitalinfo(Base): + __tablename__ = "hospitalinfo" + __table_args__ = {"comment": "医院信息表"} + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), + comment="主键Id", + ) + name = Column(Text, server_default=text("''::text"), comment="医院名称") + describe = Column(Text, server_default=text("''::text"), comment="医院描述") + describeimages = Column( + Text, server_default=text("''::text"), comment="describeimages" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) diff --git a/chapter12/booking_system/db/sync_database.py b/chapter12/booking_system/db/sync_database.py index 8e30c82..072840d 100644 --- a/chapter12/booking_system/db/sync_database.py +++ b/chapter12/booking_system/db/sync_database.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings from sqlalchemy import create_engine @@ -14,20 +15,29 @@ metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) -sync_engine = create_engine(url=URL.create(settings.SYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +sync_engine = create_engine( + url=URL.create( + settings.SYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) # 创建异步的会话管理对象 -SyncSessionLocal = sessionmaker(bind=sync_engine, expire_on_commit=False, autocommit=False, autoflush=False, - future=False) +SyncSessionLocal = sessionmaker( + bind=sync_engine, + expire_on_commit=False, + autocommit=False, + autoflush=False, + future=False, +) def depends_get_db_session(): @@ -56,20 +66,32 @@ def sync_context_get_db(): session.close() -if __name__ == '__main__': - from db.models import Hospitalinfo,DoctorSubscribeinfo +if __name__ == "__main__": + from db.models import Hospitalinfo, DoctorSubscribeinfo from sqlalchemy.sql import and_ with sync_context_get_db() as session: - ed_user = Hospitalinfo(name='ed', describe='Ed Jones', describeimages='edsnickname') + ed_user = Hospitalinfo( + name="ed", describe="Ed Jones", describeimages="edsnickname" + ) session.add(ed_user) - _result:DoctorSubscribeinfo = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).one_or_none() + _result: DoctorSubscribeinfo = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ) + .one_or_none() + ) print(_result.dno) - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).update( - {DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) \ No newline at end of file + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) diff --git a/chapter12/booking_system/exts/async_rabbit/__init__.py b/chapter12/booking_system/exts/async_rabbit/__init__.py index bd0a144..46598c3 100644 --- a/chapter12/booking_system/exts/async_rabbit/__init__.py +++ b/chapter12/booking_system/exts/async_rabbit/__init__.py @@ -32,35 +32,56 @@ async def shutdown_event(): await self._clear_all() async def init_sync_rabbit(self, rabbitconf): - self.connection = await aio_pika.connect_robust(host=rabbitconf.RABBIT_HOST, - port=rabbitconf.RABBIT_PORT, - virtualhost=rabbitconf.VIRTUAL_HOST, - login=rabbitconf.RABBIT_USERNAME, - loop=asyncio.get_event_loop(), - password=rabbitconf.RABBIT_PASSWORD - ) + self.connection = await aio_pika.connect_robust( + host=rabbitconf.RABBIT_HOST, + port=rabbitconf.RABBIT_PORT, + virtualhost=rabbitconf.VIRTUAL_HOST, + login=rabbitconf.RABBIT_USERNAME, + loop=asyncio.get_event_loop(), + password=rabbitconf.RABBIT_PASSWORD, + ) # channel_number: int = None, # publisher_confirms: bool = True, # on_return_raises: bool = False, - self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel(publisher_confirms=False) - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' + self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel( + publisher_confirms=False + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" # if auto_delete and durable is None: # durable = False - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,auto_delete=False,durable=durable) - - - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - self.queue = await self.channel.declare_queue(name=queue_name, durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, auto_delete=False, durable=durable + ) + + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" await self.queue.bind(exchange=exchange_name, routing_key=routing_key) - - async def send_basic_publish(self, routing_key, body, content_type="text/plain", content_encoding='utf-8', - message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 try: @@ -71,20 +92,17 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", expiration=message_ttl * 1000, content_type=content_type, content_encoding=content_encoding, - delivery_mode=delivery_mode + delivery_mode=delivery_mode, ), routing_key=routing_key, ) else: await self.exchange.publish( - Message( - bytes(body, "utf-8"), - delivery_mode=delivery_mode - ), + Message(bytes(body, "utf-8"), delivery_mode=delivery_mode), routing_key=routing_key, ) except UnroutableError: - print('消息发送失败') + print("消息发送失败") async def _close_connect(self): """ @@ -100,13 +118,13 @@ async def _close_channel(self): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") await self.channel.close() async def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" await self._close_connect() self.connection = None diff --git a/chapter12/booking_system/exts/exceptions/__init__.py b/chapter12/booking_system/exts/exceptions/__init__.py index 57d9d64..ecbfd6c 100644 --- a/chapter12/booking_system/exts/exceptions/__init__.py +++ b/chapter12/booking_system/exts/exceptions/__init__.py @@ -14,9 +14,15 @@ from fastapi import FastAPI, Request from starlette.exceptions import HTTPException as StarletteHTTPException from fastapi.exceptions import RequestValidationError -from exts.responses.json_response import InternalErrorException, \ - MethodnotallowedException, \ - NotfoundException, LimiterResException, BadrequestException, ParameterException, Businesserror +from exts.responses.json_response import ( + InternalErrorException, + MethodnotallowedException, + NotfoundException, + LimiterResException, + BadrequestException, + ParameterException, + Businesserror, +) from enum import Enum @@ -32,9 +38,14 @@ class ExceptionEnum(Enum): class BusinessError(Exception): - __slots__ = ['err_code', 'err_code_des'] + __slots__ = ["err_code", "err_code_des"] - def __init__(self, result: ExceptionEnum = None, err_code: str = "0000", err_code_des: str = ""): + def __init__( + self, + result: ExceptionEnum = None, + err_code: str = "0000", + err_code_des: str = "", + ): if result: self.err_code = result.value[0] self.err_code_des = err_code_des or result.value[1] @@ -52,24 +63,36 @@ def __init__(self, app=None, *args, **kwargs): def init_app(self, app: FastAPI): app.add_exception_handler(Exception, handler=self.all_exception_handler) - app.add_exception_handler(StarletteHTTPException, handler=self.http_exception_handler) + app.add_exception_handler( + StarletteHTTPException, handler=self.http_exception_handler + ) app.add_exception_handler(BusinessError, handler=self.all_businesserror_handler) - app.add_exception_handler(RequestValidationError, handler=self.validation_exception_handler) + app.add_exception_handler( + RequestValidationError, handler=self.validation_exception_handler + ) - async def validation_exception_handler(self, request: Request, exc: RequestValidationError): - return ParameterException(http_status_code=400, api_code=400, message='参数校验错误', result={ - "detail": exc.errors(), - "body": exc.body - }) + async def validation_exception_handler( + self, request: Request, exc: RequestValidationError + ): + return ParameterException( + http_status_code=400, + api_code=400, + message="参数校验错误", + result={"detail": exc.errors(), "body": exc.body}, + ) async def all_businesserror_handler(self, request: Request, exc: BusinessError): - return Businesserror(http_status_code=200, api_code=exc.err_code, message=exc.err_code_des) + return Businesserror( + http_status_code=200, api_code=exc.err_code, message=exc.err_code_des + ) async def all_exception_handler(self, request: Request, exc: Exception): return InternalErrorException() - async def http_exception_handler(self, request: Request, exc: StarletteHTTPException): + async def http_exception_handler( + self, request: Request, exc: StarletteHTTPException + ): if exc.status_code == 405: return MethodnotallowedException() if exc.status_code == 404: diff --git a/chapter12/booking_system/exts/logururoute/__init__.py b/chapter12/booking_system/exts/logururoute/__init__.py index 8deed65..76eaf24 100644 --- a/chapter12/booking_system/exts/logururoute/__init__.py +++ b/chapter12/booking_system/exts/logururoute/__init__.py @@ -13,7 +13,7 @@ from time import perf_counter from fastapi.routing import APIRoute -from typing import Callable, List, Dict,Optional +from typing import Callable, List, Dict, Optional from fastapi.responses import Response import shortuuid from datetime import datetime @@ -28,7 +28,8 @@ from fastapi.responses import StreamingResponse from exts.requestvar import request -__all__ = ("setup_ext_loguru", "ContextLogerRoute") +__all__ = ("setup_ext_loguru", "ContextLogerRoute") + class ContextLogerRoute(APIRoute): # 再静态的里面使用self来查询也可以,遵循从内到外的查询 @@ -41,11 +42,15 @@ class ContextLogerRoute(APIRoute): def filter_request_url(self): path_info = request.url.path # 过滤不需要记录日志请求地址URL - return path_info not in ['/favicon.ico'] and 'websocket' not in path_info and request.method != 'OPTIONS' + return ( + path_info not in ["/favicon.ico"] + and "websocket" not in path_info + and request.method != "OPTIONS" + ) - def filter_response_context(self,response: Response): + def filter_response_context(self, response: Response): # 过滤不需要记录日志响应体内容信息L - return 'image' not in response.media_type and hasattr(request.state, 'traceid') + return "image" not in response.media_type and hasattr(request.state, "traceid") async def make_request_start_time(self): pass @@ -55,7 +60,7 @@ async def make_request_start_time(self): # 计算时间 request.state.start_time = perf_counter() - async def make_request_log_msg(self)->Dict: + async def make_request_log_msg(self) -> Dict: log_msg = None if self.filter_request_url(): ip, method, url = request.client.host, request.method, request.url.path @@ -69,14 +74,14 @@ async def make_request_log_msg(self)->Dict: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass # 在这里记录下当前提交的body的数据,用于下文的提取 @@ -96,59 +101,75 @@ async def make_request_log_msg(self)->Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - async def before_request_record_loger(self,log_msg=None): + async def before_request_record_loger(self, log_msg=None): if self.filter_request_url() and log_msg: - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) - async def after_request_record_loger(self, response: Response): + async def after_request_record_loger(self, response: Response): if self.filter_response_context(response=response): - start_time = getattr(request.state, 'start_time') - end_time = f'{(perf_counter() - start_time):.2f}' + start_time = getattr(request.state, "start_time") + end_time = f"{(perf_counter() - start_time):.2f}" # 获取响应报文信息内容 rsp = None if not isinstance(response, StreamingResponse): if isinstance(response, Response): - rsp = str(response.body, encoding='utf-8') + rsp = str(response.body, encoding="utf-8") try: rsp = json_helper.json_to_dict(rsp) except: @@ -156,12 +177,12 @@ async def after_request_record_loger(self, response: Response): log_msg = { # 记录请求耗时 "status_code": response.status_code, - 'cost_time': end_time, + "cost_time": end_time, # 记录请求响应的最终报文信息--eval的作用是去除相关的 转义符号 "\"ok\""===》ok - 'rsp': rsp, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "rsp": rsp, + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - await async_trace_add_log_record(event_type='response', msg=log_msg) + await async_trace_add_log_record(event_type="response", msg=log_msg) async def teardown_requestcontext(self, request: Request, response: Response): pass @@ -192,44 +213,44 @@ async def custom_route_handler(request: Request) -> Response: return custom_route_handler - - - -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str( - getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - - - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) diff --git a/chapter12/booking_system/exts/logururoute/config.py b/chapter12/booking_system/exts/logururoute/config.py index 809ad95..b3aa37f 100644 --- a/chapter12/booking_system/exts/logururoute/config.py +++ b/chapter12/booking_system/exts/logururoute/config.py @@ -4,10 +4,10 @@ def setup_ext_loguru(app: FastAPI, log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ @app.on_event("startup") async def startup(): @@ -16,33 +16,52 @@ async def startup(): def init_loguru_handlers(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: # BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(log_file_path, format=format2, rotation='00:00', compression="zip", encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file \ No newline at end of file + logger.add( + log_file_path, + format=format2, + rotation="00:00", + compression="zip", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file diff --git a/chapter12/booking_system/exts/rabbit/__init__.py b/chapter12/booking_system/exts/rabbit/__init__.py index 7b5a3c9..4adb1c4 100644 --- a/chapter12/booking_system/exts/rabbit/__init__.py +++ b/chapter12/booking_system/exts/rabbit/__init__.py @@ -30,48 +30,81 @@ def shutdown_event(): self._clear_all() def init_sync_rabbit(self, rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() - @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - - self.channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type, durable=durable) + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + + self.channel.exchange_declare( + exchange=exchange_name, exchange_type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - '''创建队列''' + def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + """创建队列""" pass - self.channel.queue_declare(queue=queue_name, durable=durable, auto_delete=auto_delete, arguments=arguments) + self.channel.queue_declare( + queue=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + ) def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" pass - self.channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) + self.channel.queue_bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='', - content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -100,10 +133,11 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha message_id = str(uuid.uuid4()) if is_delay: - properties = pika.BasicProperties(content_type=content_type, - content_encoding=content_encoding, - delivery_mode=delivery_mode, - ) + properties = pika.BasicProperties( + content_type=content_type, + content_encoding=content_encoding, + delivery_mode=delivery_mode, + ) # expiration 字段以毫秒为单位表示 TTL 值,6 秒的 message properties.expiration = f"{message_ttl * 1000}" # 秒 self.channel.basic_publish( @@ -114,7 +148,7 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 发送的消息的内容 body=body, # 发现的消息的类型 - properties=properties + properties=properties, # pika.BasicProperties中的delivery_mode=2指明message为持久的,1 的话 表示不是持久化 2:表示持久化 ) else: @@ -124,13 +158,13 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 默认的匹配的key routing_key=routing_key, # 发送的消息的内容 - body=body + body=body, ) else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -150,13 +184,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None diff --git a/chapter12/booking_system/exts/rabbit2/__init__.py b/chapter12/booking_system/exts/rabbit2/__init__.py index a6bc476..907dc3d 100644 --- a/chapter12/booking_system/exts/rabbit2/__init__.py +++ b/chapter12/booking_system/exts/rabbit2/__init__.py @@ -17,63 +17,95 @@ def __init__(self, app: FastAPI = None): if app is not None: self.init_app(app, None, None) - def init_app(self, app: FastAPI,rabbitconf,startup_callback): + def init_app(self, app: FastAPI, rabbitconf, startup_callback): self.app = app + @app.on_event("startup") def startup_event(): self.init_sync_rabbit(rabbitconf) # 初始化回调 startup_callback() + @app.on_event("shutdown") def shutdown_event(): self._clear_all() - - def init_sync_rabbit(self,rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + def init_sync_rabbit(self, rabbitconf): + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' - - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,durable=durable) - + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" + + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - - - self.queue = await self.channel.declare_queue(name=queue_name,durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' - await self.queue.bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) - - + """同伙routing_key把交换机和队列的绑定""" + await self.queue.bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - async def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='',content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -88,14 +120,14 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", # mandatory: bool = True, # immediate: bool = False, # timeout: TimeoutType = None - await self.exchange.publish(message, routing_key=routing_key) + await self.exchange.publish(message, routing_key=routing_key) else: - pass + pass else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -115,13 +147,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None @@ -131,4 +163,4 @@ def _clear_all(self): self.channel = None -sync_rabbit_client = RabbitMQClintWithLock() \ No newline at end of file +sync_rabbit_client = RabbitMQClintWithLock() diff --git a/chapter12/booking_system/exts/requestvar/__init__.py b/chapter12/booking_system/exts/requestvar/__init__.py index 2f50ac3..c786445 100644 --- a/chapter12/booking_system/exts/requestvar/__init__.py +++ b/chapter12/booking_system/exts/requestvar/__init__.py @@ -3,12 +3,13 @@ import shortuuid from exts.requestvar.bing import bind_contextvar from starlette.types import ASGIApp, Receive, Scope, Send + request_var: ContextVar[Request] = ContextVar("request") request: Request = bind_contextvar(request_var) + class BindContextvarMiddleware: - def __init__( - self, app: ASGIApp) -> None: + def __init__(self, app: ASGIApp) -> None: self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: diff --git a/chapter12/booking_system/exts/responses/__init__.py b/chapter12/booking_system/exts/responses/__init__.py index f1c6644..1b80a76 100644 --- a/chapter12/booking_system/exts/responses/__init__.py +++ b/chapter12/booking_system/exts/responses/__init__.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/9/23 ------------------------------------------------- - 修改描述-2021/9/23: + 修改描述-2021/9/23: ------------------------------------------------- """ from . import json_response diff --git a/chapter12/booking_system/exts/responses/json_response.py b/chapter12/booking_system/exts/responses/json_response.py index 0a59c3e..5abd98f 100644 --- a/chapter12/booking_system/exts/responses/json_response.py +++ b/chapter12/booking_system/exts/responses/json_response.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/7/15 ------------------------------------------------- - 修改描述-2021/7/15: + 修改描述-2021/7/15: ------------------------------------------------- """ @@ -23,26 +23,30 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) elif isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") elif isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") elif isinstance(obj, datetime.time): return obj.isoformat() elif isinstance(obj, decimal.Decimal): return float(obj) elif isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") elif isinstance(obj.__class__, DeclarativeMeta): # 如果是查询返回所有的那种models类型的,需要处理些 # 将SqlAlchemy结果序列化为JSON--查询全部的时候的处理返回 - return self.default({i.name: getattr(obj, i.name) for i in obj.__table__.columns}) + return self.default( + {i.name: getattr(obj, i.name) for i in obj.__table__.columns} + ) elif isinstance(obj, dict): for k in obj: try: - if isinstance(obj[k], (datetime.datetime, datetime.date, DeclarativeMeta)): + if isinstance( + obj[k], (datetime.datetime, datetime.date, DeclarativeMeta) + ): obj[k] = self.default(obj[k]) else: obj[k] = obj[k] @@ -59,11 +63,19 @@ class ApiResponse(JSONResponse): api_code = 0 # 默认Node.如果是必选的,去掉默认值即可 result: Optional[Dict[str, Any]] = None # 结果可以是{} 或 [] - message = '成功' + message = "成功" success = True timestamp = int(time.time() * 1000) - def __init__(self, success=None, http_status_code=None, api_code=None, result=None, message=None, **options): + def __init__( + self, + success=None, + http_status_code=None, + api_code=None, + result=None, + message=None, + **options + ): self.message = message or self.message self.api_code = api_code or self.api_code self.success = success or self.success @@ -76,9 +88,11 @@ def __init__(self, success=None, http_status_code=None, api_code=None, result=No code=self.api_code, success=self.success, result=self.result, - timestamp=self.timestamp + timestamp=self.timestamp, + ) + super(ApiResponse, self).__init__( + status_code=self.http_status_code, content=body, **options ) - super(ApiResponse, self).__init__(status_code=self.http_status_code, content=body, **options) # 这个render会自动调用,如果这里需要特殊的处理的话,可以重写这个地方 def render(self, content: typing.Any) -> bytes: @@ -88,7 +102,7 @@ def render(self, content: typing.Any) -> bytes: allow_nan=False, indent=None, separators=(",", ":"), - cls=CJsonEncoder + cls=CJsonEncoder, ).encode("utf-8") @@ -96,7 +110,7 @@ class BadrequestException(ApiResponse): http_status_code = 400 api_code = 10031 result = None # 结果可以是{} 或 [] - message = '错误的请求' + message = "错误的请求" success = False @@ -104,14 +118,14 @@ class LimiterResException(ApiResponse): http_status_code = 429 api_code = 429 result = None # 结果可以是{} 或 [] - message = '访问的速度过快' + message = "访问的速度过快" success = False class ParameterException(ApiResponse): http_status_code = 400 result = {} - message = '参数校验错误,请检查提交的参数信息' + message = "参数校验错误,请检查提交的参数信息" api_code = 10031 success = False @@ -119,7 +133,7 @@ class ParameterException(ApiResponse): class UnauthorizedException(ApiResponse): http_status_code = 401 result = {} - message = '未经许可授权' + message = "未经许可授权" api_code = 10032 success = False @@ -127,7 +141,7 @@ class UnauthorizedException(ApiResponse): class ForbiddenException(ApiResponse): http_status_code = 403 result = {} - message = '失败!当前访问没有权限,或操作的数据没权限!' + message = "失败!当前访问没有权限,或操作的数据没权限!" api_code = 10033 success = False @@ -135,7 +149,7 @@ class ForbiddenException(ApiResponse): class NotfoundException(ApiResponse): http_status_code = 404 result = {} - message = '访问地址不存在' + message = "访问地址不存在" api_code = 10034 success = False @@ -143,7 +157,7 @@ class NotfoundException(ApiResponse): class MethodnotallowedException(ApiResponse): http_status_code = 405 result = {} - message = '不允许使用此方法提交访问' + message = "不允许使用此方法提交访问" api_code = 10034 success = False @@ -151,7 +165,7 @@ class MethodnotallowedException(ApiResponse): class OtherException(ApiResponse): http_status_code = 800 result = {} - message = '未知的其他HTTPEOOER异常' + message = "未知的其他HTTPEOOER异常" api_code = 10034 success = False @@ -159,7 +173,7 @@ class OtherException(ApiResponse): class InternalErrorException(ApiResponse): http_status_code = 200 result = {} - message = '程序员哥哥睡眠不足,系统崩溃了!' + message = "程序员哥哥睡眠不足,系统崩溃了!" api_code = 200 success = False @@ -167,13 +181,13 @@ class InternalErrorException(ApiResponse): class InvalidTokenException(ApiResponse): http_status_code = 401 api_code = 401 - message = '很久没操作,令牌失效' + message = "很久没操作,令牌失效" success = False class ExpiredTokenException(ApiResponse): http_status_code = 422 - message = '很久没操作,令牌过期' + message = "很久没操作,令牌过期" api_code = 10050 success = False @@ -182,19 +196,19 @@ class FileTooLargeException(ApiResponse): http_status_code = 413 api_code = 413 result = None # 结果可以是{} 或 [] - message = '文件体积过大' + message = "文件体积过大" class FileTooManyException(ApiResponse): http_status_code = 413 - message = '文件数量过多' + message = "文件数量过多" api_code = 10120 result = None # 结果可以是{} 或 [] class FileExtensionException(ApiResponse): http_status_code = 401 - message = '文件扩展名不符合规范' + message = "文件扩展名不符合规范" api_code = 10121 result = None # 结果可以是{} 或 [] @@ -203,16 +217,15 @@ class Success(ApiResponse): http_status_code = 200 api_code = 200 result = None # 结果可以是{} 或 [] - message = '获取成功' + message = "获取成功" success = True - class Businesserror(ApiResponse): http_status_code = 200 - api_code = '0000' + api_code = "0000" result = None # 结果可以是{} 或 [] - message = '业务错误逻辑处理' + message = "业务错误逻辑处理" success = False @@ -220,5 +233,5 @@ class Fail(ApiResponse): http_status_code = 200 api_code = -1 result = None # 结果可以是{} 或 [] - message = '操作失败' + message = "操作失败" success = False diff --git a/chapter12/booking_system/exts/wechatpy/__init__.py b/chapter12/booking_system/exts/wechatpy/__init__.py index 61c0ac9..24ea439 100644 --- a/chapter12/booking_system/exts/wechatpy/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/__init__.py @@ -4,21 +4,28 @@ from exts.wechatpy.client import WeChatClient # NOQA from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA -from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA +from exts.wechatpy.exceptions import ( + WeChatClientException, + WeChatException, + WeChatOAuthException, + WeChatPayException, +) # NOQA from exts.wechatpy.oauth import WeChatOAuth # NOQA from exts.wechatpy.parser import parse_message # NOQA from exts.wechatpy.pay import WeChatPay # NOQA from exts.wechatpy.replies import create_reply # NOQA -__version__ = '1.8.2' -__author__ = 'messense' +__version__ = "1.8.2" +__author__ = "messense" # Set default logging handler to avoid "No handler found" warnings. try: # Python 2.7+ from logging import NullHandler except ImportError: + class NullHandler(logging.Handler): def emit(self, record): pass + logging.getLogger(__name__).addHandler(NullHandler()) diff --git a/chapter12/booking_system/exts/wechatpy/_compat.py b/chapter12/booking_system/exts/wechatpy/_compat.py index 2306499..87376ce 100644 --- a/chapter12/booking_system/exts/wechatpy/_compat.py +++ b/chapter12/booking_system/exts/wechatpy/_compat.py @@ -1,21 +1,24 @@ # -*- coding: utf-8 -*- """ - wechatpy._compat - ~~~~~~~~~~~~~~~~~ +wechatpy._compat +~~~~~~~~~~~~~~~~~ - This module makes it easy for wechatpy to run on both Python 2 and 3. +This module makes it easy for wechatpy to run on both Python 2 and 3. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import sys import six import warnings -warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" - "use `wechatpy.utils` instead", - DeprecationWarning, stacklevel=2) +warnings.warn( + "Module `wechatpy._compat` is deprecated, will be removed in 2.0" + "use `wechatpy.utils` instead", + DeprecationWarning, + stacklevel=2, +) from exts.wechatpy.utils import get_querystring from exts.wechatpy.utils import json diff --git a/chapter12/booking_system/exts/wechatpy/client/__init__.py b/chapter12/booking_system/exts/wechatpy/client/__init__.py index 18040c0..bcb4f00 100644 --- a/chapter12/booking_system/exts/wechatpy/client/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/client/__init__.py @@ -8,13 +8,12 @@ class WeChatClient(BaseWeChatClient): - """ 微信 API 操作类 通过这个类可以操作微信 API,发送主动消息、群发消息和创建自定义菜单等。 """ - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin/" # API_BASE_URL = 'http://47.99.189.42:30005/cgi-bin/' card = api.WeChatCard() @@ -42,8 +41,15 @@ class WeChatClient(BaseWeChatClient): wxa = api.WeChatWxa() marketing = api.WeChatMarketing() - def __init__(self, appid, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + appid, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( appid, access_token, session, timeout, auto_retry ) @@ -58,27 +64,31 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ return self._fetch_access_token( - url='https://api.weixin.qq.com/cgi-bin/token', + url="https://api.weixin.qq.com/cgi-bin/token", params={ - 'grant_type': 'client_credential', - 'appid': self.appid, - 'secret': self.secret - } + "grant_type": "client_credential", + "appid": self.appid, + "secret": self.secret, + }, ) class WeChatComponentClient(WeChatClient): - """ 开放平台代公众号调用客户端 """ - def __init__(self, appid, component, access_token=None, - refresh_token=None, session=None, timeout=None): + def __init__( + self, + appid, + component, + access_token=None, + refresh_token=None, + session=None, + timeout=None, + ): # 未用到secret,所以这里没有 - super(WeChatComponentClient, self).__init__( - appid, '', '', session, timeout - ) + super(WeChatComponentClient, self).__init__(appid, "", "", session, timeout) self.appid = appid self.component = component # 如果公众号是刚授权,外部还没有缓存access_token和refresh_token @@ -86,18 +96,20 @@ def __init__(self, appid, component, access_token=None, # 如果外部已经缓存,这里只需要传入 appid,component和session即可 cache_access_token = self.session.get(self.access_token_key) - if access_token and (not cache_access_token or cache_access_token != access_token): + if access_token and ( + not cache_access_token or cache_access_token != access_token + ): self.session.set(self.access_token_key, access_token, 7200) if refresh_token: self.session.set(self.refresh_token_key, refresh_token) @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) @property def refresh_token_key(self): - return '{0}_refresh_token'.format(self.appid) + return "{0}_refresh_token".format(self.appid) @property def access_token(self): @@ -123,14 +135,11 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ expires_in = 7200 - result = self.component.refresh_authorizer_token( - self.appid, self.refresh_token) - if 'expires_in' in result: - expires_in = result['expires_in'] + result = self.component.refresh_authorizer_token(self.appid, self.refresh_token) + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - self.access_token_key, - result['authorizer_access_token'], - expires_in + self.access_token_key, result["authorizer_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result diff --git a/chapter12/booking_system/exts/wechatpy/client/api/base.py b/chapter12/booking_system/exts/wechatpy/client/api/base.py index 10bbec4..66cb918 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/base.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/base.py @@ -3,21 +3,21 @@ class BaseWeChatAPI(object): - """ WeChat API base class """ + """WeChat API base class""" def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL - print("当前URL",url) + print("当前URL", url) return self._client.post(url, **kwargs) @property diff --git a/chapter12/booking_system/exts/wechatpy/client/api/card.py b/chapter12/booking_system/exts/wechatpy/client/api/card.py index 9dcb398..7b1b399 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/card.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/card.py @@ -6,7 +6,7 @@ class WeChatCard(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create(self, card_data): """ @@ -16,9 +16,7 @@ def create(self, card_data): :return: 创建的卡券 ID """ result = self._post( - 'card/create', - data=card_data, - result_processor=lambda x: x['card_id'] + "card/create", data=card_data, result_processor=lambda x: x["card_id"] ) return result @@ -30,9 +28,9 @@ def batch_add_locations(self, location_data): :return: 门店 ID 列表,插入失败的门店元素值为 -1 """ result = self._post( - 'card/location/batchadd', + "card/location/batchadd", data=location_data, - result_processor=lambda x: x['location_id_list'] + result_processor=lambda x: x["location_id_list"], ) return result @@ -41,11 +39,7 @@ def batch_get_locations(self, offset=0, count=0): 批量获取门店信息 """ return self._post( - 'card/location/batchget', - data={ - 'offset': offset, - 'count': count - } + "card/location/batchget", data={"offset": offset, "count": count} ) def get_colors(self): @@ -53,10 +47,7 @@ def get_colors(self): 获得卡券的最新颜色列表,用于创建卡券 :return: 颜色列表 """ - result = self._get( - 'card/getcolors', - result_processor=lambda x: x['colors'] - ) + result = self._get("card/getcolors", result_processor=lambda x: x["colors"]) return result def create_qrcode(self, qrcode_data): @@ -67,9 +58,9 @@ def create_qrcode(self, qrcode_data): :return: 二维码 ticket,可使用 :func:show_qrcode 换取二维码文件 """ result = self._post( - 'card/qrcode/create', + "card/qrcode/create", data=qrcode_data, - result_processor=lambda x: x['ticket'] + result_processor=lambda x: x["ticket"], ) return result @@ -77,10 +68,7 @@ def create_landingpage(self, buffer_data): """ 创建货架 """ - result = self._post( - 'card/landingpage/create', - data=buffer_data - ) + result = self._post("card/landingpage/create", data=buffer_data) return result def get_html(self, card_id): @@ -88,11 +76,9 @@ def get_html(self, card_id): 图文消息群发卡券 """ result = self._post( - 'card/mpnews/gethtml', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['content'] + "card/mpnews/gethtml", + data={"card_id": card_id}, + result_processor=lambda x: x["content"], ) return result @@ -100,26 +86,19 @@ def consume_code(self, code, card_id=None): """ 消耗 code """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/consume', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/consume", data=card_data) def decrypt_code(self, encrypt_code): """ 解码加密的 code """ result = self._post( - 'card/code/decrypt', - data={ - 'encrypt_code': encrypt_code - }, - result_processor=lambda x: x['code'] + "card/code/decrypt", + data={"encrypt_code": encrypt_code}, + result_processor=lambda x: x["code"], ) return result @@ -127,68 +106,43 @@ def delete(self, card_id): """ 删除卡券 """ - return self._post( - 'card/delete', - data={ - 'card_id': card_id - } - ) + return self._post("card/delete", data={"card_id": card_id}) def get_code(self, code, card_id=None, check_consume=True): """ 查询 code 信息 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id + card_data["card_id"] = card_id if not check_consume: - card_data['check_consume'] = check_consume - return self._post( - 'card/code/get', - data=card_data - ) + card_data["check_consume"] = check_consume + return self._post("card/code/get", data=card_data) def get_card_list(self, openid, card_id=None): """ 用于获取用户卡包里的,属于该appid下的卡券。 """ - card_data = { - 'openid': openid - } + card_data = {"openid": openid} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/order/getcardlist', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/order/getcardlist", data=card_data) def batch_get(self, offset=0, count=50, status_list=None): """ 批量查询卡券信息 """ - card_data = { - 'offset': offset, - 'count': count - } + card_data = {"offset": offset, "count": count} if status_list: - card_data['status_list'] = status_list - return self._post( - 'card/batchget', - data=card_data - ) + card_data["status_list"] = status_list + return self._post("card/batchget", data=card_data) def get(self, card_id): """ 查询卡券详情 """ result = self._post( - 'card/get', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['card'] + "card/get", data={"card_id": card_id}, result_processor=lambda x: x["card"] ) return result @@ -197,47 +151,31 @@ def update_code(self, card_id, old_code, new_code): 更新卡券 code """ return self._post( - 'card/code/update', - data={ - 'card_id': card_id, - 'code': old_code, - 'new_code': new_code - } + "card/code/update", + data={"card_id": card_id, "code": old_code, "new_code": new_code}, ) def invalid_code(self, code, card_id=None): """ 设置卡券失效 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/unavailable', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/unavailable", data=card_data) def update(self, card_data): """ 更新卡券信息 """ - return self._post( - 'card/update', - data=card_data - ) + return self._post("card/update", data=card_data) def set_paycell(self, card_id, is_open): """ 更新卡券信息 """ return self._post( - 'card/paycell/set', - data={ - 'card_id': card_id, - 'is_open': is_open - } + "card/paycell/set", data={"card_id": card_id, "is_open": is_open} ) def set_test_whitelist(self, openids=None, usernames=None): @@ -247,11 +185,7 @@ def set_test_whitelist(self, openids=None, usernames=None): openids = openids or [] usernames = usernames or [] return self._post( - 'card/testwhitelist/set', - data={ - 'openid': openids, - 'username': usernames - } + "card/testwhitelist/set", data={"openid": openids, "username": usernames} ) def activate_membercard(self, membership_number, code, **kwargs): @@ -282,12 +216,9 @@ def activate_membercard(self, membership_number, code, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “6 激活会员卡” 部分 :return: 参见返回示例 """ - kwargs['membership_number'] = membership_number - kwargs['code'] = code - return self._post( - 'card/membercard/activate', - data=kwargs - ) + kwargs["membership_number"] = membership_number + kwargs["code"] = code + return self._post("card/membercard/activate", data=kwargs) def update_membercard(self, code, card_id, **kwargs): """ @@ -334,14 +265,13 @@ def update_membercard(self, code, card_id, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “7 更新会员信息” 部分 :return: 参见返回示例 """ - kwargs.update({ - 'code': code, - 'card_id': card_id, - }) - return self._post( - 'card/membercard/updateuser', - data=kwargs + kwargs.update( + { + "code": code, + "card_id": card_id, + } ) + return self._post("card/membercard/updateuser", data=kwargs) def get_membercard_user_info(self, card_id, code): """ @@ -354,10 +284,10 @@ def get_membercard_user_info(self, card_id, code): :return: 会员信息,包括激活资料、积分信息以及余额等信息 """ return self._post( - 'card/membercard/userinfo/get', + "card/membercard/userinfo/get", data={ - 'card_id': card_id, - 'code': code, + "card_id": card_id, + "code": code, }, ) @@ -376,20 +306,20 @@ def add_pay_giftcard(self, base_info, extra_info, is_membercard): :return: 规则 ID, 设置成功的列表,以及设置失败的列表 """ if is_membercard: - rule_key = 'member_rule' - rule_type = 'RULE_TYPE_PAY_MEMBER_CARD' + rule_key = "member_rule" + rule_type = "RULE_TYPE_PAY_MEMBER_CARD" else: - rule_key = 'single_pay' - rule_type = 'RULE_TYPE_SINGLE_PAY' + rule_key = "single_pay" + rule_type = "RULE_TYPE_SINGLE_PAY" return self._post( - 'card/paygiftcard/add', + "card/paygiftcard/add", data={ - 'rule_info': { - 'type': rule_type, - 'base_info': base_info, + "rule_info": { + "type": rule_type, + "base_info": base_info, rule_key: extra_info, } - } + }, ) def del_pay_giftcard(self, rule_id): @@ -401,9 +331,9 @@ def del_pay_giftcard(self, rule_id): :param rule_id: 支付即会员的规则 ID """ return self._post( - 'card/paygiftcard/delete', + "card/paygiftcard/delete", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, ) @@ -418,11 +348,11 @@ def get_pay_giftcard(self, rule_id): :rtype: dict """ return self._post( - 'card/paygiftcard/getbyid', + "card/paygiftcard/getbyid", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, - result_processor=lambda x: x['rule_info'], + result_processor=lambda x: x["rule_info"], ) def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): @@ -441,75 +371,81 @@ def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): :return: 支付后投放卡券规则的总数,以及查询到的列表 """ return self._post( - 'card/paygiftcard/batchget', + "card/paygiftcard/batchget", data={ - 'type': 'RULE_TYPE_PAY_MEMBER_CARD', - 'effective': effective, - 'offset': offset, - 'count': count, + "type": "RULE_TYPE_PAY_MEMBER_CARD", + "effective": effective, + "offset": offset, + "count": count, }, ) - def update_movie_ticket(self, code, ticket_class, show_time, duration, - screening_room, seat_number, card_id=None): + def update_movie_ticket( + self, + code, + ticket_class, + show_time, + duration, + screening_room, + seat_number, + card_id=None, + ): """ 更新电影票 """ ticket = { - 'code': code, - 'ticket_class': ticket_class, - 'show_time': show_time, - 'duration': duration, - 'screening_room': screening_room, - 'seat_number': seat_number + "code": code, + "ticket_class": ticket_class, + "show_time": show_time, + "duration": duration, + "screening_room": screening_room, + "seat_number": seat_number, } if card_id: - ticket['card_id'] = card_id - return self._post( - 'card/movieticket/updateuser', - data=ticket - ) - - def checkin_boardingpass(self, code, passenger_name, seat_class, - etkt_bnr, seat='', gate='', boarding_time=None, - is_cancel=False, qrcode_data=None, card_id=None): + ticket["card_id"] = card_id + return self._post("card/movieticket/updateuser", data=ticket) + + def checkin_boardingpass( + self, + code, + passenger_name, + seat_class, + etkt_bnr, + seat="", + gate="", + boarding_time=None, + is_cancel=False, + qrcode_data=None, + card_id=None, + ): """ 飞机票接口 """ data = { - 'code': code, - 'passenger_name': passenger_name, - 'class': seat_class, - 'etkt_bnr': etkt_bnr, - 'seat': seat, - 'gate': gate, - 'is_cancel': is_cancel + "code": code, + "passenger_name": passenger_name, + "class": seat_class, + "etkt_bnr": etkt_bnr, + "seat": seat, + "gate": gate, + "is_cancel": is_cancel, } if boarding_time: - data['boarding_time'] = boarding_time + data["boarding_time"] = boarding_time if qrcode_data: - data['qrcode_data'] = qrcode_data + data["qrcode_data"] = qrcode_data if card_id: - data['card_id'] = card_id - return self._post( - 'card/boardingpass/checkin', - data=data - ) + data["card_id"] = card_id + return self._post("card/boardingpass/checkin", data=data) def update_luckymoney_balance(self, code, balance, card_id=None): """ 更新红包余额 """ - card_data = { - 'code': code, - 'balance': balance - } + card_data = {"code": code, "balance": balance} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/luckymoney/updateuserbalance', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/luckymoney/updateuserbalance", data=card_data) def get_redirect_url(self, url, encrypt_code, card_id): """ @@ -525,51 +461,33 @@ def get_redirect_url(self, url, encrypt_code, card_id): signer.add_data(card_id) signature = signer.signature - r = '{url}?encrypt_code={code}&card_id={card_id}&signature={signature}' + r = "{url}?encrypt_code={code}&card_id={card_id}&signature={signature}" return r.format( - url=url, - code=encrypt_code, - card_id=card_id, - signature=signature + url=url, code=encrypt_code, card_id=card_id, signature=signature ) def deposit_code(self, card_id, codes): """ 导入code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/deposit', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/deposit", data=card_data) def get_deposit_count(self, card_id): """ 查询导入code数目 """ card_data = { - 'card_id': card_id, + "card_id": card_id, } - return self._post( - 'card/code/getdepositcount', - data=card_data - ) + return self._post("card/code/getdepositcount", data=card_data) def check_code(self, card_id, codes): """ 核查code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/checkcode', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/checkcode", data=card_data) def modify_stock(self, card_id, n): """ @@ -578,16 +496,13 @@ def modify_stock(self, card_id, n): if n == 0: return card_data = { - 'card_id': card_id, + "card_id": card_id, } if n > 0: - card_data['increase_stock_value'] = n + card_data["increase_stock_value"] = n elif n < 0: - card_data['reduce_stock_value'] = -n - return self._post( - 'card/modifystock', - data=card_data - ) + card_data["reduce_stock_value"] = -n + return self._post("card/modifystock", data=card_data) def get_activate_url(self, card_id, outer_str=None): """ @@ -600,12 +515,12 @@ def get_activate_url(self, card_id, outer_str=None): :return: 内含调用开卡插件所需的参数的 Url """ return self._post( - 'card/membercard/activate/geturl', + "card/membercard/activate/geturl", data={ - 'card_id': card_id, - 'outer_str': outer_str, + "card_id": card_id, + "outer_str": outer_str, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_activate_info(self, activate_ticket): @@ -618,11 +533,11 @@ def get_activate_info(self, activate_ticket): :return: 用户开卡时填写的字段值 """ return self._post( - 'card/membercard/activatetempinfo/get', + "card/membercard/activatetempinfo/get", data={ - 'activate_ticket': activate_ticket, + "activate_ticket": activate_ticket, }, - result_processor=lambda x: x['info'], + result_processor=lambda x: x["info"], ) def set_activate_user_form(self, card_id, **kwargs): @@ -693,8 +608,5 @@ def set_activate_user_form(self, card_id, **kwargs): :param card_id: 卡券ID :param kwargs: 其他非必填参数,见微信文档 """ - kwargs['card_id'] = card_id - return self._post( - 'card/membercard/activateuserform/set', - data=kwargs - ) + kwargs["card_id"] = card_id + return self._post("card/membercard/activateuserform/set", data=kwargs) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/customservice.py b/chapter12/booking_system/exts/wechatpy/client/api/customservice.py index a5c2471..89d0cc4 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/customservice.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/customservice.py @@ -26,12 +26,8 @@ def add_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/add', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/add", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def update_account(self, account, nickname, password): @@ -48,12 +44,8 @@ def update_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/update', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/update", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def delete_account(self, account): @@ -66,13 +58,12 @@ def delete_account(self, account): :return: 返回的 JSON 数据包 """ params_data = [ - 'access_token={0}'.format(quote(self.access_token)), - 'kf_account={0}'.format(quote(to_binary(account), safe=b'/@')), + "access_token={0}".format(quote(self.access_token)), + "kf_account={0}".format(quote(to_binary(account), safe=b"/@")), ] - params = '&'.join(params_data) + params = "&".join(params_data) return self._get( - 'https://api.weixin.qq.com/customservice/kfaccount/del', - params=params + "https://api.weixin.qq.com/customservice/kfaccount/del", params=params ) def get_accounts(self): @@ -84,8 +75,7 @@ def get_accounts(self): :return: 客服账号列表 """ res = self._get( - 'customservice/getkflist', - result_processor=lambda x: x['kf_list'] + "customservice/getkflist", result_processor=lambda x: x["kf_list"] ) return res @@ -100,13 +90,9 @@ def upload_headimg(self, account, media_file): :return: 返回的 JSON 数据包 """ return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg', - params={ - 'kf_account': account - }, - files={ - 'media': media_file - } + "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg", + params={"kf_account": account}, + files={"media": media_file}, ) def get_online_accounts(self): @@ -118,8 +104,8 @@ def get_online_accounts(self): :return: 客服接待信息列表 """ res = self._get( - 'customservice/getonlinekflist', - result_processor=lambda x: x['kf_online_list'] + "customservice/getonlinekflist", + result_processor=lambda x: x["kf_online_list"], ) return res @@ -134,14 +120,9 @@ def create_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/create', - data=data + "https://api.weixin.qq.com/customservice/kfsession/create", data=data ) def close_session(self, openid, account, text=None): @@ -155,14 +136,9 @@ def close_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/close', - data=data + "https://api.weixin.qq.com/customservice/kfsession/close", data=data ) def get_session(self, openid): @@ -175,8 +151,8 @@ def get_session(self, openid): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsession', - params={'openid': openid} + "https://api.weixin.qq.com/customservice/kfsession/getsession", + params={"openid": openid}, ) def get_session_list(self, account): @@ -189,9 +165,9 @@ def get_session_list(self, account): :return: 客服的会话列表 """ res = self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsessionlist', - params={'kf_account': account}, - result_processor=lambda x: x['sessionlist'] + "https://api.weixin.qq.com/customservice/kfsession/getsessionlist", + params={"kf_account": account}, + result_processor=lambda x: x["sessionlist"], ) return res @@ -204,11 +180,10 @@ def get_wait_case(self): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getwaitcase' + "https://api.weixin.qq.com/customservice/kfsession/getwaitcase" ) - def get_records(self, start_time, end_time, msgid=1, - number=10000): + def get_records(self, start_time, end_time, msgid=1, number=10000): """ 获取客服聊天记录 @@ -224,13 +199,13 @@ def get_records(self, start_time, end_time, msgid=1, if isinstance(end_time, datetime.datetime): end_time = time.mktime(end_time.timetuple()) record_data = { - 'starttime': int(start_time), - 'endtime': int(end_time), - 'msgid': msgid, - 'number': number + "starttime": int(start_time), + "endtime": int(end_time), + "msgid": msgid, + "number": number, } res = self._post( - 'https://api.weixin.qq.com/customservice/msgrecord/getmsglist', + "https://api.weixin.qq.com/customservice/msgrecord/getmsglist", data=record_data, ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/datacube.py b/chapter12/booking_system/exts/wechatpy/client/api/datacube.py index ef80f89..d4fafac 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/datacube.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/datacube.py @@ -9,16 +9,16 @@ class WeChatDataCube(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/datacube/' + API_BASE_URL = "https://api.weixin.qq.com/datacube/" @classmethod def _to_date_str(cls, date): if isinstance(date, (datetime.datetime, datetime.date)): - return date.strftime('%Y-%m-%d') + return date.strftime("%Y-%m-%d") elif isinstance(date, six.string_types): return date else: - raise ValueError('Can not convert %s type to str', type(date)) + raise ValueError("Can not convert %s type to str", type(date)) def get_user_summary(self, begin_date, end_date): """ @@ -31,13 +31,13 @@ def get_user_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersummary', + "getusersummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) - } + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), + }, ) - return res['list'] + return res["list"] def get_user_cumulate(self, begin_date, end_date): """ @@ -50,12 +50,12 @@ def get_user_cumulate(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusercumulate', + "getusercumulate", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -70,12 +70,12 @@ def get_interface_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummary', + "getinterfacesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -90,12 +90,12 @@ def get_interface_summary_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummaryhour', + "getinterfacesummaryhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -110,12 +110,12 @@ def get_article_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticlesummary', + "getarticlesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -130,12 +130,12 @@ def get_article_total(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticletotal', + "getarticletotal", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -150,12 +150,12 @@ def get_user_read(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserread', + "getuserread", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -170,12 +170,12 @@ def get_user_read_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserreadhour', + "getuserreadhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -190,12 +190,12 @@ def get_user_share(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusershare', + "getusershare", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -210,12 +210,12 @@ def get_user_share_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersharehour', + "getusersharehour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -230,12 +230,12 @@ def get_upstream_msg(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsg', + "getupstreammsg", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -250,12 +250,12 @@ def get_upstream_msg_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsghour', + "getupstreammsghour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -270,12 +270,12 @@ def get_upstream_msg_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgweek', + "getupstreammsgweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -290,12 +290,12 @@ def get_upstream_msg_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgmonth', + "getupstreammsgmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -310,12 +310,12 @@ def get_upstream_msg_dist(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdist', + "getupstreammsgdist", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -330,12 +330,12 @@ def get_upstream_msg_dist_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistweek', + "getupstreammsgdistweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -350,11 +350,11 @@ def get_upstream_msg_dist_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistmonth', + "getupstreammsgdistmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/device.py b/chapter12/booking_system/exts/wechatpy/client/api/device.py index 01aecb2..be27851 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/device.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/device.py @@ -9,7 +9,7 @@ class WeChatDevice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/device/' + API_BASE_URL = "https://api.weixin.qq.com/device/" def send_message(self, device_type, device_id, user_id, content): """ @@ -25,16 +25,18 @@ def send_message(self, device_type, device_id, user_id, content): """ content = to_text(base64.b64encode(to_binary(content))) return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'content': content - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "content": content, + }, ) - def send_status_message(self, device_type, device_id, user_id, msg_type, device_status): + def send_status_message( + self, device_type, device_id, user_id, msg_type, device_status + ): """ 第三方主动发送设备状态消息给微信终端 详情请参考 @@ -48,14 +50,14 @@ def send_status_message(self, device_type, device_id, user_id, msg_type, device_ :return: 返回的 JSON 数据包 """ return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'msg_type': msg_type, - 'device_status': device_status, - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "msg_type": msg_type, + "device_status": device_status, + }, ) def create_qrcode(self, device_ids): @@ -68,11 +70,8 @@ def create_qrcode(self, device_ids): :return: 返回的 JSON 数据包 """ return self._post( - 'create_qrcode', - data={ - 'device_num': len(device_ids), - 'device_id_list': device_ids - } + "create_qrcode", + data={"device_num": len(device_ids), "device_id_list": device_ids}, ) def get_qrcode_url(self, ticket, data=None): @@ -85,12 +84,12 @@ def get_qrcode_url(self, ticket, data=None): :param data: 额外数据 :return: 二维码地址 """ - url = 'https://we.qq.com/d/{ticket}'.format(ticket=ticket) + url = "https://we.qq.com/d/{ticket}".format(ticket=ticket) if data: if isinstance(data, (dict, tuple, list)): data = urllib.urlencode(data) data = to_text(base64.b64encode(to_binary(data))) - url = '{base}#{data}'.format(base=url, data=data) + url = "{base}#{data}".format(base=url, data=data) return url def bind(self, ticket, device_id, user_id): @@ -105,12 +104,7 @@ def bind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'bind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "bind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def unbind(self, ticket, device_id, user_id): @@ -125,12 +119,7 @@ def unbind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'unbind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "unbind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def compel_bind(self, device_id, user_id): @@ -144,11 +133,7 @@ def compel_bind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_bind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_bind", data={"device_id": device_id, "openid": user_id} ) force_bind = compel_bind @@ -164,11 +149,7 @@ def compel_unbind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_unbind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_unbind", data={"device_id": device_id, "openid": user_id} ) force_unbind = compel_unbind @@ -182,10 +163,7 @@ def get_stat(self, device_id): :param device_id: 设备id :return: 返回的 JSON 数据包 """ - return self._get( - 'get_stat', - params={'device_id': device_id} - ) + return self._get("get_stat", params={"device_id": device_id}) def verify_qrcode(self, ticket): """ @@ -196,10 +174,7 @@ def verify_qrcode(self, ticket): :param ticket: 设备二维码的ticket :return: 返回的 JSON 数据包 """ - return self._post( - 'verify_qrcode', - data={'ticket': ticket} - ) + return self._post("verify_qrcode", data={"ticket": ticket}) def get_user_id(self, device_type, device_id): """ @@ -212,11 +187,7 @@ def get_user_id(self, device_type, device_id): :return: 返回的 JSON 数据包 """ return self._get( - 'get_openid', - params={ - 'device_type': device_type, - 'device_id': device_id - } + "get_openid", params={"device_type": device_type, "device_id": device_id} ) get_open_id = get_user_id @@ -230,10 +201,7 @@ def get_binded_devices(self, user_id): :param user_id: 要查询的用户的openid :return: 返回的 JSON 数据包 """ - return self._get( - 'get_bind_device', - params={'openid': user_id} - ) + return self._get("get_bind_device", params={"openid": user_id}) get_bind_device = get_binded_devices @@ -246,12 +214,12 @@ def get_qrcode(self, product_id=1): :param product_id: 设备的产品编号 :return: 返回的 JSON 数据包 """ - if product_id == '1' or product_id == 1: + if product_id == "1" or product_id == 1: params = None else: - params = {'product_id': product_id} + params = {"product_id": product_id} - return self._get('getqrcode', params=params) + return self._get("getqrcode", params=params) def authorize(self, devices, op_type=1): """ @@ -264,10 +232,10 @@ def authorize(self, devices, op_type=1): :return: 返回的 JSON 数据包 """ return self._post( - 'authorize_device', + "authorize_device", data={ - 'device_num': len(devices), - 'device_list': devices, - 'op_type': op_type - } + "device_num": len(devices), + "device_list": devices, + "op_type": op_type, + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/group.py b/chapter12/booking_system/exts/wechatpy/client/api/group.py index a3e5927..6dc4e94 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/group.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/group.py @@ -26,10 +26,7 @@ def create(self, name): """ name = to_text(name) - return self._post( - 'groups/create', - data={'group': {'name': name}} - ) + return self._post("groups/create", data={"group": {"name": name}}) def get(self, user_id=None): """ @@ -50,15 +47,12 @@ def get(self, user_id=None): """ if user_id is None: - res = self._get( - 'groups/get', - result_processor=lambda x: x['groups'] - ) + res = self._get("groups/get", result_processor=lambda x: x["groups"]) else: res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -83,13 +77,7 @@ def update(self, group_id, name): """ name = to_text(name) return self._post( - 'groups/update', - data={ - 'group': { - 'id': int(group_id), - 'name': name - } - } + "groups/update", data={"group": {"id": int(group_id), "name": name}} ) def move_user(self, user_id, group_id): @@ -111,13 +99,13 @@ def move_user(self, user_id, group_id): res = client.group.move_user('openid', 1234) """ - data = {'to_groupid': group_id} + data = {"to_groupid": group_id} if isinstance(user_id, (tuple, list)): - endpoint = 'groups/members/batchupdate' - data['openid_list'] = user_id + endpoint = "groups/members/batchupdate" + data["openid_list"] = user_id else: - endpoint = 'groups/members/update' - data['openid'] = user_id + endpoint = "groups/members/update" + data["openid"] = user_id return self._post(endpoint, data=data) def delete(self, group_id): @@ -138,11 +126,4 @@ def delete(self, group_id): res = client.group.delete(1234) """ - return self._post( - 'groups/delete', - data={ - 'group': { - 'id': group_id - } - } - ) + return self._post("groups/delete", data={"group": {"id": group_id}}) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/invoice.py b/chapter12/booking_system/exts/wechatpy/client/api/invoice.py index f0182d5..b2808c2 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/invoice.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/invoice.py @@ -5,7 +5,7 @@ class WeChatInvoice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/card/invoice/' + API_BASE_URL = "https://api.weixin.qq.com/card/invoice/" def get_url(self): """ @@ -16,9 +16,9 @@ def get_url(self): :return:该开票平台专用的授权链接 """ return self._post( - 'seturl', + "seturl", data={}, - result_processor=lambda x: x['invoice_url'], + result_processor=lambda x: x["invoice_url"], ) def create_card(self, base_info, payee, invoice_type, detail=None): @@ -36,19 +36,29 @@ def create_card(self, base_info, payee, invoice_type, detail=None): :return: 发票卡券模板的编号,用于后续该商户发票生成后,作为必填参数在调用插卡接口时传入 """ return self._post( - 'platform/createcard', + "platform/createcard", data={ - 'invoice_info': { - 'base_info': base_info, - 'payee': payee, - 'type': invoice_type, - 'detail': detail, + "invoice_info": { + "base_info": base_info, + "payee": payee, + "type": invoice_type, + "detail": detail, }, }, - result_processor=lambda x: x['card_id'], + result_processor=lambda x: x["card_id"], ) - def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, auth_type, redirect_url=None): + def get_auth_url( + self, + s_pappid, + order_id, + money, + timestamp, + source, + ticket, + auth_type, + redirect_url=None, + ): """ 获取授权页链接 详情请参考 @@ -67,25 +77,27 @@ def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, aut :param redirect_url: 授权成功后跳转页面。本字段只有在source为H5的时候需要填写。 :return: 获取授权页链接 """ - if source not in {'app', 'web', 'wap'}: - raise ValueError('Unsupported source. Valid sources are "app", "web" or "wap"') - if source == 'web' and redirect_url is None: - raise ValueError('redirect_url is required if source is web') + if source not in {"app", "web", "wap"}: + raise ValueError( + 'Unsupported source. Valid sources are "app", "web" or "wap"' + ) + if source == "web" and redirect_url is None: + raise ValueError("redirect_url is required if source is web") if not (0 <= auth_type <= 2): - raise ValueError('Unsupported auth type. Valid auth types are 0, 1 or 2') + raise ValueError("Unsupported auth type. Valid auth types are 0, 1 or 2") return self._post( - 'getauthurl', + "getauthurl", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'money': money, - 'timestamp': timestamp, - 'source': source, - 'ticket': ticket, - 'type': auth_type, - 'redirect_url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "money": money, + "timestamp": timestamp, + "source": source, + "ticket": ticket, + "type": auth_type, + "redirect_url": redirect_url, }, - result_processor=lambda x: x['auth_url'], + result_processor=lambda x: x["auth_url"], ) def set_auth_field(self, user_field, biz_field): @@ -100,14 +112,14 @@ def set_auth_field(self, user_field, biz_field): :type biz_field: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_auth_field', + "action": "set_auth_field", }, data={ - 'auth_field': { - 'user_field': user_field, - 'biz_field': biz_field, + "auth_field": { + "user_field": user_field, + "biz_field": biz_field, }, }, ) @@ -122,9 +134,9 @@ def get_auth_field(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_auth_field', + "action": "get_auth_field", }, data={}, ) @@ -141,10 +153,10 @@ def get_auth_data(self, s_pappid, order_id): :rtype: dict """ return self._post( - 'getauthdata', + "getauthdata", data={ - 's_pappid': s_pappid, - 'order_id': order_id, + "s_pappid": s_pappid, + "order_id": order_id, }, ) @@ -160,12 +172,12 @@ def reject_insert(self, s_pappid, order_id, reason, redirect_url=None): :param redirect_url: 跳转链接 """ return self._post( - 'rejectinsert', + "rejectinsert", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'reason': reason, - 'url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "reason": reason, + "url": redirect_url, }, ) @@ -183,12 +195,12 @@ def insert(self, order_id, card_id, appid, card_ext): :return: 随机防重字符串,以及用户 Open ID """ return self._post( - 'insert', + "insert", data={ - 'order_id': order_id, - 'card_id': card_id, - 'appid': appid, - 'card_ext': card_ext, + "order_id": order_id, + "card_id": card_id, + "appid": appid, + "card_ext": card_ext, }, ) @@ -202,11 +214,11 @@ def upload_pdf(self, pdf): :return: 64位整数,在将发票卡券插入用户卡包时使用用于关联pdf和发票卡券。有效期为3天。 """ return self._post( - 'platform/setpdf', + "platform/setpdf", files={ - 'pdf': pdf, + "pdf": pdf, }, - result_processor=lambda x: x['s_media_id'], + result_processor=lambda x: x["s_media_id"], ) def get_pdf(self, s_media_id): @@ -220,12 +232,12 @@ def get_pdf(self, s_media_id): :rtype: dict """ return self._post( - 'platform/getpdf', + "platform/getpdf", params={ - 'action': 'get_url', + "action": "get_url", }, data={ - 's_media_id': s_media_id, + "s_media_id": s_media_id, }, ) @@ -240,11 +252,11 @@ def update_status(self, card_id, code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'platform/updatestatus', + "platform/updatestatus", data={ - 'card_id': card_id, - 'code': code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "code": code, + "reimburse_status": reimburse_status, }, ) @@ -258,14 +270,14 @@ def set_pay_mch(self, mchid, s_pappid): :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供 """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_pay_mch', + "action": "set_pay_mch", }, data={ - 'paymch_info': { - 'mchid': mchid, - 's_pappid': s_pappid, + "paymch_info": { + "mchid": mchid, + "s_pappid": s_pappid, }, }, ) @@ -280,9 +292,9 @@ def get_pay_mch(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_pay_mch', + "action": "get_pay_mch", }, data={}, ) @@ -299,10 +311,10 @@ def get_reimburse(self, card_id, encrypt_code): :rtype: dict """ return self._post( - 'reimburse/getinvoiceinfo', + "reimburse/getinvoiceinfo", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, + "card_id": card_id, + "encrypt_code": encrypt_code, }, ) @@ -317,11 +329,11 @@ def update_reimburse(self, card_id, encrypt_code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'reimburse/updateinvoicestatus', + "reimburse/updateinvoicestatus", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "encrypt_code": encrypt_code, + "reimburse_status": reimburse_status, }, ) @@ -337,17 +349,25 @@ def batch_update_reimburse(self, openid, reimburse_status, invoice_list): :type invoice_list: list[dict] """ return self._post( - 'reimburse/updatestatusbatch', + "reimburse/updatestatusbatch", data={ - 'openid': openid, - 'reimburse_status': reimburse_status, - 'invoice_list': invoice_list, + "openid": openid, + "reimburse_status": reimburse_status, + "invoice_list": invoice_list, }, ) def get_user_title_url( - self, user_fill, title=None, phone=None, tax_no=None, addr=None, bank_type=None, bank_no=None, - out_title_id=None): + self, + user_fill, + title=None, + phone=None, + tax_no=None, + addr=None, + bank_type=None, + bank_no=None, + out_title_id=None, + ): """ 获取添加发票链接 获取链接,发送给用户。用户同意以后,发票抬头信息将会录入到用户微信中 @@ -366,20 +386,20 @@ def get_user_title_url( :return: 添加发票的链接 """ if user_fill and title is None: - raise ValueError('title is required when user_fill is False') + raise ValueError("title is required when user_fill is False") return self._post( - 'biz/getusertitleurl', + "biz/getusertitleurl", data={ - 'user_fill': int(user_fill), - 'title': title, - 'phone': phone, - 'tax_no': tax_no, - 'addr': addr, - 'bank_type': bank_type, - 'bank_no': bank_no, - 'out_title_id': out_title_id, + "user_fill": int(user_fill), + "title": title, + "phone": phone, + "tax_no": tax_no, + "addr": addr, + "bank_type": bank_type, + "bank_no": bank_no, + "out_title_id": out_title_id, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_select_title_url(self, attach=None): @@ -393,11 +413,11 @@ def get_select_title_url(self, attach=None): :return: 商户专属开票链接 """ return self._post( - 'biz/getselecttitleurl', + "biz/getselecttitleurl", data={ - 'attach': attach, + "attach": attach, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def scan_title(self, scan_text): @@ -412,8 +432,8 @@ def scan_title(self, scan_text): :rtype: dict """ return self._post( - 'scantitle', + "scantitle", data={ - 'scan_text': scan_text, + "scan_text": scan_text, }, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/jsapi.py b/chapter12/booking_system/exts/wechatpy/client/api/jsapi.py index 0bbcd5c..d7db0b9 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/jsapi.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/jsapi.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.client.jsapi - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.client.jsapi +~~~~~~~~~~~~~~~~~~~~ - This module provides some APIs for JS SDK +This module provides some APIs for JS SDK - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -19,16 +19,13 @@ class WeChatJSAPI(BaseWeChatAPI): - def get_ticket(self, type='jsapi'): + def get_ticket(self, type="jsapi"): """ 获取微信 JS-SDK ticket :return: 返回的 JSON 数据包 """ - return self._get( - 'ticket/getticket', - params={'type': type} - ) + return self._get("ticket/getticket", params={"type": type}) def get_jsapi_ticket(self): """ @@ -38,14 +35,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{0}_jsapi_ticket'.format(self.appid) - expires_at_key = '{0}_jsapi_ticket_expires_at'.format(self.appid) + ticket_key = "{0}_jsapi_ticket".format(self.appid) + expires_at_key = "{0}_jsapi_ticket_expires_at".format(self.appid) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): - jsapi_ticket_response = self.get_ticket('jsapi') - ticket = jsapi_ticket_response['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket_response['expires_in']) + jsapi_ticket_response = self.get_ticket("jsapi") + ticket = jsapi_ticket_response["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket_response["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -61,12 +58,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -78,15 +75,17 @@ def get_jsapi_card_ticket(self): :return: ticket """ - jsapi_card_ticket_key = '{0}_jsapi_card_ticket'.format(self.appid) - jsapi_card_ticket_expire_at_key = '{0}_jsapi_card_ticket_expires_at'.format(self.appid) + jsapi_card_ticket_key = "{0}_jsapi_card_ticket".format(self.appid) + jsapi_card_ticket_expire_at_key = "{0}_jsapi_card_ticket_expires_at".format( + self.appid + ) ticket = self.session.get(jsapi_card_ticket_key) expires_at = self.session.get(jsapi_card_ticket_expire_at_key, 0) if not ticket or int(expires_at) < int(time.time()): - ticket_response = self.get_ticket('wx_card') - ticket = ticket_response['ticket'] - expires_at = int(time.time()) + int(ticket_response['expires_in']) + ticket_response = self.get_ticket("wx_card") + ticket = ticket_response["ticket"] + expires_at = int(time.time()) + int(ticket_response["expires_in"]) self.session.set(jsapi_card_ticket_key, ticket) self.session.set(jsapi_card_ticket_expire_at_key, expires_at) return ticket @@ -95,18 +94,18 @@ def get_jsapi_card_params(self, card_ticket, card_type, **kwargs): """ 参数意义见微信文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html :param card_ticket: 用于卡券的微信 api_ticket - :param card_type: + :param card_type: :param kwargs: 非必须参数:noncestr, timestamp, code, openid, fixed_begintimestamp, outer_str :return: 包含调用jssdk所有所需参数的 dict """ card_signature_dict = { - 'card_type': card_type, - 'noncestr': kwargs.get('noncestr', random_string()), - 'api_ticket': card_ticket, - 'appid': self.appid, - 'timestamp': kwargs.get('timestamp', str(int(time.time()))), + "card_type": card_type, + "noncestr": kwargs.get("noncestr", random_string()), + "api_ticket": card_ticket, + "appid": self.appid, + "timestamp": kwargs.get("timestamp", str(int(time.time()))), } list_before_sign = sorted([str(x) for x in card_signature_dict.values()]) str_to_sign = "".join(list_before_sign).encode() - card_signature_dict['sign'] = hashlib.sha1(str_to_sign).hexdigest() + card_signature_dict["sign"] = hashlib.sha1(str_to_sign).hexdigest() return card_signature_dict diff --git a/chapter12/booking_system/exts/wechatpy/client/api/marketing.py b/chapter12/booking_system/exts/wechatpy/client/api/marketing.py index 4aa9461..5192f8a 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/marketing.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/marketing.py @@ -10,9 +10,9 @@ class WeChatMarketing(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/marketing/' + API_BASE_URL = "https://api.weixin.qq.com/marketing/" - def add_user_action_sets(self, _type, name, description, version='v1.0'): + def add_user_action_sets(self, _type, name, description, version="v1.0"): """ 创建数据源 https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 @@ -24,18 +24,15 @@ def add_user_action_sets(self, _type, name, description, version='v1.0'): :return: 数据源唯一ID """ return self._post( - 'user_action_sets/add', - params={'version': version}, + "user_action_sets/add", + params={"version": version}, json=optionaldict( - type=_type, - name=name, - description=description, - version=version + type=_type, name=name, description=description, version=version ), - result_processor=lambda x: x['data']['user_action_set_id'] + result_processor=lambda x: x["data"]["user_action_set_id"], ) - def get_user_action_sets(self, user_action_set_id, version='v1.0'): + def get_user_action_sets(self, user_action_set_id, version="v1.0"): """ 获取数据源信息 @@ -43,12 +40,12 @@ def get_user_action_sets(self, user_action_set_id, version='v1.0'): :param version: 版本号 v1.0 """ return self._get( - 'user_action_sets/get', - params={'version': version, 'user_action_set_id': user_action_set_id}, - result_processor=lambda x: x['data']['list'] + "user_action_sets/get", + params={"version": version, "user_action_set_id": user_action_set_id}, + result_processor=lambda x: x["data"]["list"], ) - def add_user_actions(self, actions=(), version='v1.0'): + def add_user_actions(self, actions=(), version="v1.0"): """ 回传数据 @@ -58,12 +55,18 @@ def add_user_actions(self, actions=(), version='v1.0'): :param version: 版本号 v1.0 """ return self._post( - 'user_actions/add', - params={'version': version}, - json={'actions': actions} + "user_actions/add", params={"version": version}, json={"actions": actions} ) - def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, page_size=100, version='v1.0'): + def get_ad_leads( + self, + start_date=None, + end_date=None, + filtering=(), + page=1, + page_size=100, + version="v1.0", + ): """ 获取朋友圈销售线索数据接口 @@ -85,13 +88,13 @@ def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, pag end_date = end_date.strftime("%Y-%m-%d") return self._get( - 'wechat_ad_leads/get', + "wechat_ad_leads/get", params=optionaldict( - date_range=json.dumps({'start_date': start_date, 'end_date': end_date}), + date_range=json.dumps({"start_date": start_date, "end_date": end_date}), filtering=json.dumps(filtering) if filtering else None, page=page, page_size=page_size, - version=version + version=version, ), - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/material.py b/chapter12/booking_system/exts/wechatpy/client/api/material.py index 9754776..af2b40e 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/material.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/material.py @@ -18,23 +18,22 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0), - 'need_open_comment': int(article.get('need_open_comment', False)), - 'only_fans_can_comment': int(article.get('only_fans_can_comment', False)), - }) - return self._post( - 'material/add_news', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + "need_open_comment": int(article.get("need_open_comment", False)), + "only_fans_can_comment": int( + article.get("only_fans_can_comment", False) + ), + } + ) + return self._post("material/add_news", data={"articles": articles_data}) def add(self, media_type, media_file, title=None, introduction=None): """ @@ -48,24 +47,14 @@ def add(self, media_type, media_file, title=None, introduction=None): :param introduction: 视频素材简介,仅上传视频素材时需要 :return: 返回的 JSON 数据包 """ - params = { - 'access_token': self.access_token, - 'type': media_type - } - if media_type == 'video': - assert title, 'Video title must be set' - assert introduction, 'Video introduction must be set' - description = { - 'title': title, - 'introduction': introduction - } - params['description'] = json.dumps(description) + params = {"access_token": self.access_token, "type": media_type} + if media_type == "video": + assert title, "Video title must be set" + assert introduction, "Video introduction must be set" + description = {"title": title, "introduction": introduction} + params["description"] = json.dumps(description) return self._post( - 'material/add_material', - params=params, - files={ - 'media': media_file - } + "material/add_material", params=params, files={"media": media_file} ) def get(self, media_id): @@ -77,19 +66,18 @@ def get(self, media_id): :param media_id: 素材的 media_id :return: 图文素材返回图文列表,其它类型为素材的内容 """ + def _processor(res): if isinstance(res, dict): - if 'news_item' in res: + if "news_item" in res: # 图文素材 - return res['news_item'] + return res["news_item"] return res res = self._post( - 'material/get_material', - data={ - 'media_id': media_id - }, - result_processor=_processor + "material/get_material", + data={"media_id": media_id}, + result_processor=_processor, ) return res @@ -102,12 +90,7 @@ def delete(self, media_id): :param media_id: 素材的 media_id :return: 返回的 JSON 数据包 """ - return self._post( - 'material/del_material', - data={ - 'media_id': media_id - } - ) + return self._post("material/del_material", data={"media_id": media_id}) def update_article(self, media_id, index, article): """ @@ -121,21 +104,17 @@ def update_article(self, media_id, index, article): :return: 返回的 JSON 数据包 """ article_data = { - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } return self._post( - 'material/update_news', - data={ - 'media_id': media_id, - 'index': index, - 'articles': article_data - } + "material/update_news", + data={"media_id": media_id, "index": index, "articles": article_data}, ) def update_articles(self, media_id, index, articles): @@ -163,12 +142,8 @@ def batchget(self, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget_material', - data={ - 'type': media_type, - 'offset': offset, - 'count': count - } + "material/batchget_material", + data={"type": media_type, "offset": offset, "count": count}, ) def get_count(self): @@ -179,7 +154,7 @@ def get_count(self): :return: 返回的 JSON 数据包 """ - return self._get('material/get_materialcount') + return self._get("material/get_materialcount") def open_comment(self, msg_data_id, index=1): """ @@ -187,94 +162,102 @@ def open_comment(self, msg_data_id, index=1): https://mp.weixin.qq.com/wiki?id=mp1494572718_WzHIY """ return self._post( - 'comment/open', + "comment/open", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def close_comment(self, msg_data_id, index=1): """ 关闭已群发文章评论 """ return self._post( - 'comment/close', + "comment/close", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def list_comment(self, msg_data_id, index=1, begin=0, count=50, type=0): """ 查看指定文章的评论数据 """ return self._post( - 'comment/list', + "comment/list", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'begin': begin, - 'count': count, - 'type': type - }) + "msg_data_id": msg_data_id, + "index": index, + "begin": begin, + "count": count, + "type": type, + }, + ) def markelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论标记精选 """ return self._post( - 'comment/markelect', + "comment/markelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def unmarkelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论取消精选 """ return self._post( - 'comment/unmarkelect', + "comment/unmarkelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def delete_comment(self, msg_data_id, index, user_comment_id): """ 删除评论 """ return self._post( - 'comment/delete', + "comment/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def add_reply_comment(self, msg_data_id, index, user_comment_id, content): """ 回复评论 """ return self._post( - 'comment/reply/add', + "comment/reply/add", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - 'content': content - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + "content": content, + }, + ) def delete_reply_comment(self, msg_data_id, index, user_comment_id): """ 删除回复 """ return self._post( - 'comment/reply/delete', + "comment/reply/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/media.py b/chapter12/booking_system/exts/wechatpy/client/api/media.py index b4338b3..3b414c6 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/media.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/media.py @@ -17,13 +17,7 @@ def upload(self, media_type, media_file): :return: 返回的 JSON 数据包 """ return self._post( - url='media/upload', - params={ - 'type': media_type - }, - files={ - 'media': media_file - } + url="media/upload", params={"type": media_type}, files={"media": media_file} ) def download(self, media_id): @@ -36,12 +30,7 @@ def download(self, media_id): :return: requests 的 Response 实例 """ - return self._get( - 'media/get', - params={ - 'media_id': media_id - } - ) + return self._get("media/get", params={"media_id": media_id}) def get_url(self, media_id): """ @@ -51,13 +40,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://api.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://api.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def upload_video(self, media_id, title, description): """ @@ -72,12 +61,8 @@ def upload_video(self, media_id, title, description): :return: 返回的 JSON 数据包 """ return self._post( - url='media/uploadvideo', - data={ - 'media_id': media_id, - 'title': title, - 'description': description - } + url="media/uploadvideo", + data={"media_id": media_id, "title": title, "description": description}, ) def upload_articles(self, articles): @@ -91,21 +76,18 @@ def upload_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'media/uploadnews', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) + return self._post("media/uploadnews", data={"articles": articles_data}) def upload_image(self, media_file): """ @@ -117,11 +99,9 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='media/uploadimg', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="media/uploadimg", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/menu.py b/chapter12/booking_system/exts/wechatpy/client/api/menu.py index f0f6ce7..d509bc6 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/menu.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/menu.py @@ -24,7 +24,7 @@ def get(self): """ try: - return self._get('menu/get') + return self._get("menu/get") except WeChatClientException as e: if e.errcode == 46003: # menu not exist @@ -81,10 +81,7 @@ def create(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/create', - data=menu_data - ) + return self._post("menu/create", data=menu_data) def update(self, menu_data): """ @@ -153,7 +150,7 @@ def delete(self): res = client.menu.delete() """ - return self._get('menu/delete') + return self._get("menu/delete") def get_menu_info(self): """ @@ -171,7 +168,7 @@ def get_menu_info(self): menu_info = client.menu.get_menu_info() """ - return self._get('get_current_selfmenu_info') + return self._get("get_current_selfmenu_info") def add_conditional(self, menu_data): """ @@ -230,10 +227,7 @@ def add_conditional(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/addconditional', - data=menu_data - ) + return self._post("menu/addconditional", data=menu_data) def del_conditional(self, menu_id): """ @@ -254,10 +248,7 @@ def del_conditional(self, menu_id): res = client.menu.del_conditional('menu_id') """ - return self._post( - 'menu/delconditional', - data={'menuid': menu_id} - ) + return self._post("menu/delconditional", data={"menuid": menu_id}) def try_match(self, user_id): """ @@ -278,7 +269,4 @@ def try_match(self, user_id): res = client.menu.try_match('openid') """ - return self._post( - 'menu/trymatch', - data={'user_id': user_id} - ) + return self._post("menu/trymatch", data={"user_id": user_id}) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/__init__.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/__init__.py index d8342ac..710b104 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/__init__.py @@ -12,7 +12,7 @@ class WeChatMerchant(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def __init__(self, *args, **kwargs): super(WeChatMerchant, self).__init__(*args, **kwargs) @@ -28,54 +28,30 @@ def __init__(self, *args, **kwargs): def create(self, product_data): """增加商品""" - return self._post( - 'merchant/create', - data=product_data - ) + return self._post("merchant/create", data=product_data) def delete(self, product_id): """删除商品""" - return self._post( - 'merchant/del', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/del", data={"product_id": product_id}) def update(self, product_id, product_data): """修改商品""" - product_data['product_id'] = product_id - return self._post( - 'merchant/update', - data=product_data - ) + product_data["product_id"] = product_id + return self._post("merchant/update", data=product_data) def get(self, product_id): """查询商品""" - return self._post( - 'merchant/get', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/get", data={"product_id": product_id}) def get_by_status(self, status): """获取指定状态的所有商品""" - return self._post( - 'merchant/getbystatus', - data={ - 'status': status - } - ) + return self._post("merchant/getbystatus", data={"status": status}) def update_product_status(self, product_id, status): """商品上下架""" return self._post( - 'merchant/modproductstatus', - data={ - 'product_id': product_id, - 'status': status - } + "merchant/modproductstatus", + data={"product_id": product_id, "status": status}, ) def get_subcategories(self, cate_id): @@ -85,12 +61,7 @@ def get_subcategories(self, cate_id): :param cate_id: 大分类ID(根节点分类id为1) :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsub', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsub", data={"cate_id": cate_id}) def get_category_sku(self, cate_id): """ @@ -99,12 +70,7 @@ def get_category_sku(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsku', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsku", data={"cate_id": cate_id}) def get_category_property(self, cate_id): """ @@ -113,12 +79,7 @@ def get_category_property(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getproperty', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getproperty", data={"cate_id": cate_id}) def add_stock(self, product_id, sku_info, quantity): """ @@ -130,12 +91,8 @@ def add_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/add', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/add", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def reduce_stock(self, product_id, sku_info, quantity): @@ -148,12 +105,8 @@ def reduce_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/reduce', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/reduce", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def add_express(self, product_data): @@ -163,10 +116,7 @@ def add_express(self, product_data): :param product_data: 邮费信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/add', - data=product_data - ) + return self._post("merchant/express/add", data=product_data) def del_express(self, template_id): """ @@ -175,12 +125,7 @@ def del_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update_express(self, template_id, delivery_template): """ @@ -190,11 +135,8 @@ def update_express(self, template_id, delivery_template): :param delivery_template: 邮费模板信息(字段说明详见增加邮费模板) :return: 返回的 JSON 数据包 """ - delivery_template['template_id'] = template_id - return self._post( - 'merchant/express/update', - data=delivery_template - ) + delivery_template["template_id"] = template_id + return self._post("merchant/express/update", data=delivery_template) def get_express(self, template_id): """ @@ -203,12 +145,7 @@ def get_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/getbyid", data={"template_id": template_id}) def get_all_express(self): """ @@ -217,9 +154,7 @@ def get_all_express(self): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/express/getall' - ) + return self._get("merchant/express/getall") def add_group(self, group_detail): """ @@ -228,10 +163,7 @@ def add_group(self, group_detail): :param group_detail: 商品分组信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/add', - data=group_detail - ) + return self._post("merchant/group/add", data=group_detail) def del_group(self, group_id): """ @@ -240,12 +172,7 @@ def del_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update_group_property(self, group_id, group_properties): """ @@ -255,11 +182,8 @@ def update_group_property(self, group_id, group_properties): :param group_properties: 商品分组属性 :return: 返回的 JSON 数据包 """ - group_properties['group_id'] = group_id - return self._post( - 'merchant/group/propertymod', - data=group_properties - ) + group_properties["group_id"] = group_id + return self._post("merchant/group/propertymod", data=group_properties) def update_group_product(self, group_id, product_data): """ @@ -269,11 +193,8 @@ def update_group_product(self, group_id, product_data): :param product_data: 分组商品信息 :return: 返回的 JSON 数据包 """ - product_data['group_id'] = group_id - return self._post( - 'merchant/group/productmod', - data=product_data - ) + product_data["group_id"] = group_id + return self._post("merchant/group/productmod", data=product_data) def get_all_groups(self): """ @@ -281,9 +202,7 @@ def get_all_groups(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/group/getall' - ) + return self._get("merchant/group/getall") def get_group(self, group_id): """ @@ -292,12 +211,7 @@ def get_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/getbyid", data={"group_id": group_id}) def add_shelf(self, shelf_data): """ @@ -306,10 +220,7 @@ def add_shelf(self, shelf_data): :param shelf_data: 货架详情信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/add', - data=shelf_data - ) + return self._post("merchant/shelf/add", data=shelf_data) def del_shelf(self, shelf_id): """ @@ -318,12 +229,7 @@ def del_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update_shelf(self, shelf_id, shelf_data): """ @@ -333,11 +239,8 @@ def update_shelf(self, shelf_id, shelf_data): :param shelf_data: 货架详情 :return: 返回的 JSON 数据包 """ - shelf_data['shelf_id'] = shelf_id - return self._post( - 'merchant/shelf/mod', - data=shelf_data - ) + shelf_data["shelf_id"] = shelf_id + return self._post("merchant/shelf/mod", data=shelf_data) def get_all_shelves(self): """ @@ -345,9 +248,7 @@ def get_all_shelves(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/shelf/getall' - ) + return self._get("merchant/shelf/getall") def get_shelf(self, shelf_id): """ @@ -356,12 +257,7 @@ def get_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) def get_order(self, order_id): """ @@ -370,12 +266,7 @@ def get_order(self, order_id): :param order_id: 订单ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/getbyid", data={"order_id": order_id}) def query_order(self, status=None, begintime=None, endtime=None): """ @@ -387,12 +278,8 @@ def query_order(self, status=None, begintime=None, endtime=None): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/order/getbyfilter', - data={ - 'status': status, - 'begintime': begintime, - 'endtime': endtime - } + "merchant/order/getbyfilter", + data={"status": status, "begintime": begintime, "endtime": endtime}, ) def set_delivery(self, order_id, delivery_data): @@ -403,11 +290,8 @@ def set_delivery(self, order_id, delivery_data): :param delivery_data: 商品物流信息 :return: 返回的 JSON 数据包 """ - delivery_data['order_id'] = order_id - return self._post( - 'merchant/shelf/setdeliverymod', - data=delivery_data - ) + delivery_data["order_id"] = order_id + return self._post("merchant/shelf/setdeliverymod", data=delivery_data) def upload_image(self, media_file): """ @@ -417,10 +301,8 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='merchant/common/upload_img', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="merchant/common/upload_img", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/category.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/category.py index 3297125..584a902 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/category.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/category.py @@ -5,28 +5,28 @@ class MerchantCategory(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get_sub_categories(self, cate_id): res = self._post( - 'merchant/category/getsub', - data={'cate_id': cate_id}, - result_processor=lambda x: x['cate_list'] + "merchant/category/getsub", + data={"cate_id": cate_id}, + result_processor=lambda x: x["cate_list"], ) return res def get_sku_list(self, cate_id): res = self._post( - 'merchant/category/getsku', - data={'cate_id': cate_id}, - result_processor=lambda x: x['sku_table'] + "merchant/category/getsku", + data={"cate_id": cate_id}, + result_processor=lambda x: x["sku_table"], ) return res def get_properties(self, cate_id): res = self._post( - 'merchant/category/getproperty', - data={'cate_id': cate_id}, - result_processor=lambda x: x['properties'] + "merchant/category/getproperty", + data={"cate_id": cate_id}, + result_processor=lambda x: x["properties"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/common.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/common.py index e1d3323..2700e77 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/common.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/common.py @@ -5,15 +5,13 @@ class MerchantCommon(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def upload_image(self, filename, image_data): res = self._post( - 'merchant/common/upload_img', - params={ - 'filename': filename - }, + "merchant/common/upload_img", + params={"filename": filename}, data=image_data, - result_processor=lambda x: x['image_url'] + result_processor=lambda x: x["image_url"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/express.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/express.py index e6e2e5c..488e05d 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/express.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/express.py @@ -5,46 +5,32 @@ class MerchantExpress(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, delivery_template): return self._post( - 'merchant/express/add', - data={ - 'delivery_template': delivery_template - } + "merchant/express/add", data={"delivery_template": delivery_template} ) def delete(self, template_id): - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update(self, template_id, delivery_template): return self._post( - 'merchant/express/update', - data={ - 'template_id': template_id, - 'delivery_template': delivery_template - } + "merchant/express/update", + data={"template_id": template_id, "delivery_template": delivery_template}, ) def get(self, template_id): res = self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - }, - result_processor=lambda x: x['template_info'] + "merchant/express/getbyid", + data={"template_id": template_id}, + result_processor=lambda x: x["template_info"], ) return res def get_all(self): res = self._get( - 'merchant/express/getall', - result_processor=lambda x: x['template_info'] + "merchant/express/getall", result_processor=lambda x: x["template_info"] ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/group.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/group.py index acaf1df..02c17d6 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/group.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/group.py @@ -5,58 +5,38 @@ class MerchantGroup(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, product_list): return self._post( - 'merchant/group/add', - data={ - 'group_detail': { - 'group_name': name, - 'product_list': product_list - } - } + "merchant/group/add", + data={"group_detail": {"group_name": name, "product_list": product_list}}, ) def delete(self, group_id): - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update(self, group_id, name): return self._post( - 'merchant/group/propertymod', - data={ - 'group_id': group_id, - 'group_name': name - } + "merchant/group/propertymod", + data={"group_id": group_id, "group_name": name}, ) def update_product(self, group_id, product): return self._post( - 'merchant/group/productmod', - data={ - 'group_id': group_id, - 'product': product - } + "merchant/group/productmod", data={"group_id": group_id, "product": product} ) def get_all(self): res = self._get( - 'merchant/group/getall', - result_processor=lambda x: x['groups_detail'] + "merchant/group/getall", result_processor=lambda x: x["groups_detail"] ) return res def get(self, group_id): res = self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - }, - result_processor=lambda x: x['group_detail'] + "merchant/group/getbyid", + data={"group_id": group_id}, + result_processor=lambda x: x["group_detail"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/order.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/order.py index 7e49412..7938633 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/order.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/order.py @@ -6,49 +6,39 @@ class MerchantOrder(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get(self, order_id): res = self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - }, - result_processor=lambda x: x['order'] + "merchant/order/getbyid", + data={"order_id": order_id}, + result_processor=lambda x: x["order"], ) return res def get_by_filter(self, status=None, begin_time=None, end_time=None): filter_dict = optionaldict( - status=status, - begintime=begin_time, - endtime=end_time + status=status, begintime=begin_time, endtime=end_time ) res = self._post( - 'merchant/order/getbyfilter', + "merchant/order/getbyfilter", data=dict(filter_dict), - result_processor=lambda x: x['order_list'] + result_processor=lambda x: x["order_list"], ) return res - def set_delivery(self, order_id, company, track_no, - need_delivery=1, is_others=0): + def set_delivery(self, order_id, company, track_no, need_delivery=1, is_others=0): return self._post( - 'merchant/order/setdelivery', + "merchant/order/setdelivery", data={ - 'order_id': order_id, - 'delivery_company': company, - 'delivery_track_no': track_no, - 'need_delivery': need_delivery, - 'is_others': is_others - } + "order_id": order_id, + "delivery_company": company, + "delivery_track_no": track_no, + "need_delivery": need_delivery, + "is_others": is_others, + }, ) def close(self, order_id): - return self._post( - 'merchant/order/close', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/close", data={"order_id": order_id}) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/shelf.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/shelf.py index afca61f..b6dc2a8 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/shelf.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/shelf.py @@ -5,48 +5,33 @@ class MerchantShelf(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', - data={ - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "merchant/shelf/add", + data={"shelf_name": name, "shelf_banner": banner, "shelf_data": shelf_data}, ) def delete(self, shelf_id): - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update(self, shelf_id, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', + "merchant/shelf/add", data={ - 'shelf_id': shelf_id, - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "shelf_id": shelf_id, + "shelf_name": name, + "shelf_banner": banner, + "shelf_data": shelf_data, + }, ) def get_all(self): res = self._get( - 'merchant/shelf/getall', - result_processor=lambda x: x['shelves'] + "merchant/shelf/getall", result_processor=lambda x: x["shelves"] ) return res def get(self, shelf_id): - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/merchant/stock.py b/chapter12/booking_system/exts/wechatpy/client/api/merchant/stock.py index b2a6b1c..295eddb 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/merchant/stock.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/merchant/stock.py @@ -5,24 +5,16 @@ class MerchantStock(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" - def add(self, product_id, quantity, sku_info=''): + def add(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/add', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/add", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) - def reduce(self, product_id, quantity, sku_info=''): + def reduce(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/reduce', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/reduce", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/message.py b/chapter12/booking_system/exts/wechatpy/client/api/message.py index 8dacb07..c418a02 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/message.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/message.py @@ -12,16 +12,13 @@ class WeChatMessage(BaseWeChatAPI): - OPENID_RE = re.compile(r'^[\w\-]{28}$', re.I) + OPENID_RE = re.compile(r"^[\w\-]{28}$", re.I) def _send_custom_message(self, data, account=None): data = data or {} if account: - data['customservice'] = {'kf_account': account} - return self._post( - 'message/custom/send', - data=data - ) + data["customservice"] = {"kf_account": account} + return self._post("message/custom/send", data=data) def send_text(self, user_id, content, account=None): """ @@ -43,11 +40,7 @@ def send_text(self, user_id, content, account=None): res = client.message.send_text('openid', 'text') """ - data = { - 'touser': user_id, - 'msgtype': 'text', - 'text': {'content': content} - } + data = {"touser": user_id, "msgtype": "text", "text": {"content": content}} return self._send_custom_message(data, account=account) def send_image(self, user_id, media_id, account=None): @@ -70,13 +63,7 @@ def send_image(self, user_id, media_id, account=None): res = client.message.send_image('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'image', - 'image': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "image", "image": {"media_id": media_id}} return self._send_custom_message(data, account=account) def send_voice(self, user_id, media_id, account=None): @@ -99,17 +86,10 @@ def send_voice(self, user_id, media_id, account=None): res = client.message.send_voice('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "voice", "voice": {"media_id": media_id}} return self._send_custom_message(data, account=account) - def send_video(self, user_id, media_id, title=None, - description=None, account=None): + def send_video(self, user_id, media_id, title=None, description=None, account=None): """ 发送视频消息 @@ -131,22 +111,26 @@ def send_video(self, user_id, media_id, title=None, res = client.message.send_video('openid', 'media_id', 'title', 'description') """ video_data = { - 'media_id': media_id, + "media_id": media_id, } if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'video', - 'video': video_data - } + data = {"touser": user_id, "msgtype": "video", "video": video_data} return self._send_custom_message(data, account=account) - def send_music(self, user_id, url, hq_url, thumb_media_id, - title=None, description=None, account=None): + def send_music( + self, + user_id, + url, + hq_url, + thumb_media_id, + title=None, + description=None, + account=None, + ): """ 发送音乐消息 @@ -163,20 +147,16 @@ def send_music(self, user_id, url, hq_url, thumb_media_id, :return: 返回的 JSON 数据包 """ music_data = { - 'musicurl': url, - 'hqmusicurl': hq_url, - 'thumb_media_id': thumb_media_id + "musicurl": url, + "hqmusicurl": hq_url, + "thumb_media_id": thumb_media_id, } if title: - music_data['title'] = title + music_data["title"] = title if description: - music_data['description'] = description + music_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'music', - 'music': music_data - } + data = {"touser": user_id, "msgtype": "music", "music": music_data} return self._send_custom_message(data, account=account) def send_articles(self, user_id, articles, account=None): @@ -194,26 +174,26 @@ def send_articles(self, user_id, articles, account=None): if isinstance(articles, (tuple, list)): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article.get('image', article.get('picurl')), - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article.get("image", article.get("picurl")), + } + ) data = { - 'touser': user_id, - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } + "touser": user_id, + "msgtype": "news", + "news": {"articles": articles_data}, } else: data = { - 'touser': user_id, - 'msgtype': 'mpnews', - 'mpnews': { - 'media_id': articles, - } + "touser": user_id, + "msgtype": "mpnews", + "mpnews": { + "media_id": articles, + }, } return self._send_custom_message(data, account=account) @@ -231,14 +211,14 @@ def send_card(self, user_id, card_id, card_ext=None, account=None): :return: 返回的 JSON 数据包 """ wxcard = { - 'card_id': card_id, + "card_id": card_id, } if card_ext: - wxcard['card_ext'] = card_ext + wxcard["card_ext"] = card_ext data = { - 'touser': user_id, - 'msgtype': 'wxcard', - 'wxcard': wxcard, + "touser": user_id, + "msgtype": "wxcard", + "wxcard": wxcard, } return self._send_custom_message(data, account=account) @@ -254,9 +234,9 @@ def send_mini_program_page(self, user_id, miniprogrampage, account=None): :return: 返回的 JSON 数据包 """ data = { - 'touser': user_id, - 'msgtype': 'miniprogrampage', - 'miniprogrampage': miniprogrampage + "touser": user_id, + "msgtype": "miniprogrampage", + "miniprogrampage": miniprogrampage, } return self._send_custom_message(data, account=account) @@ -278,55 +258,60 @@ def delete_mass(self, msg_id): res = client.message.delete_mass('message id') """ - return self._post( - 'message/mass/delete', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/delete", data={"msg_id": msg_id}) - def _send_mass_message(self, group_or_users, msg_type, msg, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def _send_mass_message( + self, + group_or_users, + msg_type, + msg, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): data = { - 'msgtype': msg_type, - 'send_ignore_reprint': send_ignore_reprint, + "msgtype": msg_type, + "send_ignore_reprint": send_ignore_reprint, } if client_msg_id is not None: - data['clientmsgid'] = client_msg_id + data["clientmsgid"] = client_msg_id if not preview: if isinstance(group_or_users, (tuple, list)): # send by order ids - data['touser'] = group_or_users - endpoint = 'message/mass/send' + data["touser"] = group_or_users + endpoint = "message/mass/send" else: # send by group id - data['filter'] = { - 'group_id': group_or_users, - 'is_to_all': is_to_all, + data["filter"] = { + "group_id": group_or_users, + "is_to_all": is_to_all, } - endpoint = 'message/mass/sendall' + endpoint = "message/mass/sendall" else: if not isinstance(group_or_users, six.string_types): - raise ValueError('group_or_users should be string types') + raise ValueError("group_or_users should be string types") # 预览接口 if self.OPENID_RE.match(group_or_users): # 按照 openid 预览群发 - data['touser'] = group_or_users + data["touser"] = group_or_users else: # 按照微信号预览群发 - data['towxname'] = group_or_users - endpoint = 'message/mass/preview' + data["towxname"] = group_or_users + endpoint = "message/mass/preview" data.update(msg) - return self._post( - endpoint, - data=data - ) - - def send_mass_text(self, group_or_users, content, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + return self._post(endpoint, data=data) + + def send_mass_text( + self, + group_or_users, + content, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发文本消息 @@ -353,21 +338,23 @@ def send_mass_text(self, group_or_users, content, """ return self._send_mass_message( group_or_users, - 'text', - { - 'text': { - 'content': content - } - }, + "text", + {"text": {"content": content}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_image(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_image( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图片消息 @@ -394,21 +381,23 @@ def send_mass_image(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'image', - { - 'image': { - 'media_id': media_id - } - }, + "image", + {"image": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_voice(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_voice( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发语音消息 @@ -435,21 +424,25 @@ def send_mass_voice(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'voice', - { - 'voice': { - 'media_id': media_id - } - }, + "voice", + {"voice": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_video(self, group_or_users, media_id, title=None, - description=None, is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_video( + self, + group_or_users, + media_id, + title=None, + description=None, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发视频消息 @@ -476,28 +469,30 @@ def send_mass_video(self, group_or_users, media_id, title=None, :return: 返回的 JSON 数据包 """ - video_data = { - 'media_id': media_id - } + video_data = {"media_id": media_id} if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description return self._send_mass_message( group_or_users, - 'mpvideo', - { - 'mpvideo': video_data - }, + "mpvideo", + {"mpvideo": video_data}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_article(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_article( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图文消息 @@ -524,12 +519,8 @@ def send_mass_article(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'mpnews', - { - 'mpnews': { - 'media_id': media_id - } - }, + "mpnews", + {"mpnews": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, @@ -554,14 +545,11 @@ def get_mass(self, msg_id): res = client.message.get_mass('mass message id') """ - return self._post( - 'message/mass/get', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/get", data={"msg_id": msg_id}) - def send_template(self, to_user_openid, template_id, data, url=None, mini_program=None): + def send_template( + self, to_user_openid, template_id, data, url=None, mini_program=None + ): """ 发送模板消息 @@ -582,10 +570,7 @@ def send_template(self, to_user_openid, template_id, data, url=None, mini_progra miniprogram=mini_program, data=data, ) - return self._post( - 'message/template/send', - data=tpl_data - ) + return self._post("message/template/send", data=tpl_data) def get_autoreply_info(self): """ @@ -604,11 +589,17 @@ def get_autoreply_info(self): info = client.message.get_autoreply_info() """ - return self._get('get_current_autoreply_info') + return self._get("get_current_autoreply_info") - def send_mass_card(self, group_or_users, card_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_card( + self, + group_or_users, + card_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发卡券消息 @@ -635,19 +626,17 @@ def send_mass_card(self, group_or_users, card_id, """ return self._send_mass_message( group_or_users, - 'wxcard', - { - 'wxcard': { - 'card_id': card_id - } - }, + "wxcard", + {"wxcard": {"card_id": card_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved=None): + def get_subscribe_authorize_url( + self, scene, template_id, redirect_url, reserved=None + ): """ 构造请求用户授权的url 详情请参阅: @@ -661,20 +650,24 @@ def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved """ if reserved is None: reserved = random_string() - base_url = 'https://mp.weixin.qq.com/mp/subscribemsg' + base_url = "https://mp.weixin.qq.com/mp/subscribemsg" params = [ - ('action', 'get_confirm'), - ('appid', self.appid), - ('scene', scene), - ('template_id', template_id), - ('redirect_url', redirect_url), - ('reserved', reserved), + ("action", "get_confirm"), + ("appid", self.appid), + ("scene", scene), + ("template_id", template_id), + ("redirect_url", redirect_url), + ("reserved", reserved), ] encoded_params = six.moves.urllib.parse.urlencode(params) - url = '{base}?{params}#wechat_redirect'.format(base=base_url, params=encoded_params) + url = "{base}?{params}#wechat_redirect".format( + base=base_url, params=encoded_params + ) return url - def send_subscribe_template(self, openid, template_id, scene, title, data, url=None): + def send_subscribe_template( + self, openid, template_id, scene, title, data, url=None + ): """ 一次性订阅消息,通过API推送订阅模板消息给到授权微信用户。 详情请参阅: @@ -690,16 +683,16 @@ def send_subscribe_template(self, openid, template_id, scene, title, data, url=N :param url: 点击消息跳转的链接,需要有ICP备案 """ post_data = { - 'touser': openid, - 'template_id': template_id, - 'url': url, - 'scene': scene, - 'title': title, - 'data': data, + "touser": openid, + "template_id": template_id, + "url": url, + "scene": scene, + "title": title, + "data": data, } if url is not None: - post_data['url'] = url + post_data["url"] = url return self._post( - 'message/template/subscribe', + "message/template/subscribe", data=post_data, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/misc.py b/chapter12/booking_system/exts/wechatpy/client/api/misc.py index 8a8f996..a6eacb6 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/misc.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/misc.py @@ -23,11 +23,7 @@ def short_url(self, long_url): """ return self._post( - 'shorturl', - data={ - 'action': 'long2short', - 'long_url': long_url - } + "shorturl", data={"action": "long2short", "long_url": long_url} ) def get_wechat_ips(self): @@ -44,8 +40,5 @@ def get_wechat_ips(self): ips = client.misc.get_wechat_ips() """ - res = self._get( - 'getcallbackip', - result_processor=lambda x: x['ip_list'] - ) + res = self._get("getcallbackip", result_processor=lambda x: x["ip_list"]) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/poi.py b/chapter12/booking_system/exts/wechatpy/client/api/poi.py index 0acfb7d..6bceefd 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/poi.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/poi.py @@ -15,7 +15,7 @@ def add(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/addpoi', data=poi_data) + return self._post("poi/addpoi", data=poi_data) def get(self, poi_id): """ @@ -27,7 +27,7 @@ def get(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/getpoi', data={'poi_id': poi_id}) + return self._post("poi/getpoi", data={"poi_id": poi_id}) def list(self, begin=0, limit=20): """ @@ -41,11 +41,11 @@ def list(self, begin=0, limit=20): :return: 返回的 JSON 数据包 """ return self._post( - 'poi/getpoilist', + "poi/getpoilist", data={ - 'begin': begin, - 'limit': limit, - } + "begin": begin, + "limit": limit, + }, ) def update(self, poi_data): @@ -58,7 +58,7 @@ def update(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/updatepoi', data=poi_data) + return self._post("poi/updatepoi", data=poi_data) def delete(self, poi_id): """ @@ -70,7 +70,7 @@ def delete(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/delpoi', data={'poi_id': poi_id}) + return self._post("poi/delpoi", data={"poi_id": poi_id}) def get_categories(self): """ @@ -82,7 +82,6 @@ def get_categories(self): :return: 门店类目表 """ res = self._get( - 'api_getwxcategory', - result_processor=lambda x: x['category_list'] + "api_getwxcategory", result_processor=lambda x: x["category_list"] ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/qrcode.py b/chapter12/booking_system/exts/wechatpy/client/api/qrcode.py index 51b7af1..07dcc9b 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/qrcode.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/qrcode.py @@ -38,10 +38,7 @@ def create(self, qrcode_data): }) """ - return self._post( - 'qrcode/create', - data=qrcode_data - ) + return self._post("qrcode/create", data=qrcode_data) def show(self, ticket): """ @@ -61,12 +58,9 @@ def show(self, ticket): """ if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] return requests.get( - url='https://mp.weixin.qq.com/cgi-bin/showqrcode', - params={ - 'ticket': ticket - } + url="https://mp.weixin.qq.com/cgi-bin/showqrcode", params={"ticket": ticket} ) @classmethod @@ -87,8 +81,8 @@ def get_url(cls, ticket): url = client.qrcode.get_url('ticket data') """ - url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}' + url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}" if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] ticket = six.moves.urllib.parse.quote(ticket) return url.format(ticket=ticket) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/scan.py b/chapter12/booking_system/exts/wechatpy/client/api/scan.py index c7a1589..1fb2d4a 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/scan.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/scan.py @@ -6,7 +6,7 @@ class WeChatScan(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/scan/' + API_BASE_URL = "https://api.weixin.qq.com/scan/" def get_merchant_info(self): """ @@ -24,7 +24,7 @@ def get_merchant_info(self): client = WeChatClient('appid', 'secret') info = client.scan.get_merchant_info() """ - return self._get('merchantinfo/get') + return self._get("merchantinfo/get") def create_product(self, product_data): """ @@ -35,7 +35,7 @@ def create_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/create', data=product_data) + return self._post("product/create", data=product_data) def modify_product_status(self, standard, key, status): """ @@ -50,11 +50,11 @@ def modify_product_status(self, standard, key, status): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, - 'status': status, + "keystandard": standard, + "keystr": key, + "status": status, } - return self._post('product/modstatus', data=data) + return self._post("product/modstatus", data=data) def publish_product(self, standard, key): """ @@ -62,7 +62,7 @@ def publish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'on')`` """ - return self.modify_product_status(standard, key, 'on') + return self.modify_product_status(standard, key, "on") def unpublish_product(self, standard, key): """ @@ -70,7 +70,7 @@ def unpublish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'off')`` """ - return self.modify_product_status(standard, key, 'off') + return self.modify_product_status(standard, key, "off") def set_test_whitelist(self, userids=None, usernames=None): """ @@ -85,11 +85,8 @@ def set_test_whitelist(self, userids=None, usernames=None): :param usernames: 可选,测试人员的微信号列表 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=userids, - username=usernames - ) - return self._post('testwhitelist/set', data=data) + data = optionaldict(openid=userids, username=usernames) + return self._post("testwhitelist/set", data=data) def get_product(self, standard, key): """ @@ -103,10 +100,10 @@ def get_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/get', data=data) + return self._post("product/get", data=data) def list_product(self, offset=0, limit=10, status=None, key=None): """ @@ -128,7 +125,7 @@ def list_product(self, offset=0, limit=10, status=None, key=None): status=status, keystr=key, ) - return self._post('product/getlist', data=data) + return self._post("product/getlist", data=data) def update_product(self, product_data): """ @@ -139,7 +136,7 @@ def update_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/update', data=product_data) + return self._post("product/update", data=product_data) def clear_product(self, standard, key): """ @@ -153,10 +150,10 @@ def clear_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/clear', data=data) + return self._post("product/clear", data=data) def check_ticket(self, ticket): """ @@ -168,4 +165,4 @@ def check_ticket(self, ticket): :param ticket: 请求 URL 中带上的 wxticket 参数 :return: 返回的 JSON 数据包 """ - return self._post('scanticket/check', data={'ticket': ticket}) + return self._post("scanticket/check", data={"ticket": ticket}) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/semantic.py b/chapter12/booking_system/exts/wechatpy/client/api/semantic.py index 73325ed..4a234eb 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/semantic.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/semantic.py @@ -7,14 +7,16 @@ class WeChatSemantic(BaseWeChatAPI): - def search(self, - query, - category, - uid=None, - latitude=None, - longitude=None, - city=None, - region=None): + def search( + self, + query, + category, + uid=None, + latitude=None, + longitude=None, + city=None, + region=None, + ): """ 发送语义理解请求 详情请参考 @@ -42,18 +44,17 @@ def search(self, """ if isinstance(category, (tuple, list)): - category = ','.join(category) + category = ",".join(category) data = optionaldict() - data['query'] = query - data['category'] = category - data['uid'] = uid - data['latitude'] = latitude - data['longitude'] = longitude - data['city'] = city - data['region'] = region - data['appid'] = self._client.appid + data["query"] = query + data["category"] = category + data["uid"] = uid + data["latitude"] = latitude + data["longitude"] = longitude + data["city"] = city + data["region"] = region + data["appid"] = self._client.appid return self._post( - url='https://api.weixin.qq.com/semantic/semproxy/search', - data=data + url="https://api.weixin.qq.com/semantic/semproxy/search", data=data ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/shakearound.py b/chapter12/booking_system/exts/wechatpy/client/api/shakearound.py index cca5ba7..52fdb37 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/shakearound.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/shakearound.py @@ -11,12 +11,12 @@ class WeChatShakeAround(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" @classmethod def _to_timestamp(cls, date): if isinstance(date, six.string_types): - date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S') + date = datetime.strptime(date, "%Y-%m-%d %H:%M:%S") if isinstance(date, datetime): timestamp = int(time.mktime(date.timetuple())) return timestamp @@ -35,19 +35,20 @@ def apply_device_id(self, quantity, reason, poi_id=None, comment=None): :return: 申请的设备信息 """ data = optionaldict() - data['quantity'] = quantity - data['apply_reason'] = reason - data['poi_id'] = poi_id - data['comment'] = comment + data["quantity"] = quantity + data["apply_reason"] = reason + data["poi_id"] = poi_id + data["comment"] = comment res = self._post( - 'shakearound/device/applyid', + "shakearound/device/applyid", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res - def update_device(self, device_id=None, uuid=None, major=None, - minor=None, comment=None): + def update_device( + self, device_id=None, uuid=None, major=None, minor=None, comment=None + ): """ 更新设备信息 详情请参考 @@ -61,20 +62,18 @@ def update_device(self, device_id=None, uuid=None, major=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['comment'] = comment - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["comment"] = comment + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/update', - data=data - ) + return self._post("shakearound/device/update", data=data) - def bind_device_location(self, poi_id, device_id=None, uuid=None, - major=None, minor=None): + def bind_device_location( + self, poi_id, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与门店的关联关系 详情请参考 @@ -88,20 +87,16 @@ def bind_device_location(self, poi_id, device_id=None, uuid=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['poi_id'] = poi_id - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["poi_id"] = poi_id + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/bindlocation', - data=data - ) + return self._post("shakearound/device/bindlocation", data=data) - def search_device(self, identifiers=None, apply_id=None, - begin=0, count=10): + def search_device(self, identifiers=None, apply_id=None, begin=0, count=10): """ 查询设备列表 详情请参考 @@ -114,15 +109,13 @@ def search_device(self, identifiers=None, apply_id=None, :return: 设备列表 """ data = optionaldict() - data['begin'] = begin - data['count'] = count - data['apply_id'] = apply_id + data["begin"] = begin + data["count"] = count + data["apply_id"] = apply_id if identifiers: - data['device_identifiers'] = identifiers + data["device_identifiers"] = identifiers res = self._post( - 'shakearound/device/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/device/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -141,20 +134,19 @@ def add_page(self, title, description, icon_url, page_url, comment=None): :return: 页面信息 """ data = optionaldict() - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/add', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/add", data=data, result_processor=lambda x: x["data"] ) return res - def update_page(self, page_id, title, description, - icon_url, page_url, comment=None): + def update_page( + self, page_id, title, description, icon_url, page_url, comment=None + ): """ 编辑页面信息 详情请参考 @@ -170,16 +162,14 @@ def update_page(self, page_id, title, description, :return: 页面信息 """ data = optionaldict() - data['page_id'] = page_id - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["page_id"] = page_id + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/update', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/update", data=data, result_processor=lambda x: x["data"] ) return res @@ -195,23 +185,14 @@ def search_pages(self, page_ids=None, begin=0, count=10): :return: 页面查询结果信息 """ if not page_ids: - data = { - 'type': 2, - 'begin': begin, - 'count': count - } + data = {"type": 2, "begin": begin, "count": count} else: if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] - data = { - 'type': 1, - 'page_ids': page_ids - } + data = {"type": 1, "page_ids": page_ids} res = self._post( - 'shakearound/page/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -224,14 +205,9 @@ def delete_page(self, page_id): :param page_id: 指定页面的id列表 :return: 返回的 JSON 数据包 """ - return self._post( - 'shakearound/page/delete', - data={ - 'page_id': page_id - } - ) + return self._post("shakearound/page/delete", data={"page_id": page_id}) - def add_material(self, media_file, media_type='icon'): + def add_material(self, media_file, media_type="icon"): """ 上传图片素材 详情请参考 @@ -242,19 +218,16 @@ def add_material(self, media_file, media_type='icon'): :return: 上传的素材信息 """ res = self._post( - 'shakearound/material/add', - files={ - 'media': media_file - }, - params={ - 'type': media_type - }, - result_processor=lambda x: x['data'] + "shakearound/material/add", + files={"media": media_file}, + params={"type": media_type}, + result_processor=lambda x: x["data"], ) return res - def bind_device_pages(self, page_ids, bind, append, device_id=None, - uuid=None, major=None, minor=None): + def bind_device_pages( + self, page_ids, bind, append, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与页面的关联关系 详情请参考 @@ -272,20 +245,17 @@ def bind_device_pages(self, page_ids, bind, append, device_id=None, if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] data = { - 'page_ids': page_ids, - 'bind': int(bind), - 'append': int(append), - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor - } + "page_ids": page_ids, + "bind": int(bind), + "append": int(append), + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, + }, } - return self._post( - 'shakearound/device/bindpage', - data=data - ) + return self._post("shakearound/device/bindpage", data=data) def get_shake_info(self, ticket): """ @@ -297,16 +267,15 @@ def get_shake_info(self, ticket): :return: 设备及用户信息 """ res = self._post( - 'shakearound/order/getshakeinfo', - data={ - 'ticket': ticket - }, - result_processor=lambda x: x['data'] + "shakearound/order/getshakeinfo", + data={"ticket": ticket}, + result_processor=lambda x: x["data"], ) return res - def get_device_statistics(self, begin_date, end_date, device_id=None, - uuid=None, major=None, minor=None): + def get_device_statistics( + self, begin_date, end_date, device_id=None, uuid=None, major=None, minor=None + ): """ 以设备为维度的数据统计接口 http://mp.weixin.qq.com/wiki/0/8a24bcacad40fe7ee98d1573cb8a6764.html @@ -319,19 +288,19 @@ def get_device_statistics(self, begin_date, end_date, device_id=None, :param minor: minor """ data = { - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, }, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date) + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), } res = self._post( - 'shakearound/statistics/device', + "shakearound/statistics/device", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -347,13 +316,13 @@ def get_page_statistics(self, page_id, begin_date, end_date): :return: 统计数据 """ res = self._post( - 'shakearound/statistics/page', + "shakearound/statistics/page", data={ - 'page_id': page_id, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date), + "page_id": page_id, + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -367,10 +336,10 @@ def get_apply_status(self, apply_id): :return: 批次状态信息 """ res = self._post( - 'shakearound/device/applystatus', + "shakearound/device/applystatus", data={ - 'apply_id': apply_id, + "apply_id": apply_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/tag.py b/chapter12/booking_system/exts/wechatpy/client/api/tag.py index 6c2a9aa..daf553d 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/tag.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/tag.py @@ -17,9 +17,9 @@ def create(self, name): """ name = to_text(name) return self._post( - 'tags/create', - data={'tag': {'name': name}}, - result_processor=lambda x: x['tag'] + "tags/create", + data={"tag": {"name": name}}, + result_processor=lambda x: x["tag"], ) def get(self): @@ -30,10 +30,7 @@ def get(self): """ - res = self._get( - 'tags/get', - result_processor=lambda x: x['tags'] - ) + res = self._get("tags/get", result_processor=lambda x: x["tags"]) return res @@ -48,13 +45,7 @@ def update(self, tag_id, name): """ name = to_text(name) return self._post( - 'tags/update', - data={ - 'tag': { - 'id': int(tag_id), - 'name': name - } - } + "tags/update", data={"tag": {"id": int(tag_id), "name": name}} ) def delete(self, tag_id): @@ -65,14 +56,7 @@ def delete(self, tag_id): :return: 返回的 JSON 数据包 """ - return self._post( - 'tags/delete', - data={ - 'tag': { - 'id': tag_id - } - } - ) + return self._post("tags/delete", data={"tag": {"id": tag_id}}) def tag_user(self, tag_id, user_id): """ @@ -84,12 +68,14 @@ def tag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchtagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchtagging", data=data) def untag_user(self, tag_id, user_id): """ @@ -101,12 +87,14 @@ def untag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchuntagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchuntagging", data=data) def get_user_tag(self, user_id): """ @@ -116,11 +104,9 @@ def get_user_tag(self, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'tags/getidlist', - data={ - 'openid': user_id - }, - result_processor=lambda x: x['tagid_list'] + "tags/getidlist", + data={"openid": user_id}, + result_processor=lambda x: x["tagid_list"], ) def get_tag_users(self, tag_id, first_user_id=None): @@ -132,14 +118,11 @@ def get_tag_users(self, tag_id, first_user_id=None): :return: 返回的 JSON 数据包 """ data = { - 'tagid': tag_id, + "tagid": tag_id, } if first_user_id: - data['next_openid'] = first_user_id - return self._post( - 'order/tag/get', - data=data - ) + data["next_openid"] = first_user_id + return self._post("order/tag/get", data=data) def iter_tag_users(self, tag_id, first_user_id=None): """ @@ -158,11 +141,11 @@ def iter_tag_users(self, tag_id, first_user_id=None): """ while True: follower_data = self.get_tag_users(tag_id, first_user_id) - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid - first_user_id = follower_data.get('next_openid') + first_user_id = follower_data.get("next_openid") if not first_user_id: return @@ -178,9 +161,9 @@ def get_black_list(self, begin_openid=None): """ data = {} if begin_openid: - data['begin_openid'] = begin_openid + data["begin_openid"] = begin_openid return self._post( - 'tags/members/getblacklist', + "tags/members/getblacklist", data=data, ) @@ -194,9 +177,9 @@ def batch_black_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchblacklist', + "tags/members/batchblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) @@ -210,8 +193,8 @@ def batch_unblack_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchunblacklist', + "tags/members/batchunblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/template.py b/chapter12/booking_system/exts/wechatpy/client/api/template.py index 5d202da..01f9bbd 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/template.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/template.py @@ -17,11 +17,8 @@ def set_industry(self, industry_id1, industry_id2): :return: 返回的 JSON 数据包 """ return self._post( - 'template/api_set_industry', - data={ - 'industry_id1': industry_id1, - 'industry_id2': industry_id2 - } + "template/api_set_industry", + data={"industry_id1": industry_id1, "industry_id2": industry_id2}, ) def get_industry(self): @@ -32,9 +29,7 @@ def get_industry(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_industry' - ) + return self._get("template/get_industry") def get(self, template_id_short): """ @@ -46,11 +41,9 @@ def get(self, template_id_short): :return: 模板 ID """ res = self._post( - 'template/api_add_template', - data={ - 'template_id_short': template_id_short - }, - result_processor=lambda x: x['template_id'] + "template/api_add_template", + data={"template_id_short": template_id_short}, + result_processor=lambda x: x["template_id"], ) return res @@ -64,9 +57,7 @@ def get_all_private_template(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_all_private_template' - ) + return self._get("template/get_all_private_template") def del_private_template(self, template_id): """ @@ -78,8 +69,5 @@ def del_private_template(self, template_id): :return: 返回的 JSON 数据包 """ return self._post( - 'template/del_private_template', - data={ - 'template_id': template_id - } + "template/del_private_template", data={"template_id": template_id} ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/user.py b/chapter12/booking_system/exts/wechatpy/client/api/user.py index 6e2a428..977310d 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/user.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/user.py @@ -8,7 +8,7 @@ class WeChatUser(BaseWeChatAPI): - def get(self, user_id, lang='zh_CN'): + def get(self, user_id, lang="zh_CN"): """ 获取用户基本信息(包括UnionID机制) 详情请参考 @@ -26,15 +26,13 @@ def get(self, user_id, lang='zh_CN'): order = client.order.get('openid') """ - assert lang in ('zh_CN', 'zh_TW', 'en'), 'lang can only be one of \ - zh_CN, zh_TW, en language codes' - return self._get( - 'order/info', - params={ - 'openid': user_id, - 'lang': lang - } - ) + assert lang in ( + "zh_CN", + "zh_TW", + "en", + ), "lang can only be one of \ + zh_CN, zh_TW, en language codes" + return self._get("order/info", params={"openid": user_id, "lang": lang}) def get_followers(self, first_user_id=None): """ @@ -56,11 +54,8 @@ def get_followers(self, first_user_id=None): """ params = {} if first_user_id: - params['next_openid'] = first_user_id - return self._get( - 'order/get', - params=params - ) + params["next_openid"] = first_user_id + return self._get("order/get", params=params) def iter_followers(self, first_user_id=None): """ @@ -86,9 +81,9 @@ def iter_followers(self, first_user_id=None): # 微信有个bug(或者叫feature),没有下一页,也返回next_openid这个字段 # 所以要通过total_count和data的长度比较判断(比较麻烦,并且不稳定) # 或者获得结果前先判断data是否存在 - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid if not first_user_id: return @@ -113,11 +108,7 @@ def update_remark(self, user_id, remark): """ return self._post( - 'order/info/updateremark', - data={ - 'openid': user_id, - 'remark': remark - } + "order/info/updateremark", data={"openid": user_id, "remark": remark} ) def get_group_id(self, user_id): @@ -139,9 +130,9 @@ def get_group_id(self, user_id): """ res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -169,16 +160,16 @@ def get_batch(self, user_list): """ if all((isinstance(x, six.string_types) for x in user_list)): - user_list = [{'openid': oid} for oid in user_list] + user_list = [{"openid": oid} for oid in user_list] res = self._post( - 'order/info/batchget', - data={'user_list': user_list}, - result_processor=lambda x: x['user_info_list'] + "order/info/batchget", + data={"user_list": user_list}, + result_processor=lambda x: x["user_info_list"], ) return res def change_openid(self, from_appid, openid_list): - '''微信公众号主体变更迁移用户 openid + """微信公众号主体变更迁移用户 openid 详情请参考 http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html @@ -186,9 +177,9 @@ def change_openid(self, from_appid, openid_list): :param from_appid: 原公众号的 appid :param openid_list: 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 :return: 转换后的 openid 信息列表 - ''' + """ return self._post( - 'changeopenid', - data={'from_appid': from_appid, 'openid_list': openid_list}, - result_processor=lambda x: x['result_list'] + "changeopenid", + data={"from_appid": from_appid, "openid_list": openid_list}, + result_processor=lambda x: x["result_list"], ) diff --git a/chapter12/booking_system/exts/wechatpy/client/api/wifi.py b/chapter12/booking_system/exts/wechatpy/client/api/wifi.py index 0852103..a513764 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/wifi.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/wifi.py @@ -8,7 +8,7 @@ class WeChatWiFi(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/bizwifi/' + API_BASE_URL = "https://api.weixin.qq.com/bizwifi/" def list_shops(self, page_index=1, page_size=20): """ @@ -22,12 +22,12 @@ def list_shops(self, page_index=1, page_size=20): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/list', + "shop/list", data={ - 'pageindex': page_index, - 'pagesize': page_size, + "pageindex": page_index, + "pagesize": page_size, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -40,11 +40,11 @@ def get_shop(self, shop_id=0): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/get', + "shop/get", data={ - 'shop_id': shop_id, + "shop_id": shop_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -63,13 +63,13 @@ def add_device(self, shop_id, ssid, password, bssid): :return: 返回的 JSON 数据包 """ return self._post( - 'device/add', + "device/add", data={ - 'shop_id': shop_id, - 'ssid': ssid, - 'password': password, - 'bssid': bssid, - } + "shop_id": shop_id, + "ssid": ssid, + "password": password, + "bssid": bssid, + }, ) def list_devices(self, shop_id=None, page_index=1, page_size=20): @@ -84,16 +84,8 @@ def list_devices(self, shop_id=None, page_index=1, page_size=20): :param page_size: 可选,每页的个数,默认20个,最大20个 :return: 返回的 JSON 数据包 """ - data = optionaldict( - shop_id=shop_id, - pageindex=page_index, - pagesize=page_size - ) - res = self._post( - 'device/list', - data=data, - result_processor=lambda x: x['data'] - ) + data = optionaldict(shop_id=shop_id, pageindex=page_index, pagesize=page_size) + res = self._post("device/list", data=data, result_processor=lambda x: x["data"]) return res def delete_device(self, bssid): @@ -106,7 +98,7 @@ def delete_device(self, bssid): :param bssid: 无线网络设备无线mac地址,格式冒号分隔,字符长度17个,并且字母小写 :return: 返回的 JSON 数据包 """ - return self._post('device/delete', data={'bssid': bssid}) + return self._post("device/delete", data={"bssid": bssid}) def get_qrcode_url(self, shop_id, img_id): """ @@ -121,12 +113,12 @@ def get_qrcode_url(self, shop_id, img_id): :return: 二维码图片网址 """ res = self._post( - 'qrcode/get', + "qrcode/get", data={ - 'shop_id': shop_id, - 'img_id': img_id, + "shop_id": shop_id, + "img_id": img_id, }, - result_processor=lambda x: x['data']['qrcode_url'] + result_processor=lambda x: x["data"]["qrcode_url"], ) return res @@ -143,12 +135,12 @@ def set_homepage(self, shop_id, template_id, url=None): :return: 返回的 JSON 数据包 """ data = { - 'shop_id': shop_id, - 'template_id': template_id, + "shop_id": shop_id, + "template_id": template_id, } if url: - data['struct'] = {'url': url} - return self._post('homepage/set', data=data) + data["struct"] = {"url": url} + return self._post("homepage/set", data=data) def get_homepage(self, shop_id): """ @@ -161,9 +153,9 @@ def get_homepage(self, shop_id): :return: 返回的 JSON 数据包 """ res = self._post( - 'homepage/get', - data={'shop_id': shop_id}, - result_processor=lambda x: x['data'] + "homepage/get", + data={"shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res @@ -180,16 +172,12 @@ def list_statistics(self, begin_date, end_date, shop_id=-1): :return: 返回的 JSON 数据包 """ if isinstance(begin_date, (datetime, date)): - begin_date = begin_date.strftime('%Y-%m-%d') + begin_date = begin_date.strftime("%Y-%m-%d") if isinstance(end_date, (datetime, date)): - end_date = end_date.strftime('%Y-%m-%d') + end_date = end_date.strftime("%Y-%m-%d") res = self._post( - 'statistics/list', - data={ - 'begin_date': begin_date, - 'end_date': end_date, - 'shop_id': shop_id - }, - result_processor=lambda x: x['data'] + "statistics/list", + data={"begin_date": begin_date, "end_date": end_date, "shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res diff --git a/chapter12/booking_system/exts/wechatpy/client/api/wxa.py b/chapter12/booking_system/exts/wechatpy/client/api/wxa.py index 1c44460..91077d3 100644 --- a/chapter12/booking_system/exts/wechatpy/client/api/wxa.py +++ b/chapter12/booking_system/exts/wechatpy/client/api/wxa.py @@ -7,7 +7,7 @@ class WeChatWxa(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create_qrcode(self, path, width=430): """ @@ -16,49 +16,49 @@ def create_qrcode(self, path, width=430): https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'cgi-bin/wxaapp/createwxaqrcode', - data={ - 'path': path, - 'width': width - } + "cgi-bin/wxaapp/createwxaqrcode", data={"path": path, "width": width} ) - def get_wxa_code(self, - path, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - is_hyaline=False): + def get_wxa_code( + self, + path, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + is_hyaline=False, + ): """ 创建小程序码(接口A: 适用于需要的码数量较少的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacode', + "wxa/getwxacode", data={ - 'path': path, - 'width': width, - 'auto_color': auto_color, - 'line_color': line_color, - 'is_hyaline': is_hyaline, - } + "path": path, + "width": width, + "auto_color": auto_color, + "line_color": line_color, + "is_hyaline": is_hyaline, + }, ) - def get_wxa_code_unlimited(self, - scene, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - page=None, - is_hyaline=False): + def get_wxa_code_unlimited( + self, + scene, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + page=None, + is_hyaline=False, + ): """ 创建小程序码(接口B:适用于需要的码数量极多,或仅临时使用的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacodeunlimit', + "wxa/getwxacodeunlimit", data=optionaldict( scene=scene, page=page, @@ -66,10 +66,19 @@ def get_wxa_code_unlimited(self, auto_color=auto_color, line_color=line_color, is_hyaline=is_hyaline, - ) + ), ) - def send_template_message(self, user_id, template_id, data, form_id, page=None, color=None, emphasis_keyword=None): + def send_template_message( + self, + user_id, + template_id, + data, + form_id, + page=None, + color=None, + emphasis_keyword=None, + ): """ 发送模板消息 详情请参考 @@ -84,12 +93,16 @@ def send_template_message(self, user_id, template_id, data, form_id, page=None, color=color, emphasis_keyword=emphasis_keyword, ) - return self._post( - 'cgi-bin/message/wxopen/template/send', - data=tpl_data - ) + return self._post("cgi-bin/message/wxopen/template/send", data=tpl_data) - def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_domain=(), download_domain=()): + def modify_domain( + self, + action, + request_domain=(), + wsrequest_domain=(), + upload_domain=(), + download_domain=(), + ): """ 修改小程序服务器授权域名 详情请参考 @@ -102,14 +115,14 @@ def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_d :param download_domain: download file 合法域名 """ return self._post( - 'wxa/modify_domain', + "wxa/modify_domain", data={ - 'action': action, - 'requestdomain': request_domain, - 'wsrequestdomain': wsrequest_domain, - 'uploaddomain': upload_domain, - 'downloaddomain': download_domain, - } + "action": action, + "requestdomain": request_domain, + "wsrequestdomain": wsrequest_domain, + "uploaddomain": upload_domain, + "downloaddomain": download_domain, + }, ) def bind_tester(self, wechat_id): @@ -121,10 +134,10 @@ def bind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/bind_tester', + "wxa/bind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def unbind_tester(self, wechat_id): @@ -136,10 +149,10 @@ def unbind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/unbind_tester', + "wxa/unbind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def commit(self, template_id, ext_json, version, description): @@ -154,12 +167,12 @@ def commit(self, template_id, ext_json, version, description): :param description: 代码描述,开发者可自定义 """ return self._post( - 'wxa/commit', + "wxa/commit", data={ - 'template_id': template_id, - 'ext_json': ext_json, - 'user_version': version, - 'user_desc': description, + "template_id": template_id, + "ext_json": ext_json, + "user_version": version, + "user_desc": description, }, ) @@ -172,7 +185,7 @@ def get_qrcode(self): :rtype: requests.Response """ - return self._get('wxa/get_qrcode') + return self._get("wxa/get_qrcode") def get_category(self): """ @@ -183,8 +196,8 @@ def get_category(self): :rtype: list[dict] """ return self._get( - 'wxa/get_category', - result_processor=lambda x: x['category_list'], + "wxa/get_category", + result_processor=lambda x: x["category_list"], ) def get_page(self): @@ -196,8 +209,8 @@ def get_page(self): :rtype: list """ return self._get( - 'wxa/get_page', - result_processor=lambda x: x['page_list'], + "wxa/get_page", + result_processor=lambda x: x["page_list"], ) def submit_audit(self, item_list): @@ -212,11 +225,11 @@ def submit_audit(self, item_list): :rtype: int """ return self._post( - 'wxa/submit_audit', + "wxa/submit_audit", data={ - 'item_list': item_list, + "item_list": item_list, }, - result_processor=lambda x: x['auditid'], + result_processor=lambda x: x["auditid"], ) def get_audit_status(self, auditid): @@ -230,9 +243,9 @@ def get_audit_status(self, auditid): :return: 一个包含 status, reason 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ return self._post( - 'wxa/get_auditstatus', + "wxa/get_auditstatus", data={ - 'auditid': auditid, + "auditid": auditid, }, ) @@ -244,9 +257,7 @@ def get_latest_audit_status(self): :return: 一个包含 status, reason, auditid 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ - return self._get( - 'wxa/get_latest_auditstatus' - ) + return self._get("wxa/get_latest_auditstatus") def release(self): """ @@ -255,7 +266,7 @@ def release(self): https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&id=open1489140610_Uavc4 """ return self._post( - 'wxa/release', + "wxa/release", data={}, ) @@ -269,9 +280,9 @@ def change_visit_status(self, close=False): :type close: bool """ return self._post( - 'wxa/change_visitstatus', + "wxa/change_visitstatus", data={ - 'action': 'close' if close else 'open', + "action": "close" if close else "open", }, ) @@ -289,10 +300,10 @@ def list_library_templates(self, offset=0, count=20): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/list', + "cgi-bin/wxopen/template/library/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, ) @@ -306,9 +317,9 @@ def get_library_template(self, template_short_id): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/get', + "cgi-bin/wxopen/template/library/get", data={ - 'id': template_short_id, + "id": template_short_id, }, ) @@ -326,12 +337,12 @@ def list_templates(self, offset=0, count=20): :rtype: list[dict] """ return self._post( - 'cgi-bin/wxopen/template/list', + "cgi-bin/wxopen/template/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, - result_processor=lambda x: x['list'], + result_processor=lambda x: x["list"], ) def add_template(self, template_short_id, keyword_id_list): @@ -346,12 +357,12 @@ def add_template(self, template_short_id, keyword_id_list): :return: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/add', + "cgi-bin/wxopen/template/add", data={ - 'id': template_short_id, - 'keyword_id_list': keyword_id_list, + "id": template_short_id, + "keyword_id_list": keyword_id_list, }, - result_processor=lambda x: x['template_id'], + result_processor=lambda x: x["template_id"], ) def del_template(self, template_id): @@ -363,9 +374,9 @@ def del_template(self, template_id): :param template_id: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/del', + "cgi-bin/wxopen/template/del", data={ - 'template_id': template_id, + "template_id": template_id, }, ) @@ -379,11 +390,11 @@ def create_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/create', + "cgi-bin/open/create", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def get_open(self, appid): @@ -396,11 +407,11 @@ def get_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/get', + "cgi-bin/open/get", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def bind_open(self, appid, open_appid): @@ -413,11 +424,11 @@ def bind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/bind', + "cgi-bin/open/bind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def unbind_open(self, appid, open_appid): @@ -430,11 +441,11 @@ def unbind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/unbind', + "cgi-bin/open/unbind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def code_to_session(self, js_code): @@ -447,11 +458,11 @@ def code_to_session(self, js_code): :return: """ return self._get( - 'sns/jscode2session', + "sns/jscode2session", params={ - 'appid': self.appid, - 'secret': self.secret, - 'js_code': js_code, - 'grant_type': 'authorization_code' - } + "appid": self.appid, + "secret": self.secret, + "js_code": js_code, + "grant_type": "authorization_code", + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/client/base.py b/chapter12/booking_system/exts/wechatpy/client/base.py index 88c7b85..1ac1b91 100644 --- a/chapter12/booking_system/exts/wechatpy/client/base.py +++ b/chapter12/booking_system/exts/wechatpy/client/base.py @@ -23,7 +23,7 @@ def _is_api_endpoint(obj): class BaseWeChatClient(object): - API_BASE_URL = '' + API_BASE_URL = "" def __new__(cls, *args, **kwargs): self = super(BaseWeChatClient, cls).__new__(cls) @@ -34,7 +34,9 @@ def __new__(cls, *args, **kwargs): setattr(self, name, api) return self - def __init__(self, appid, access_token=None, session=None, timeout=None, auto_retry=True): + def __init__( + self, appid, access_token=None, session=None, timeout=None, auto_retry=True + ): self._http = requests.Session() self.appid = appid self.expires_at = None @@ -47,7 +49,7 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -58,35 +60,30 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'access_token' not in kwargs['params']: - kwargs['params']['access_token'] = self.access_token - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - result_processor = kwargs.pop('result_processor', None) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "access_token" not in kwargs["params"] + ): + kwargs["params"]["access_token"] = self.access_token + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + result_processor = kwargs.pop("result_processor", None) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -95,24 +92,23 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - return self._handle_result( - res, method, url, result_processor, **kwargs - ) + return self._handle_result(res, method, url, result_processor, **kwargs) def _decode_result(self, res): try: - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) except (TypeError, ValueError): # Return origin response object if we can not decode it as JSON - logger.debug('Can not decode response as JSON', exc_info=True) + logger.debug("Can not decode response as JSON", exc_info=True) return res return result - def _handle_result(self, res, method=None, url=None, - result_processor=None, **kwargs): + def _handle_result( + self, res, method=None, url=None, result_processor=None, **kwargs + ): if not isinstance(res, dict): # Dirty hack around asyncio based AsyncWeChatClient result = self._decode_result(res) @@ -122,23 +118,24 @@ def _handle_result(self, res, method=None, url=None, if not isinstance(result, dict): return result - if 'base_resp' in result: + if "base_resp" in result: # Different response in device APIs. Fuck tencent! - result.update(result.pop('base_resp')) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result.update(result.pop("base_resp")) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Access token expired, fetch a new one and retry request') + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info("Access token expired, fetch a new one and retry request") self.fetch_access_token() access_token = self.session.get(self.access_token_key) - kwargs['params']['access_token'] = access_token + kwargs["params"]["access_token"] = access_token return self._request( method=method, url_or_endpoint=url, @@ -148,56 +145,43 @@ def _handle_result(self, res, method=None, url=None, elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result if not result_processor else result_processor(result) def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def _get(self, url, **kwargs): - warnings.warn('`_get` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `get` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_get` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `get` instead", + DeprecationWarning, + stacklevel=2, + ) return self.get(url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def _post(self, url, **kwargs): - warnings.warn('`_post` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `post` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_post` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `post` instead", + DeprecationWarning, + stacklevel=2, + ) return self.post(url, **kwargs) def _fetch_access_token(self, url, params): - """ The real fetch access token """ - logger.info('Fetching access token') - res = self._http.get( - url=url, - params=params - ) + """The real fetch access token""" + logger.info("Fetching access token") + res = self._http.get(url=url, params=params) try: res.raise_for_status() except requests.RequestException as reqe: @@ -206,26 +190,22 @@ def _fetch_access_token(self, url, params): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] - self.session.set( - self.access_token_key, - result['access_token'], - expires_in - ) + if "expires_in" in result: + expires_in = result["expires_in"] + self.session.set(self.access_token_key, result["access_token"], expires_in) self.expires_at = int(time.time()) + expires_in return result @@ -234,7 +214,7 @@ def fetch_access_token(self): @property def access_token(self): - """ WeChat access token """ + """WeChat access token""" access_token = self.session.get(self.access_token_key) if access_token: if not self.expires_at: diff --git a/chapter12/booking_system/exts/wechatpy/component.py b/chapter12/booking_system/exts/wechatpy/component.py index 980daa4..e663e23 100644 --- a/chapter12/booking_system/exts/wechatpy/component.py +++ b/chapter12/booking_system/exts/wechatpy/component.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.component - ~~~~~~~~~~~~~~~ +wechatpy.component +~~~~~~~~~~~~~~~ - This module provides client library for WeChat Open Platform +This module provides client library for WeChat Open Platform - :copyright: (c) 2015 by hunter007. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2015 by hunter007. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -22,8 +22,12 @@ from exts.wechatpy.client import WeChatComponentClient from exts.wechatpy.constants import WeChatErrorCode from exts.wechatpy.crypto import WeChatCrypto -from exts.wechatpy.exceptions import APILimitedException, WeChatClientException, WeChatOAuthException, \ - WeChatComponentOAuthException +from exts.wechatpy.exceptions import ( + APILimitedException, + WeChatClientException, + WeChatOAuthException, + WeChatComponentOAuthException, +) from exts.wechatpy.fields import DateTimeField, StringField from exts.wechatpy.messages import MessageMetaClass from exts.wechatpy.session.memorystorage import MemoryStorage @@ -38,22 +42,23 @@ def register_component_message(msg_type): def register(cls): COMPONENT_MESSAGE_TYPES[msg_type] = cls return cls + return register class BaseComponentMessage(six.with_metaclass(MessageMetaClass)): """Base class for all component messages and events""" - type = 'unknown' - appid = StringField('AppId') - create_time = DateTimeField('CreateTime') + + type = "unknown" + appid = StringField("AppId") + create_time = DateTimeField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -61,60 +66,67 @@ def __repr__(self): return to_text(_repr) -@register_component_message('component_verify_ticket') +@register_component_message("component_verify_ticket") class ComponentVerifyTicketMessage(BaseComponentMessage): """ component_verify_ticket协议 """ - type = 'component_verify_ticket' - verify_ticket = StringField('ComponentVerifyTicket') + + type = "component_verify_ticket" + verify_ticket = StringField("ComponentVerifyTicket") -@register_component_message('unauthorized') +@register_component_message("unauthorized") class ComponentUnauthorizedMessage(BaseComponentMessage): """ 取消授权通知 """ - type = 'unauthorized' - authorizer_appid = StringField('AuthorizerAppid') + type = "unauthorized" + authorizer_appid = StringField("AuthorizerAppid") -@register_component_message('authorized') + +@register_component_message("authorized") class ComponentAuthorizedMessage(ComponentUnauthorizedMessage): """ 新增授权通知 """ - type = 'authorized' - authorization_code = StringField('AuthorizationCode') - authorization_code_expired_time = StringField('AuthorizationCodeExpiredTime') - pre_auth_code = StringField('PreAuthCode') + + type = "authorized" + authorization_code = StringField("AuthorizationCode") + authorization_code_expired_time = StringField("AuthorizationCodeExpiredTime") + pre_auth_code = StringField("PreAuthCode") -@register_component_message('updateauthorized') +@register_component_message("updateauthorized") class ComponentUpdateauthorizedMessage(ComponentAuthorizedMessage): """ 更新授权通知 """ - type = 'updateauthorized' + + type = "updateauthorized" class ComponentUnknownMessage(BaseComponentMessage): """ 未知通知 """ - type = 'unknown' + type = "unknown" -class BaseWeChatComponent(object): - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin' - def __init__(self, - component_appid, - component_appsecret, - component_token, - encoding_aes_key, - session=None, - auto_retry=True): +class BaseWeChatComponent(object): + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin" + + def __init__( + self, + component_appid, + component_appsecret, + component_token, + encoding_aes_key, + session=None, + auto_retry=True, + ): """ :param component_appid: 第三方平台appid :param component_appsecret: 第三方平台appsecret @@ -125,8 +137,7 @@ def __init__(self, self.component_appid = component_appid self.component_appsecret = component_appsecret self.expires_at = None - self.crypto = WeChatCrypto( - component_token, encoding_aes_key, component_appid) + self.crypto = WeChatCrypto(component_token, encoding_aes_key, component_appid) self.session = session or MemoryStorage() self.auto_retry = auto_retry @@ -135,7 +146,7 @@ def __init__(self, from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -143,32 +154,26 @@ def __init__(self, @property def component_verify_ticket(self): - return self.session.get('component_verify_ticket') + return self.session.get("component_verify_ticket") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'component_access_token' not in kwargs['params']: - kwargs['params'][ - 'component_access_token'] = self.access_token - if isinstance(kwargs['data'], dict): - kwargs['data'] = json.dumps(kwargs['data']) - - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "component_access_token" not in kwargs["params"] + ): + kwargs["params"]["component_access_token"] = self.access_token + if isinstance(kwargs["data"], dict): + kwargs["data"] = json.dumps(kwargs["data"]) + + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -177,49 +182,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method, url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.fetch_access_token() - kwargs['params']['component_access_token'] = self.session.get( - 'component_access_token' + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + self.fetch_access_token() + kwargs["params"]["component_access_token"] = self.session.get( + "component_access_token" ) + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result @@ -231,26 +227,22 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ - url = '{0}{1}'.format( - self.API_BASE_URL, - '/component/api_component_token' - ) + url = "{0}{1}".format(self.API_BASE_URL, "/component/api_component_token") return self._fetch_access_token( url=url, - data=json.dumps({ - 'component_appid': self.component_appid, - 'component_appsecret': self.component_appsecret, - 'component_verify_ticket': self.component_verify_ticket - }) + data=json.dumps( + { + "component_appid": self.component_appid, + "component_appsecret": self.component_appsecret, + "component_verify_ticket": self.component_verify_ticket, + } + ), ) def _fetch_access_token(self, url, data): - """ The real fetch access token """ - logger.info('Fetching component access token') - res = self._http.post( - url=url, - data=data - ) + """The real fetch access token""" + logger.info("Fetching component access token") + res = self._http.post(url=url, data=data) try: res.raise_for_status() except requests.RequestException as reqe: @@ -259,33 +251,31 @@ def _fetch_access_token(self, url, data): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - 'component_access_token', - result['component_access_token'], - expires_in + "component_access_token", result["component_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result @property def access_token(self): - """ WeChat component access token """ - access_token = self.session.get('component_access_token') + """WeChat component access token""" + access_token = self.session.get("component_access_token") if access_token: if not self.expires_at: # order provided access_token, just return it @@ -296,41 +286,39 @@ def access_token(self): return access_token self.fetch_access_token() - return self.session.get('component_access_token') + return self.session.get("component_access_token") def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) class WeChatComponent(BaseWeChatComponent): - PRE_AUTH_URL = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage' + PRE_AUTH_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage" def get_pre_auth_url(self, redirect_uri): - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") return "{0}?component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - self.PRE_AUTH_URL, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri - ) + self.PRE_AUTH_URL, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, + ) def get_pre_auth_url_m(self, redirect_uri): """ 快速获取pre auth url,可以直接微信中发送该链接,直接授权 """ url = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=3&no_scan=1&" - redirect_uri = quote(redirect_uri, safe='') + redirect_uri = quote(redirect_uri, safe="") return "{0}component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - url, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri + url, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, ) def create_preauthcode(self): @@ -338,10 +326,8 @@ def create_preauthcode(self): 获取预授权码 """ return self.post( - '/component/api_create_preauthcode', - data={ - 'component_appid': self.component_appid - } + "/component/api_create_preauthcode", + data={"component_appid": self.component_appid}, ) def _query_auth(self, authorization_code): @@ -351,11 +337,11 @@ def _query_auth(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ return self.post( - '/component/api_query_auth', + "/component/api_query_auth", data={ - 'component_appid': self.component_appid, - 'authorization_code': authorization_code - } + "component_appid": self.component_appid, + "authorization_code": authorization_code, + }, ) def query_auth(self, authorization_code): @@ -366,28 +352,35 @@ def query_auth(self, authorization_code): """ result = self._query_auth(authorization_code) - assert result is not None \ - and 'authorization_info' in result \ - and 'authorizer_appid' in result['authorization_info'] + assert ( + result is not None + and "authorization_info" in result + and "authorizer_appid" in result["authorization_info"] + ) - authorizer_appid = result['authorization_info']['authorizer_appid'] - if 'authorizer_access_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_access_token']: - access_token = result['authorization_info']['authorizer_access_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + authorizer_appid = result["authorization_info"]["authorizer_appid"] + if ( + "authorizer_access_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_access_token"] + ): + access_token = result["authorization_info"]["authorizer_access_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in result['authorization_info']: - expires_in = result['authorization_info']['expires_in'] + if "expires_in" in result["authorization_info"]: + expires_in = result["authorization_info"]["expires_in"] self.session.set(access_token_key, access_token, expires_in) - if 'authorizer_refresh_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_refresh_token']: - refresh_token = result['authorization_info']['authorizer_refresh_token'] - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) - self.session.set(refresh_token_key, refresh_token) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 + if ( + "authorizer_refresh_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_refresh_token"] + ): + refresh_token = result["authorization_info"]["authorizer_refresh_token"] + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) + self.session.set( + refresh_token_key, refresh_token + ) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 return result - def refresh_authorizer_token( - self, authorizer_appid, authorizer_refresh_token): + def refresh_authorizer_token(self, authorizer_appid, authorizer_refresh_token): """ 获取(刷新)授权公众号的令牌 @@ -395,12 +388,12 @@ def refresh_authorizer_token( :params authorizer_refresh_token: 授权方的刷新令牌 """ return self.post( - '/component/api_authorizer_token', + "/component/api_authorizer_token", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'authorizer_refresh_token': authorizer_refresh_token - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "authorizer_refresh_token": authorizer_refresh_token, + }, ) def get_authorizer_info(self, authorizer_appid): @@ -410,11 +403,11 @@ def get_authorizer_info(self, authorizer_appid): :params authorizer_appid: 授权方appid """ return self.post( - '/component/api_get_authorizer_info', + "/component/api_get_authorizer_info", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + }, ) def get_authorizer_option(self, authorizer_appid, option_name): @@ -425,16 +418,15 @@ def get_authorizer_option(self, authorizer_appid, option_name): :params option_name: 选项名称 """ return self.post( - '/component/api_get_authorizer_option', + "/component/api_get_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + }, ) - def set_authorizer_option( - self, authorizer_appid, option_name, option_value): + def set_authorizer_option(self, authorizer_appid, option_name, option_value): """ 设置授权方的选项信息 @@ -443,13 +435,13 @@ def set_authorizer_option( :params option_value: 设置的选项值 """ return self.post( - '/component/api_set_authorizer_option', + "/component/api_set_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name, - 'option_value': option_value - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + "option_value": option_value, + }, ) def get_client_by_authorization_code(self, authorization_code): @@ -458,17 +450,19 @@ def get_client_by_authorization_code(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ - warnings.warn('`get_client_by_authorization_code` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` parse message and ' - 'Use `get_client_by_appid` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_client_by_authorization_code` method of `WeChatComponent` is deprecated," + "Use `parse_message` parse message and " + "Use `get_client_by_appid` instead", + DeprecationWarning, + stacklevel=2, + ) result = self.query_auth(authorization_code) - access_token = result['authorization_info']['authorizer_access_token'] - refresh_token = result['authorization_info']['authorizer_refresh_token'] # NOQA - authorizer_appid = result['authorization_info']['authorizer_appid'] # noqa + access_token = result["authorization_info"]["authorizer_access_token"] + refresh_token = result["authorization_info"]["authorizer_refresh_token"] # NOQA + authorizer_appid = result["authorization_info"]["authorizer_appid"] # noqa return WeChatComponentClient( - authorizer_appid, self, access_token, refresh_token, - session=self.session + authorizer_appid, self, access_token, refresh_token, session=self.session ) def get_client_by_appid(self, authorizer_appid): @@ -477,30 +471,23 @@ def get_client_by_appid(self, authorizer_appid): :params authorizer_appid: 授权公众号appid """ - access_token_key = '{0}_access_token'.format(authorizer_appid) - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) + access_token_key = "{0}_access_token".format(authorizer_appid) + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) access_token = self.session.get(access_token_key) refresh_token = self.session.get(refresh_token_key) assert refresh_token if not access_token: - ret = self.refresh_authorizer_token( - authorizer_appid, - refresh_token - ) - access_token = ret['authorizer_access_token'] - refresh_token = ret['authorizer_refresh_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + ret = self.refresh_authorizer_token(authorizer_appid, refresh_token) + access_token = ret["authorizer_access_token"] + refresh_token = ret["authorizer_refresh_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in ret: - expires_in = ret['expires_in'] + if "expires_in" in ret: + expires_in = ret["expires_in"] self.session.set(access_token_key, access_token, expires_in) - return WeChatComponentClient( - authorizer_appid, - self, - session=self.session - ) + return WeChatComponentClient(authorizer_appid, self, session=self.session) def parse_message(self, msg, msg_signature, timestamp, nonce): """ @@ -512,13 +499,15 @@ def parse_message(self, msg, msg_signature, timestamp, nonce): :params nonce: 随机数 """ content = self.crypto.decrypt_message(msg, msg_signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] - message_type = message['InfoType'].lower() - message_class = COMPONENT_MESSAGE_TYPES.get(message_type, ComponentUnknownMessage) + message = xmltodict.parse(to_text(content))["xml"] + message_type = message["InfoType"].lower() + message_class = COMPONENT_MESSAGE_TYPES.get( + message_type, ComponentUnknownMessage + ) msg = message_class(message) - if msg.type == 'component_verify_ticket': + if msg.type == "component_verify_ticket": self.session.set(msg.type, msg.verify_ticket) - elif msg.type in ('authorized', 'updateauthorized'): + elif msg.type in ("authorized", "updateauthorized"): msg.query_auth_result = self.query_auth(msg.authorization_code) return msg @@ -531,11 +520,14 @@ def cache_component_verify_ticket(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`cache_component_verify_ticket` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`cache_component_verify_ticket` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] o = ComponentVerifyTicketMessage(message) self.session.set(o.type, o.verify_ticket) @@ -548,11 +540,14 @@ def get_unauthorized(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`get_unauthorized` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_unauthorized` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] return ComponentUnauthorizedMessage(message) def get_component_oauth(self, authorizer_appid): @@ -565,16 +560,25 @@ def get_component_oauth(self, authorizer_appid): class ComponentOAuth(object): - """ 微信开放平台 代公众号 OAuth 网页授权 + """微信开放平台 代公众号 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' - def __init__(self, app_id, component_appid=None, component_access_token=None, - redirect_uri=None, scope='snsapi_base', state='', component=None): + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" + + def __init__( + self, + app_id, + component_appid=None, + component_access_token=None, + redirect_uri=None, + scope="snsapi_base", + state="", + component=None, + ): """ :param app_id: 微信公众号 app_id @@ -584,42 +588,55 @@ def __init__(self, app_id, component_appid=None, component_access_token=None, self.app_id = app_id self.component = component if self.component is None: - warnings.warn('cannot found `component` param of `ComponentOAuth` `__init__` method,' - 'Use `WeChatComponent.get_component_oauth` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "cannot found `component` param of `ComponentOAuth` `__init__` method," + "Use `WeChatComponent.get_component_oauth` instead", + DeprecationWarning, + stacklevel=2, + ) - self.component = ObjectDict({'component_appid': component_appid, 'access_token': component_access_token}) + self.component = ObjectDict( + { + "component_appid": component_appid, + "access_token": component_access_token, + } + ) if redirect_uri is not None: - warnings.warn('found `redirect_uri` param of `ComponentOAuth` `__init__` method,' - 'Use `ComponentOAuth.get_authorize_url` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "found `redirect_uri` param of `ComponentOAuth` `__init__` method," + "Use `ComponentOAuth.get_authorize_url` instead", + DeprecationWarning, + stacklevel=2, + ) self.authorize_url = self.get_authorize_url(redirect_uri, scope, state) - def get_authorize_url(self, redirect_uri, scope='snsapi_base', state=''): + def get_authorize_url(self, redirect_uri, scope="snsapi_base", state=""): """ :param redirect_uri: 重定向地址,需要urlencode,这里填写的应是服务开发方的回调地址 :param scope: 可选,微信公众号 OAuth2 scope,默认为 ``snsapi_base`` :param state: 可选,重定向后会带上state参数,开发者可以填写任意参数值,最多128字节 """ - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', + "&response_type=code&scope=", scope, ] if state: - url_list.extend(['&state=', state]) - url_list.extend([ - '&component_appid=', - self.component.component_appid, - ]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.extend( + [ + "&component_appid=", + self.component.component_appid, + ] + ) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -628,20 +645,20 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/access_token', + "sns/oauth2/component/access_token", params={ - 'appid': self.app_id, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - 'code': code, - 'grant_type': 'authorization_code', - } + "appid": self.app_id, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res def refresh_access_token(self, refresh_token): @@ -651,24 +668,24 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/refresh_token', + "sns/oauth2/component/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): - """ 获取用户基本信息(需授权作用域为snsapi_userinfo) + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): + """获取用户基本信息(需授权作用域为snsapi_userinfo) 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。 @@ -680,33 +697,24 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -715,53 +723,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method=method, url=url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.component.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.component.fetch_access_token() - kwargs['params']['component_access_token'] = self.component.access_token - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) + self.component.fetch_access_token() + kwargs["params"]["component_access_token"] = self.component.access_token + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatComponentOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) diff --git a/chapter12/booking_system/exts/wechatpy/constants.py b/chapter12/booking_system/exts/wechatpy/constants.py index 628476a..967736e 100644 --- a/chapter12/booking_system/exts/wechatpy/constants.py +++ b/chapter12/booking_system/exts/wechatpy/constants.py @@ -6,26 +6,28 @@ @unique class UserFormInfoFlag(Enum): - """ 微信卡券会员卡格式化的选项类型 """ - MOBILE = 'USER_FORM_INFO_FLAG_MOBILE' # 手机号 - SEX = 'USER_FORM_INFO_FLAG_SEX' # 性别 - NAME = 'USER_FORM_INFO_FLAG_NAME' # 姓名 - BIRTHDAY = 'USER_FORM_INFO_FLAG_BIRTHDAY' # 生日 - IDCARD = 'USER_FORM_INFO_FLAG_IDCARD' # 身份证 - EMAIL = 'USER_FORM_INFO_FLAG_EMAIL' # 邮箱 - LOCATION = 'USER_FORM_INFO_FLAG_LOCATION' # 详细地址 - EDUCATION_BACKGRO = 'USER_FORM_INFO_FLAG_EDUCATION_BACKGRO' # 教育背景 - INDUSTRY = 'USER_FORM_INFO_FLAG_INDUSTRY' # 行业 - INCOME = 'USER_FORM_INFO_FLAG_INCOME' # 收入 - HABIT = 'USER_FORM_INFO_FLAG_HABIT' # 兴趣爱好 + """微信卡券会员卡格式化的选项类型""" + + MOBILE = "USER_FORM_INFO_FLAG_MOBILE" # 手机号 + SEX = "USER_FORM_INFO_FLAG_SEX" # 性别 + NAME = "USER_FORM_INFO_FLAG_NAME" # 姓名 + BIRTHDAY = "USER_FORM_INFO_FLAG_BIRTHDAY" # 生日 + IDCARD = "USER_FORM_INFO_FLAG_IDCARD" # 身份证 + EMAIL = "USER_FORM_INFO_FLAG_EMAIL" # 邮箱 + LOCATION = "USER_FORM_INFO_FLAG_LOCATION" # 详细地址 + EDUCATION_BACKGRO = "USER_FORM_INFO_FLAG_EDUCATION_BACKGRO" # 教育背景 + INDUSTRY = "USER_FORM_INFO_FLAG_INDUSTRY" # 行业 + INCOME = "USER_FORM_INFO_FLAG_INCOME" # 收入 + HABIT = "USER_FORM_INFO_FLAG_HABIT" # 兴趣爱好 @unique class ReimburseStatus(Enum): - """ 发票报销状态 """ - INIT = 'INVOICE_REIMBURSE_INIT' # 初始状态,未锁定,可提交报销 - LOCK = 'INVOICE_REIMBURSE_LOCK' # 已锁定,无法重复提交报销 - CLOSURE = 'INVOICE_REIMBURSE_CLOSURE' # 已核销,从用户卡包中移除 + """发票报销状态""" + + INIT = "INVOICE_REIMBURSE_INIT" # 初始状态,未锁定,可提交报销 + LOCK = "INVOICE_REIMBURSE_LOCK" # 已锁定,无法重复提交报销 + CLOSURE = "INVOICE_REIMBURSE_CLOSURE" # 已核销,从用户卡包中移除 @unique @@ -33,6 +35,7 @@ class WeChatErrorCode(IntEnum): """ 微信接口返回码,全局返回码请参考 https://mp.weixin.qq.com/wiki?id=mp1433747234 """ + # 系统错误 SYSTEM_ERROR = -1000 diff --git a/chapter12/booking_system/exts/wechatpy/crypto/__init__.py b/chapter12/booking_system/exts/wechatpy/crypto/__init__.py index 4c93dbd..0df8905 100644 --- a/chapter12/booking_system/exts/wechatpy/crypto/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/crypto/__init__.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.crypto - ~~~~~~~~~~~~~~~~ +wechatpy.crypto +~~~~~~~~~~~~~~~~ - This module provides some crypto tools for WeChat and WeChat enterprise +This module provides some crypto tools for WeChat and WeChat enterprise - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import json @@ -14,10 +14,7 @@ import base64 from exts.wechatpy.utils import to_text, to_binary, WeChatSigner -from exts.wechatpy.exceptions import ( - InvalidAppIdException, - InvalidSignatureException -) +from exts.wechatpy.exceptions import InvalidAppIdException, InvalidSignatureException from exts.wechatpy.crypto.base import BasePrpCrypto, WeChatCipher from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder @@ -40,29 +37,22 @@ def decrypt(self, text, app_id): class BaseWeChatCrypto(object): def __init__(self, token, encoding_aes_key, _id): - encoding_aes_key = to_binary(encoding_aes_key + '=') + encoding_aes_key = to_binary(encoding_aes_key + "=") self.key = base64.b64decode(encoding_aes_key) assert len(self.key) == 32 self.token = token self._id = _id - def _check_signature(self, - signature, - timestamp, - nonce, - echo_str, - crypto_class=None): + def _check_signature( + self, signature, timestamp, nonce, echo_str, crypto_class=None + ): _signature = _get_signature(self.token, timestamp, nonce, echo_str) if _signature != signature: raise InvalidSignatureException() pc = crypto_class(self.key) return pc.decrypt(echo_str, self._id) - def _encrypt_message(self, - msg, - nonce, - timestamp=None, - crypto_class=None): + def _encrypt_message(self, msg, nonce, timestamp=None, crypto_class=None): from exts.wechatpy.replies import BaseReply xml = """ @@ -77,25 +67,19 @@ def _encrypt_message(self, pc = crypto_class(self.key) encrypt = to_text(pc.encrypt(msg, self._id)) signature = _get_signature(self.token, timestamp, nonce, encrypt) - return to_text(xml.format( - encrypt=encrypt, - signature=signature, - timestamp=timestamp, - nonce=nonce - )) - - def _decrypt_message(self, - msg, - signature, - timestamp, - nonce, - crypto_class=None): + return to_text( + xml.format( + encrypt=encrypt, signature=signature, timestamp=timestamp, nonce=nonce + ) + ) + + def _decrypt_message(self, msg, signature, timestamp, nonce, crypto_class=None): if not isinstance(msg, dict): import xmltodict - msg = xmltodict.parse(to_text(msg))['xml'] + msg = xmltodict.parse(to_text(msg))["xml"] - encrypt = msg['Encrypt'] + encrypt = msg["Encrypt"] _signature = _get_signature(self.token, timestamp, nonce, encrypt) if _signature != signature: raise InvalidSignatureException() @@ -113,13 +97,7 @@ def encrypt_message(self, msg, nonce, timestamp=None): return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) class WeChatWxaCrypto(object): @@ -132,6 +110,6 @@ def decrypt_message(self, msg): decrypted = self.cipher.decrypt(raw_data) plaintext = PKCS7Encoder.decode(decrypted) decrypted_msg = json.loads(to_text(plaintext)) - if decrypted_msg['watermark']['appid'] != self.app_id: + if decrypted_msg["watermark"]["appid"] != self.app_id: raise InvalidAppIdException() return decrypted_msg diff --git a/chapter12/booking_system/exts/wechatpy/crypto/base.py b/chapter12/booking_system/exts/wechatpy/crypto/base.py index e12300e..a6f60d3 100644 --- a/chapter12/booking_system/exts/wechatpy/crypto/base.py +++ b/chapter12/booking_system/exts/wechatpy/crypto/base.py @@ -6,13 +6,14 @@ from exts.wechatpy.utils import to_text, to_binary, random_string, byte2int from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder + try: from exts.wechatpy.crypto.cryptography import WeChatCipher except ImportError: try: from exts.wechatpy.crypto.pycrypto import WeChatCipher except ImportError: - raise Exception('You must install either cryptography or pycryptodome!') + raise Exception("You must install either cryptography or pycryptodome!") class BasePrpCrypto(object): @@ -27,12 +28,12 @@ def _encrypt(self, text, _id): text = to_binary(text) tmp_list = [] tmp_list.append(to_binary(self.get_random_string())) - length = struct.pack(b'I', socket.htonl(len(text))) + length = struct.pack(b"I", socket.htonl(len(text))) tmp_list.append(length) tmp_list.append(text) tmp_list.append(to_binary(_id)) - text = b''.join(tmp_list) + text = b"".join(tmp_list) text = PKCS7Encoder.encode(text) ciphertext = to_binary(self.cipher.encrypt(text)) @@ -43,9 +44,9 @@ def _decrypt(self, text, _id, exception=None): plain_text = self.cipher.decrypt(base64.b64decode(text)) padding = byte2int(plain_text[-1]) content = plain_text[16:-padding] - xml_length = socket.ntohl(struct.unpack(b'I', content[:4])[0]) - xml_content = to_text(content[4:xml_length + 4]) - from_id = to_text(content[xml_length + 4:]) + xml_length = socket.ntohl(struct.unpack(b"I", content[:4])[0]) + xml_content = to_text(content[4 : xml_length + 4]) + from_id = to_text(content[xml_length + 4 :]) if from_id != _id: exception = exception or Exception raise exception() diff --git a/chapter12/booking_system/exts/wechatpy/crypto/cryptography.py b/chapter12/booking_system/exts/wechatpy/crypto/cryptography.py index e63917f..944923e 100644 --- a/chapter12/booking_system/exts/wechatpy/crypto/cryptography.py +++ b/chapter12/booking_system/exts/wechatpy/crypto/cryptography.py @@ -9,11 +9,7 @@ class WeChatCipher(object): def __init__(self, key, iv=None): iv = iv or key[:16] backend = default_backend() - self.cipher = Cipher( - algorithms.AES(key), - modes.CBC(iv), - backend=backend - ) + self.cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) def encrypt(self, plaintext): encryptor = self.cipher.encryptor() diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/__init__.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/__init__.py index 89b19c6..94d6b23 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/__init__.py @@ -6,7 +6,7 @@ class WeChatClient(BaseWeChatClient): - API_BASE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin/" agent = api.WeChatAgent() appchat = api.WeChatAppChat() @@ -25,8 +25,15 @@ class WeChatClient(BaseWeChatClient): tag = api.WeChatTag() user = api.WeChatUser() - def __init__(self, corp_id, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + corp_id, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( corp_id, access_token, session, timeout, auto_retry ) @@ -35,14 +42,11 @@ def __init__(self, corp_id, secret, access_token=None, @property def access_token_key(self): - return '{0}_{1}_access_token'.format(self.corp_id, self.secret[:10]) + return "{0}_{1}_access_token".format(self.corp_id, self.secret[:10]) def fetch_access_token(self): - """ Fetch access token""" + """Fetch access token""" return self._fetch_access_token( - url='https://qyapi.weixin.qq.com/cgi-bin/gettoken', - params={ - 'corpid': self.corp_id, - 'corpsecret': self.secret - } + url="https://qyapi.weixin.qq.com/cgi-bin/gettoken", + params={"corpid": self.corp_id, "corpsecret": self.secret}, ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/agent.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/agent.py index 2ba1d4c..d969d72 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/agent.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/agent.py @@ -19,12 +19,7 @@ def get(self, agent_id): :param agent_id: 应用id :return: 返回的 JSON 数据包 """ - return self._get( - 'agent/get', - params={ - 'agentid': agent_id - } - ) + return self._get("agent/get", params={"agentid": agent_id}) def list(self): """ @@ -33,18 +28,20 @@ def list(self): :return: 应用概况列表 """ - res = self._get('agent/list') - return res['agentlist'] + res = self._get("agent/list") + return res["agentlist"] - def set(self, - agent_id, - name=None, - description=None, - redirect_domain=None, - logo_media_id=None, - report_location_flag=0, - is_report_user=True, - is_report_enter=True): + def set( + self, + agent_id, + name=None, + description=None, + redirect_domain=None, + logo_media_id=None, + report_location_flag=0, + is_report_user=True, + is_report_enter=True, + ): """ 设置应用 https://work.weixin.qq.com/api/doc#90000/90135/90228 @@ -60,15 +57,12 @@ def set(self, :return: 返回的 JSON 数据包 """ agent_data = optionaldict() - agent_data['agentid'] = agent_id - agent_data['name'] = name - agent_data['description'] = description - agent_data['redirect_domain'] = redirect_domain - agent_data['logo_mediaid'] = logo_media_id - agent_data['report_location_flag'] = report_location_flag - agent_data['isreportenter'] = 1 if is_report_enter else 0 - agent_data['isreportuser'] = 1 if is_report_user else 0 - return self._post( - 'agent/set', - data=agent_data - ) + agent_data["agentid"] = agent_id + agent_data["name"] = name + agent_data["description"] = description + agent_data["redirect_domain"] = redirect_domain + agent_data["logo_mediaid"] = logo_media_id + agent_data["report_location_flag"] = report_location_flag + agent_data["isreportenter"] = 1 if is_report_enter else 0 + agent_data["isreportuser"] = 1 if is_report_user else 0 + return self._post("agent/set", data=agent_data) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/appchat.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/appchat.py index e6a5b46..1feb9e6 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/appchat.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/appchat.py @@ -35,7 +35,7 @@ def create(self, chat_id=None, name=None, owner=None, user_list=None): owner=owner, userlist=user_list, ) - return self._post('appchat/create', data=data) + return self._post("appchat/create", data=data) def get(self, chat_id): """ @@ -47,11 +47,12 @@ def get(self, chat_id): :param chat_id: 群聊id :return: 会话信息 """ - res = self._get('appchat/get', params={'chatid': chat_id}) - return res['chat_info'] + res = self._get("appchat/get", params={"chatid": chat_id}) + return res["chat_info"] - def update(self, chat_id, name=None, owner=None, - add_user_list=None, del_user_list=None): + def update( + self, chat_id, name=None, owner=None, add_user_list=None, del_user_list=None + ): """ 修改群聊会话 @@ -72,7 +73,7 @@ def update(self, chat_id, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('appchat/update', data=data) + return self._post("appchat/update", data=data) def send(self, chat_id, msg_type, **kwargs): """ @@ -84,16 +85,13 @@ def send(self, chat_id, msg_type, **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = { - 'chatid': chat_id, - 'safe': kwargs.get('safe') or 0 - } + data = {"chatid": chat_id, "safe": kwargs.get("safe") or 0} data.update(self._build_msg_content(msg_type, **kwargs)) - return self._post('appchat/send', data=data) + return self._post("appchat/send", data=data) def send_msg(self, chat_id, msg_type, **kwargs): - """ deprecated, use `send` instead """ + """deprecated, use `send` instead""" return self.send(chat_id, msg_type, **kwargs) def send_text(self, chat_id, content, safe=0): @@ -107,9 +105,9 @@ def send_text(self, chat_id, content, safe=0): :param safe: 表示是否是保密消息,0表示否,1表示是,默认0 :return: """ - return self.send(chat_id, 'text', safe=safe, content=content) + return self.send(chat_id, "text", safe=safe, content=content) - def _build_msg_content(self, msgtype='text', **kwargs): + def _build_msg_content(self, msgtype="text", **kwargs): """ 构造消息内容 @@ -118,25 +116,25 @@ def _build_msg_content(self, msgtype='text', **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = {'msgtype': msgtype} - if msgtype == 'text': - data[msgtype] = {'content': kwargs.get('content')} - elif msgtype == 'image' or msgtype == 'voice' or msgtype == 'file': - data[msgtype] = {'media_id': kwargs.get('media_id')} - elif msgtype == 'video': + data = {"msgtype": msgtype} + if msgtype == "text": + data[msgtype] = {"content": kwargs.get("content")} + elif msgtype == "image" or msgtype == "voice" or msgtype == "file": + data[msgtype] = {"media_id": kwargs.get("media_id")} + elif msgtype == "video": data[msgtype] = { - 'media_id': kwargs.get('media_id'), - 'title': kwargs.get('title'), - 'description': kwargs.get('description') + "media_id": kwargs.get("media_id"), + "title": kwargs.get("title"), + "description": kwargs.get("description"), } - elif msgtype == 'textcard': + elif msgtype == "textcard": data[msgtype] = { - 'title': kwargs.get('title'), - 'description': kwargs.get('description'), - 'url': kwargs.get('url'), - 'btntxt': kwargs.get('btntxt'), + "title": kwargs.get("title"), + "description": kwargs.get("description"), + "url": kwargs.get("url"), + "btntxt": kwargs.get("btntxt"), } - elif msgtype == 'news': + elif msgtype == "news": # { # "articles" : # [ @@ -149,7 +147,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'mpnews': + elif msgtype == "mpnews": # { # "articles":[ # { @@ -163,7 +161,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'markdown': + elif msgtype == "markdown": # { # "content": "您的会议室已经预定,稍后会同步到`邮箱` # >**事项详情** @@ -181,5 +179,5 @@ def _build_msg_content(self, msgtype='text', **kwargs): # } data[msgtype] = kwargs else: - raise TypeError('不能识别的msgtype: %s' % msgtype) + raise TypeError("不能识别的msgtype: %s" % msgtype) return data diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/batch.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/batch.py index 8ed88d5..268ebf3 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/batch.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/batch.py @@ -30,16 +30,16 @@ def sync_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/syncuser', + "batch/syncuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): @@ -56,16 +56,16 @@ def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceuser', + "batch/replaceuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_party(self, url, token, encoding_aes_key, media_id): @@ -81,15 +81,15 @@ def replace_party(self, url, token, encoding_aes_key, media_id): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceparty', + "batch/replaceparty", data={ - 'media_id': media_id, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def get_result(self, job_id): @@ -101,7 +101,7 @@ def get_result(self, job_id): :param job_id: 异步任务id,最大长度为64字符 :return: 返回的 JSON 数据包 """ - return self._get('batch/getresult', params={'jobid': job_id}) + return self._get("batch/getresult", params={"jobid": job_id}) def invite(self, user=None, party=None, tag=None): """ @@ -117,10 +117,18 @@ def invite(self, user=None, party=None, tag=None): :return: 返回的 JSON 数据包 """ data = optionaldict(user=user, party=party, tag=tag) - return self._post('batch/invite', data=data) - - def invite_user(self, url, token, encoding_aes_key, user_ids=None, - party_ids=None, tag_ids=None, invite_tips=None): + return self._post("batch/invite", data=data) + + def invite_user( + self, + url, + token, + encoding_aes_key, + user_ids=None, + party_ids=None, + tag_ids=None, + invite_tips=None, + ): """ 邀请成员关注(deprecated) https://qydev.weixin.qq.com/wiki/index.php?title=异步任务接口 @@ -135,19 +143,19 @@ def invite_user(self, url, token, encoding_aes_key, user_ids=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['callback'] = { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key + data["callback"] = { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, } if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(map(to_text, user_ids)) + user_ids = "|".join(map(to_text, user_ids)) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(map(to_text, party_ids)) + party_ids = "|".join(map(to_text, party_ids)) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(map(to_text, tag_ids)) - data['touser'] = user_ids - data['toparty'] = party_ids - data['totag'] = tag_ids - data['invite_tips'] = invite_tips - return self._post('batch/inviteuser', data=data) + tag_ids = "|".join(map(to_text, tag_ids)) + data["touser"] = user_ids + data["toparty"] = party_ids + data["totag"] = tag_ids + data["invite_tips"] = invite_tips + return self._post("batch/inviteuser", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/chat.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/chat.py index da16e5c..a71f53c 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/chat.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/chat.py @@ -27,13 +27,13 @@ def create(self, chat_id, name, owner, user_list): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/create', + "chat/create", data={ - 'chatid': chat_id, - 'name': name, - 'owner': owner, - 'userlist': user_list, - } + "chatid": chat_id, + "name": name, + "owner": owner, + "userlist": user_list, + }, ) def get(self, chat_id): @@ -46,11 +46,18 @@ def get(self, chat_id): :param chat_id: 会话 ID :return: 会话信息 """ - res = self._get('chat/get', params={'chatid': chat_id}) - return res['chat_info'] - - def update(self, chat_id, op_user, name=None, owner=None, - add_user_list=None, del_user_list=None): + res = self._get("chat/get", params={"chatid": chat_id}) + return res["chat_info"] + + def update( + self, + chat_id, + op_user, + name=None, + owner=None, + add_user_list=None, + del_user_list=None, + ): """ 修改会话 @@ -73,7 +80,7 @@ def update(self, chat_id, op_user, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('chat/update', data=data) + return self._post("chat/update", data=data) def quit(self, chat_id, op_user): """ @@ -87,11 +94,11 @@ def quit(self, chat_id, op_user): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/quit', + "chat/quit", data={ - 'chatid': chat_id, - 'op_user': op_user, - } + "chatid": chat_id, + "op_user": op_user, + }, ) def clear_notify(self, op_user, type, id): @@ -107,14 +114,14 @@ def clear_notify(self, op_user, type, id): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/clearnotify', + "chat/clearnotify", data={ - 'op_user': op_user, - 'chat': { - 'type': type, - 'id': id, - } - } + "op_user": op_user, + "chat": { + "type": type, + "id": id, + }, + }, ) def set_mute(self, user_mute_list): @@ -127,10 +134,7 @@ def set_mute(self, user_mute_list): :param user_mute_list: 成员新消息免打扰参数,数组,最大支持10000个成员 :return: 返回的 JSON 数据包 """ - return self._post( - 'chat/setmute', - data={'user_mute_list': user_mute_list} - ) + return self._post("chat/setmute", data={"user_mute_list": user_mute_list}) def send_text(self, sender, receiver_type, receiver_id, content): """ @@ -146,17 +150,17 @@ def send_text(self, sender, receiver_type, receiver_id, content): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "text", + "text": { + "content": content, }, - 'sender': sender, - 'msgtype': 'text', - 'text': { - 'content': content, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_text(self, sender, receiver, content): """ @@ -167,7 +171,7 @@ def send_single_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'single', receiver, content) + return self.send_text(sender, "single", receiver, content) def send_group_text(self, sender, receiver, content): """ @@ -178,7 +182,7 @@ def send_group_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'group', receiver, content) + return self.send_text(sender, "group", receiver, content) def send_image(self, sender, receiver_type, receiver_id, media_id): """ @@ -194,17 +198,17 @@ def send_image(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "image", + "image": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'image', - 'image': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_image(self, sender, receiver, media_id): """ @@ -215,7 +219,7 @@ def send_single_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'single', receiver, media_id) + return self.send_image(sender, "single", receiver, media_id) def send_group_image(self, sender, receiver, media_id): """ @@ -226,7 +230,7 @@ def send_group_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'group', receiver, media_id) + return self.send_image(sender, "group", receiver, media_id) def send_file(self, sender, receiver_type, receiver_id, media_id): """ @@ -242,17 +246,17 @@ def send_file(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "file", + "file": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'file', - 'file': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_file(self, sender, receiver, media_id): """ @@ -263,7 +267,7 @@ def send_single_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'single', receiver, media_id) + return self.send_file(sender, "single", receiver, media_id) def send_group_file(self, sender, receiver, media_id): """ @@ -274,4 +278,4 @@ def send_group_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'group', receiver, media_id) + return self.send_file(sender, "group", receiver, media_id) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/department.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/department.py index d36893c..603c2ae 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/department.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/department.py @@ -23,13 +23,8 @@ def create(self, name, parent_id=1, order=None, id=None): :param id: 部门id,32位整型,指定时必须大于1。若不填该参数,将自动生成id :return: 返回的 JSON 数据包 """ - data = optionaldict( - name=name, - parentid=parent_id, - order=order, - id=id - ) - return self._post('department/create', data=data) + data = optionaldict(name=name, parentid=parent_id, order=order, id=id) + return self._post("department/create", data=data) def update(self, id, name=None, parent_id=None, order=None): """ @@ -43,13 +38,8 @@ def update(self, id, name=None, parent_id=None, order=None): :param order: 在父部门中的次序值。order值大的排序靠前。有效的值范围是[0, 2^32) :return: 返回的 JSON 数据包 """ - data = optionaldict( - id=id, - name=name, - parentid=parent_id, - order=order - ) - return self._post('department/update', data=data) + data = optionaldict(id=id, name=name, parentid=parent_id, order=order) + return self._post("department/update", data=data) def delete(self, id): """ @@ -60,7 +50,7 @@ def delete(self, id): :param id: 部门id。(注:不能删除根部门;不能删除含有子部门、成员的部门) :return: 返回的 JSON 数据包 """ - return self._get('department/delete', params={'id': id}) + return self._get("department/delete", params={"id": id}) def get(self, id=None): """ @@ -75,10 +65,10 @@ def get(self, id=None): :return: 部门列表 """ if id is None: - res = self._get('department/list') + res = self._get("department/list") else: - res = self._get('department/list', params={'id': id}) - return res['department'] + res = self._get("department/list", params={"id": id}) + return res["department"] def get_users(self, id, status=0, fetch_child=0, simple=True): """ @@ -92,13 +82,13 @@ def get_users(self, id, status=0, fetch_child=0, simple=True): :param simple: True 获取部门成员,False 获取部门成员详情 :return: 部门成员列表 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': id, - 'status': status, - 'fetch_child': 1 if fetch_child else 0 - } + "department_id": id, + "status": status, + "fetch_child": 1 if fetch_child else 0, + }, ) - return res['userlist'] + return res["userlist"] diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py index 59571df..d0b7be6 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py @@ -20,7 +20,7 @@ def get_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('get_jsapi_ticket') + return self._get("get_jsapi_ticket") def get_jsapi_signature(self, noncestr, ticket, timestamp, url): """ @@ -35,12 +35,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -52,7 +52,7 @@ def get_agent_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('ticket/get', params={'type': 'agent_config'}) + return self._get("ticket/get", params={"type": "agent_config"}) def get_jsapi_ticket(self): """ @@ -62,14 +62,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -82,14 +82,14 @@ def get_agent_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_agent_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_agent_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_agent_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_agent_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_agent_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/material.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/material.py index 9de5fef..2c23f37 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/material.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/material.py @@ -19,22 +19,19 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'material/add_mpnews', - data={ - "mpnews": { - "articles": articles_data + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } - } + ) + return self._post( + "material/add_mpnews", data={"mpnews": {"articles": articles_data}} ) def add(self, agent_id, media_type, media_file): @@ -49,15 +46,11 @@ def add(self, agent_id, media_type, media_file): :return: 返回的 JSON 数据包 """ params = { - 'agentid': agent_id, - 'type': media_type, + "agentid": agent_id, + "type": media_type, } return self._post( - url='material/add_material', - params=params, - files={ - 'media': media_file - } + url="material/add_material", params=params, files={"media": media_file} ) def get_url(self, agent_id, media_id): @@ -71,15 +64,15 @@ def get_url(self, agent_id, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/material/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/material/get", + "?access_token=", self.access_token, - '&media_id=', + "&media_id=", media_id, - '&agentid=', + "&agentid=", agent_id, ) - return ''.join(parts) + return "".join(parts) def get(self, agent_id, media_id): """ @@ -104,11 +97,11 @@ def get_articles(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get', + "material/get", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def delete(self, agent_id, media_id): @@ -122,11 +115,11 @@ def delete(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/del', + "material/del", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def update_articles(self, agent_id, media_id, articles): @@ -142,22 +135,20 @@ def update_articles(self, agent_id, media_id, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) return self._post( - 'material/update_news', - data={ - 'agentid': agent_id, - 'media_id': media_id, - 'articles': articles_data - } + "material/update_news", + data={"agentid": agent_id, "media_id": media_id, "articles": articles_data}, ) def get_count(self, agent_id): @@ -170,10 +161,10 @@ def get_count(self, agent_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get_count', + "material/get_count", params={ - 'agent_id': agent_id, - } + "agent_id": agent_id, + }, ) def batchget(self, agent_id, media_type, offset=0, count=20): @@ -190,11 +181,11 @@ def batchget(self, agent_id, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget', + "material/batchget", data={ - 'agent_id': agent_id, - 'type': media_type, - 'offset': offset, - 'count': count - } + "agent_id": agent_id, + "type": media_type, + "offset": offset, + "count": count, + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/media.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/media.py index 15762f3..4705bbf 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/media.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/media.py @@ -23,7 +23,9 @@ def upload(self, media_type, media_file): :param media_file: 要上传的文件,一个 File-object :return: 返回的 JSON 数据包 """ - return self._post('media/upload', params={'type': media_type}, files={'media': media_file}) + return self._post( + "media/upload", params={"type": media_type}, files={"media": media_file} + ) def upload_img(self, image_file): """ @@ -38,7 +40,7 @@ def upload_img(self, image_file): :return: 返回的 JSON 数据包 """ - return self._post('media/uploadimg', files={'media': image_file}) + return self._post("media/uploadimg", files={"media": image_file}) def get_url(self, media_id): """ @@ -50,13 +52,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def get_jssdk_url(self, media_id): """ @@ -68,13 +70,13 @@ def get_jssdk_url(self, media_id): :return: 高清语音素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def download(self, media_id): """ diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/menu.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/menu.py index 612fb25..41aabd2 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/menu.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/menu.py @@ -19,13 +19,7 @@ def create(self, agent_id, menu_data): :param agent_id: 应用id """ - return self._post( - 'menu/create', - params={ - 'agentid': agent_id - }, - data=menu_data - ) + return self._post("menu/create", params={"agentid": agent_id}, data=menu_data) def get(self, agent_id): """ @@ -35,12 +29,7 @@ def get(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/get', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/get", params={"agentid": agent_id}) def delete(self, agent_id): """ @@ -50,12 +39,7 @@ def delete(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/delete', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/delete", params={"agentid": agent_id}) def update(self, agent_id, menu_data): self.delete(agent_id) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/message.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/message.py index 21b2988..9952ebc 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/message.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/message.py @@ -25,8 +25,7 @@ class WeChatMessage(BaseWeChatAPI): * 小程序通知消息 """ - def send(self, agent_id, user_ids, party_ids='', - tag_ids='', msg=None): + def send(self, agent_id, user_ids, party_ids="", tag_ids="", msg=None): """ 通用的消息发送接口。msg 内需要指定 msgtype 和对应类型消息必须的字段。 如果部分接收人无权限或不存在,发送仍然执行,但会返回无效的部分(即invaliduser或invalidparty或invalidtag),常见的原因是接收人不在应用的可见范围内。 @@ -42,38 +41,42 @@ def send(self, agent_id, user_ids, party_ids='', """ msg = msg or {} if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(user_ids) + user_ids = "|".join(user_ids) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(party_ids) + party_ids = "|".join(party_ids) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(tag_ids) + tag_ids = "|".join(tag_ids) data = { - 'touser': user_ids, - 'toparty': party_ids, - 'totag': tag_ids, - 'agentid': agent_id + "touser": user_ids, + "toparty": party_ids, + "totag": tag_ids, + "agentid": agent_id, } data.update(msg) - return self._post('message/send', data=data) + return self._post("message/send", data=data) - def send_text(self, agent_id, user_ids, content, - party_ids='', tag_ids='', safe=0): + def send_text(self, agent_id, user_ids, content, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'text', - 'text': {'content': content}, - 'safe': safe - } + msg={"msgtype": "text", "text": {"content": content}, "safe": safe}, ) - def send_text_card(self, agent_id, user_ids, title, description, url, btntxt='详情', - party_ids='', tag_ids=''): - """ 文本卡片消息 + def send_text_card( + self, + agent_id, + user_ids, + title, + description, + url, + btntxt="详情", + party_ids="", + tag_ids="", + ): + """文本卡片消息 https://work.weixin.qq.com/api/doc#90000/90135/90236/文本卡片消息 @@ -113,129 +116,114 @@ def send_text_card(self, agent_id, user_ids, title, description, url, btntxt=' party_ids, tag_ids, msg={ - 'msgtype': 'textcard', - 'textcard': { - 'title': title, - 'description': description, - 'url': url, - 'btntxt': btntxt, + "msgtype": "textcard", + "textcard": { + "title": title, + "description": description, + "url": url, + "btntxt": btntxt, }, - } + }, ) - def send_image(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_image( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'image', - 'image': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "image", "image": {"media_id": media_id}, "safe": safe}, ) - def send_voice(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_voice( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "voice", "voice": {"media_id": media_id}, "safe": safe}, ) - def send_video(self, agent_id, user_ids, media_id, title=None, - description=None, party_ids='', tag_ids='', safe=0): + def send_video( + self, + agent_id, + user_ids, + media_id, + title=None, + description=None, + party_ids="", + tag_ids="", + safe=0, + ): video_data = optionaldict() - video_data['media_id'] = media_id - video_data['title'] = title - video_data['description'] = description + video_data["media_id"] = media_id + video_data["title"] = title + video_data["description"] = description return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'video', - 'video': dict(video_data), - 'safe': safe - } + msg={"msgtype": "video", "video": dict(video_data), "safe": safe}, ) - def send_file(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_file(self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'file', - 'file': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "file", "file": {"media_id": media_id}, "safe": safe}, ) - def send_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids=''): + def send_articles(self, agent_id, user_ids, articles, party_ids="", tag_ids=""): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article['image'] - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article["image"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } - } + msg={"msgtype": "news", "news": {"articles": articles_data}}, ) - def send_mp_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids='', safe=0): + def send_mp_articles( + self, agent_id, user_ids, articles, party_ids="", tag_ids="", safe=0 + ): articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'author': article['author'], - 'title': article['title'], - 'content': article['content'], - 'content_source_url': article['content_source_url'], - 'digest': article['digest'], - 'show_cover_pic': article['show_cover_pic'] - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "author": article["author"], + "title": article["title"], + "content": article["content"], + "content_source_url": article["content_source_url"], + "digest": article["digest"], + "show_cover_pic": article["show_cover_pic"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, msg={ - 'msgtype': 'mpnews', - 'mpnews': { - 'articles': articles_data - }, - 'safe': safe - } + "msgtype": "mpnews", + "mpnews": {"articles": articles_data}, + "safe": safe, + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/misc.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/misc.py index 54c356c..34c9e2f 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/misc.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/misc.py @@ -14,5 +14,5 @@ def get_wechat_ips(self): :return: 企业微信回调的IP段 """ - res = self._get('getcallbackip') - return res['ip_list'] + res = self._get("getcallbackip") + return res["ip_list"] diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/oauth.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/oauth.py index cffe7ca..9bb913a 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/oauth.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/oauth.py @@ -7,7 +7,7 @@ class WeChatOAuth(BaseWeChatAPI): - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize' + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" def authorize_url(self, redirect_uri, state=None): """ @@ -19,19 +19,19 @@ def authorize_url(self, redirect_uri, state=None): :param state: 重定向后会带上 state 参数 :return: 返回的 JSON 数据包 """ - redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b'') + redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - '?appid=', + "?appid=", self._client.corp_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=snsapi_base', + "&response_type=code&scope=snsapi_base", ] if state: - url_list.extend(['&state=', state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def get_user_info(self, code): """ @@ -44,8 +44,8 @@ def get_user_info(self, code): """ return self._get( - 'order/getuserinfo', + "order/getuserinfo", params={ - 'code': code, - } + "code": code, + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/service.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/service.py index 75ba8ee..2b4d083 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/service.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/service.py @@ -23,11 +23,11 @@ def get_provider_token(self, provider_secret): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_provider_token', + "service/get_provider_token", data={ - 'corpid': self._client.corp_id, - 'provider_secret': provider_secret, - } + "corpid": self._client.corp_id, + "provider_secret": provider_secret, + }, ) def get_suite_token(self, suite_id, suite_secret, suite_ticket): @@ -42,12 +42,12 @@ def get_suite_token(self, suite_id, suite_secret, suite_ticket): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_suite_token', + "service/get_suite_token", data={ - 'suite_id': suite_id, - 'suite_secret': suite_secret, - 'suite_ticket': suite_ticket - } + "suite_id": suite_id, + "suite_secret": suite_secret, + "suite_ticket": suite_ticket, + }, ) def get_login_info(self, auth_code, provider_access_token=None): @@ -62,16 +62,18 @@ def get_login_info(self, auth_code, provider_access_token=None): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_info', + "service/get_login_info", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'auth_code': auth_code, - } + "auth_code": auth_code, + }, ) - def get_login_url(self, login_ticket, target, agentid=None, provider_access_token=None): + def get_login_url( + self, login_ticket, target, agentid=None, provider_access_token=None + ): """ 获取登录企业号官网的url @@ -85,13 +87,13 @@ def get_login_url(self, login_ticket, target, agentid=None, provider_access_toke :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_url', + "service/get_login_url", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'login_ticket': login_ticket, - 'target': target, - 'agentid': agentid, - } + "login_ticket": login_ticket, + "target": target, + "agentid": agentid, + }, ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py index 0155576..047ebbc 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py @@ -15,10 +15,5 @@ def get_shake_info(self, ticket): :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 :return: 设备及用户信息 """ - res = self._post( - 'shakearound/getshakeinfo', - data={ - 'ticket': ticket - } - ) - return res['data'] + res = self._post("shakearound/getshakeinfo", data={"ticket": ticket}) + return res["data"] diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/tag.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/tag.py index dce5dd5..8db6f66 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/tag.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/tag.py @@ -12,56 +12,27 @@ class WeChatTag(BaseWeChatAPI): """ def create(self, name): - return self._post( - 'tag/create', - data={ - 'tagname': name - } - ) + return self._post("tag/create", data={"tagname": name}) def update(self, tag_id, name): - return self._post( - 'tag/update', - data={ - 'tagid': tag_id, - 'tagname': name - } - ) + return self._post("tag/update", data={"tagid": tag_id, "tagname": name}) def delete(self, tag_id): - return self._get( - 'tag/delete', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/delete", params={"tagid": tag_id}) def get_users(self, tag_id): - return self._get( - 'tag/get', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/get", params={"tagid": tag_id}) def add_users(self, tag_id, user_ids): return self._post( - 'tag/addtagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/addtagusers", data={"tagid": tag_id, "userlist": user_ids} ) def delete_users(self, tag_id, user_ids): return self._post( - 'tag/deltagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/deltagusers", data={"tagid": tag_id, "userlist": user_ids} ) def list(self): - res = self._get('tag/list') - return res['taglist'] + res = self._get("tag/list") + return res["taglist"] diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/user.py b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/user.py index bd5e367..e94404c 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/client/api/user.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/client/api/user.py @@ -15,30 +15,37 @@ class WeChatUser(BaseWeChatAPI): 邀请成员接口位于 `WeChatBatch.invite` """ - def create(self, user_id, name, department=None, position=None, - mobile=None, gender=0, tel=None, email=None, - weixin_id=None, extattr=None): + def create( + self, + user_id, + name, + department=None, + position=None, + mobile=None, + gender=0, + tel=None, + email=None, + weixin_id=None, + extattr=None, + ): """ 创建成员 https://work.weixin.qq.com/api/doc#90000/90135/90195 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - - return self._post( - 'order/create', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + + return self._post("order/create", data=user_data) def get(self, user_id): """ @@ -46,38 +53,41 @@ def get(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90196 """ - return self._get( - 'order/get', - params={ - 'userid': user_id - } - ) - - def update(self, user_id, name=None, department=None, position=None, - mobile=None, gender=None, tel=None, email=None, - weixin_id=None, enable=None, extattr=None): + return self._get("order/get", params={"userid": user_id}) + + def update( + self, + user_id, + name=None, + department=None, + position=None, + mobile=None, + gender=None, + tel=None, + email=None, + weixin_id=None, + enable=None, + extattr=None, + ): """ 更新成员 https://work.weixin.qq.com/api/doc#90000/90135/90197 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - user_data['enable'] = enable - - return self._post( - 'order/update', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + user_data["enable"] = enable + + return self._post("order/update", data=user_data) def delete(self, user_id): """ @@ -85,12 +95,7 @@ def delete(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90198 """ - return self._get( - 'order/delete', - params={ - 'userid': user_id - } - ) + return self._get("order/delete", params={"userid": user_id}) def batch_delete(self, user_ids): """ @@ -98,12 +103,7 @@ def batch_delete(self, user_ids): https://work.weixin.qq.com/api/doc#90000/90135/90199 """ - return self._post( - 'order/batchdelete', - data={ - 'useridlist': user_ids - } - ) + return self._post("order/batchdelete", data={"useridlist": user_ids}) def list(self, department_id, fetch_child=False, status=0, simple=False): """ @@ -114,16 +114,16 @@ def list(self, department_id, fetch_child=False, status=0, simple=False): 此接口和 `WeChatDepartment.get_users` 是同一个接口,区别为 simple 的默认值不同。 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': department_id, - 'fetch_child': 1 if fetch_child else 0, - 'status': status - } + "department_id": department_id, + "fetch_child": 1 if fetch_child else 0, + "status": status, + }, ) - return res['userlist'] + return res["userlist"] def convert_to_openid(self, user_id, agent_id=None): """ @@ -135,11 +135,8 @@ def convert_to_openid(self, user_id, agent_id=None): :param agent_id: 可选,需要发送红包的应用ID,若只是使用微信支付和企业转账,则无需该参数 :return: 返回的 JSON 数据包 """ - data = optionaldict( - userid=user_id, - agentid=agent_id - ) - return self._post('order/convert_to_openid', data=data) + data = optionaldict(userid=user_id, agentid=agent_id) + return self._post("order/convert_to_openid", data=data) def convert_to_user_id(self, openid): """ @@ -150,8 +147,8 @@ def convert_to_user_id(self, openid): :param openid: 在使用微信支付、微信红包和企业转账之后,返回结果的openid :return: 该 openid 在企业微信中对应的成员 user_id """ - res = self._post('order/convert_to_userid', data={'openid': openid}) - return res['userid'] + res = self._post("order/convert_to_userid", data={"openid": openid}) + return res["userid"] def verify(self, user_id): """ @@ -161,18 +158,9 @@ def verify(self, user_id): :param user_id: 成员UserID。对应管理端的帐号 """ - return self._get( - 'order/authsucc', - params={ - 'userid': user_id - } - ) + return self._get("order/authsucc", params={"userid": user_id}) def get_info(self, agent_id, code): return self._get( - 'order/getuserinfo', - params={ - 'agentid': agent_id, - 'code': code - } + "order/getuserinfo", params={"agentid": agent_id, "code": code} ) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/crypto.py b/chapter12/booking_system/exts/wechatpy/enterprise/crypto.py index 9b14bd6..90e6f4a 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/crypto.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/crypto.py @@ -20,27 +20,10 @@ def __init__(self, token, encoding_aes_key, corp_id): self.corp_id = corp_id def check_signature(self, signature, timestamp, nonce, echo_str): - return self._check_signature( - signature, - timestamp, - nonce, - echo_str, - PrpCrypto - ) + return self._check_signature(signature, timestamp, nonce, echo_str, PrpCrypto) def encrypt_message(self, msg, nonce, timestamp=None): - return self._encrypt_message( - msg, - nonce, - timestamp, - PrpCrypto - ) + return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/exceptions.py b/chapter12/booking_system/exts/wechatpy/enterprise/exceptions.py index a4ac5ee..13cd7f5 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/exceptions.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/exceptions.py @@ -6,5 +6,5 @@ class InvalidCorpIdException(WeChatException): - def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): + def __init__(self, errcode=-40005, errmsg="Invalid corp_id"): super(InvalidCorpIdException, self).__init__(errcode, errmsg) diff --git a/chapter12/booking_system/exts/wechatpy/enterprise/parser.py b/chapter12/booking_system/exts/wechatpy/enterprise/parser.py index 31fa199..7d1040d 100644 --- a/chapter12/booking_system/exts/wechatpy/enterprise/parser.py +++ b/chapter12/booking_system/exts/wechatpy/enterprise/parser.py @@ -12,10 +12,10 @@ def parse_message(xml): if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() - if message_type == 'event': - event_type = message['Event'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() + if message_type == "event": + event_type = message["Event"].lower() message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter12/booking_system/exts/wechatpy/events.py b/chapter12/booking_system/exts/wechatpy/events.py index eeb03db..a1ba320 100644 --- a/chapter12/booking_system/exts/wechatpy/events.py +++ b/chapter12/booking_system/exts/wechatpy/events.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.events - ~~~~~~~~~~~~~~~~ +wechatpy.events +~~~~~~~~~~~~~~~~ - This module contains all the events WeChat callback uses. +This module contains all the events WeChat callback uses. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -16,7 +16,7 @@ IntegerField, BaseField, Base64DecodeField, - DateTimeField + DateTimeField, ) from exts.wechatpy.messages import BaseMessage @@ -30,19 +30,22 @@ def register_event(event_type): :param event_type: Event type """ + def register(cls): EVENT_TYPES[event_type] = cls return cls + return register class BaseEvent(BaseMessage): """Base class for all events""" - type = 'event' - event = '' + + type = "event" + event = "" -@register_event('subscribe') +@register_event("subscribe") class SubscribeEvent(BaseEvent): """ 用户关注事件 @@ -50,11 +53,12 @@ class SubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe' - key = StringField('EventKey', '') + event = "subscribe" + key = StringField("EventKey", "") -@register_event('unsubscribe') + +@register_event("unsubscribe") class UnsubscribeEvent(BaseEvent): """ 用户取消关注事件 @@ -62,10 +66,11 @@ class UnsubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'unsubscribe' + + event = "unsubscribe" -@register_event('subscribe_scan') +@register_event("subscribe_scan") class SubscribeScanEvent(BaseEvent): """ 用户扫描二维码关注事件 @@ -73,12 +78,13 @@ class SubscribeScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe_scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + event = "subscribe_scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('scan') + +@register_event("scan") class ScanEvent(BaseEvent): """ 用户扫描二维码事件 @@ -86,12 +92,13 @@ class ScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + + event = "scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('location') +@register_event("location") class LocationEvent(BaseEvent): """ 上报地理位置事件 @@ -99,13 +106,14 @@ class LocationEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'location' - latitude = FloatField('Latitude', 0.0) - longitude = FloatField('Longitude', 0.0) - precision = FloatField('Precision', 0.0) + + event = "location" + latitude = FloatField("Latitude", 0.0) + longitude = FloatField("Longitude", 0.0) + precision = FloatField("Precision", 0.0) -@register_event('click') +@register_event("click") class ClickEvent(BaseEvent): """ 点击菜单拉取消息事件 @@ -113,11 +121,12 @@ class ClickEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'click' - key = StringField('EventKey') + event = "click" + key = StringField("EventKey") -@register_event('view') + +@register_event("view") class ViewEvent(BaseEvent): """ 点击菜单跳转链接事件 @@ -125,11 +134,12 @@ class ViewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'view' - url = StringField('EventKey') + + event = "view" + url = StringField("EventKey") -@register_event('masssendjobfinish') +@register_event("masssendjobfinish") class MassSendJobFinishEvent(BaseEvent): """ 群发消息任务完成事件 @@ -137,16 +147,17 @@ class MassSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1481187827_i0l21 """ - id = IntegerField('MsgID', 0) - event = 'masssendjobfinish' - status = StringField('Status') - total_count = IntegerField('TotalCount', 0) - filter_count = IntegerField('FilterCount', 0) - sent_count = IntegerField('SentCount', 0) - error_count = IntegerField('ErrorCount', 0) + id = IntegerField("MsgID", 0) + event = "masssendjobfinish" + status = StringField("Status") + total_count = IntegerField("TotalCount", 0) + filter_count = IntegerField("FilterCount", 0) + sent_count = IntegerField("SentCount", 0) + error_count = IntegerField("ErrorCount", 0) -@register_event('templatesendjobfinish') + +@register_event("templatesendjobfinish") class TemplateSendJobFinishEvent(BaseEvent): """ 模板消息任务完成事件 @@ -154,25 +165,26 @@ class TemplateSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1433751277 """ - id = IntegerField('MsgID') - event = 'templatesendjobfinish' - status = StringField('Status') + + id = IntegerField("MsgID") + event = "templatesendjobfinish" + status = StringField("Status") class BaseScanCodeEvent(BaseEvent): - key = StringField('EventKey') - scan_code_info = BaseField('ScanCodeInfo', {}) + key = StringField("EventKey") + scan_code_info = BaseField("ScanCodeInfo", {}) @property def scan_type(self): - return self.scan_code_info['ScanType'] + return self.scan_code_info["ScanType"] @property def scan_result(self): - return self.scan_code_info['ScanResult'] + return self.scan_code_info["ScanResult"] -@register_event('scancode_push') +@register_event("scancode_push") class ScanCodePushEvent(BaseScanCodeEvent): """ 扫码推事件 @@ -180,10 +192,11 @@ class ScanCodePushEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_push' + + event = "scancode_push" -@register_event('scancode_waitmsg') +@register_event("scancode_waitmsg") class ScanCodeWaitMsgEvent(BaseScanCodeEvent): """ 扫码推事件且弹出“消息接收中”提示框的事件 @@ -191,28 +204,29 @@ class ScanCodeWaitMsgEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_waitmsg' + + event = "scancode_waitmsg" class BasePictureEvent(BaseEvent): - key = StringField('EventKey') - pictures_info = BaseField('SendPicsInfo', {}) + key = StringField("EventKey") + pictures_info = BaseField("SendPicsInfo", {}) @property def count(self): - return int(self.pictures_info['Count']) + return int(self.pictures_info["Count"]) @property def pictures(self): - if self.pictures_info['PicList']: - items = self.pictures_info['PicList']['item'] + if self.pictures_info["PicList"]: + items = self.pictures_info["PicList"]["item"] if self.count > 1: return items return [items] return [] -@register_event('pic_sysphoto') +@register_event("pic_sysphoto") class PicSysPhotoEvent(BasePictureEvent): """ 弹出系统拍照发图的事件 @@ -220,10 +234,11 @@ class PicSysPhotoEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_sysphoto' + + event = "pic_sysphoto" -@register_event('pic_photo_or_album') +@register_event("pic_photo_or_album") class PicPhotoOrAlbumEvent(BasePictureEvent): """ 弹出拍照或者相册发图的事件 @@ -231,10 +246,11 @@ class PicPhotoOrAlbumEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_photo_or_album' + event = "pic_photo_or_album" -@register_event('pic_weixin') + +@register_event("pic_weixin") class PicWeChatEvent(BasePictureEvent): """ 弹出微信相册发图器的事件 @@ -242,10 +258,11 @@ class PicWeChatEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_weixin' + + event = "pic_weixin" -@register_event('location_select') +@register_event("location_select") class LocationSelectEvent(BaseEvent): """ 弹出地理位置选择器的事件 @@ -253,17 +270,18 @@ class LocationSelectEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'location_select' - key = StringField('EventKey') - location_info = BaseField('SendLocationInfo', {}) + + event = "location_select" + key = StringField("EventKey") + location_info = BaseField("SendLocationInfo", {}) @property def location_x(self): - return self.location_info['Location_X'] + return self.location_info["Location_X"] @property def location_y(self): - return self.location_info['Location_Y'] + return self.location_info["Location_Y"] @property def location(self): @@ -271,30 +289,30 @@ def location(self): @property def scale(self): - return self.location_info['Scale'] + return self.location_info["Scale"] @property def label(self): - return self.location_info['Label'] + return self.location_info["Label"] @property def poiname(self): - return self.location_info['Poiname'] + return self.location_info["Poiname"] -@register_event('card_pass_check') +@register_event("card_pass_check") class CardPassCheckEvent(BaseEvent): - event = 'card_pass_check' - card_id = StringField('CardId') + event = "card_pass_check" + card_id = StringField("CardId") -@register_event('card_not_pass_check') +@register_event("card_not_pass_check") class CardNotPassCheckEvent(BaseEvent): - event = 'card_not_pass_check' - card_id = StringField('CardId') + event = "card_not_pass_check" + card_id = StringField("CardId") -@register_event('user_get_card') +@register_event("user_get_card") class UserGetCardEvent(BaseEvent): """ 领取事件推送 @@ -302,16 +320,17 @@ class UserGetCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_get_card' - card_id = StringField('CardId') - is_given_by_friend = IntegerField('IsGiveByFriend') - friend = StringField('FriendUserName') - code = StringField('UserCardCode') - old_code = StringField('OldUserCardCode') - outer_id = StringField('OuterId') + + event = "user_get_card" + card_id = StringField("CardId") + is_given_by_friend = IntegerField("IsGiveByFriend") + friend = StringField("FriendUserName") + code = StringField("UserCardCode") + old_code = StringField("OldUserCardCode") + outer_id = StringField("OuterId") -@register_event('user_del_card') +@register_event("user_del_card") class UserDeleteCardEvent(BaseEvent): """ 卡券删除事件推送 @@ -319,12 +338,13 @@ class UserDeleteCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_del_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') + event = "user_del_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") -@register_event('user_consume_card') + +@register_event("user_consume_card") class UserConsumeCardEvent(BaseEvent): """ 卡券核销事件推送 @@ -332,95 +352,96 @@ class UserConsumeCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_consume_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') - consume_source = StringField('ConsumeSource') - location_id = StringField('LocationId') - staff = StringField('StaffOpenId') + + event = "user_consume_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") + consume_source = StringField("ConsumeSource") + location_id = StringField("LocationId") + staff = StringField("StaffOpenId") -@register_event('merchant_order') +@register_event("merchant_order") class MerchantOrderEvent(BaseEvent): - event = 'merchant_order' - order_id = StringField('OrderId') - order_status = IntegerField('OrderStatus') - product_id = StringField('ProductId') - sku_info = StringField('SkuInfo') + event = "merchant_order" + order_id = StringField("OrderId") + order_status = IntegerField("OrderStatus") + product_id = StringField("ProductId") + sku_info = StringField("SkuInfo") -@register_event('kf_create_session') +@register_event("kf_create_session") class KfCreateSessionEvent(BaseEvent): - event = 'kf_create_session' - account = StringField('KfAccount') + event = "kf_create_session" + account = StringField("KfAccount") -@register_event('kf_close_session') +@register_event("kf_close_session") class KfCloseSessionEvent(BaseEvent): - event = 'kf_close_session' - account = StringField('KfAccount') + event = "kf_close_session" + account = StringField("KfAccount") -@register_event('kf_switch_session') +@register_event("kf_switch_session") class KfSwitchSessionEvent(BaseEvent): - event = 'kf_switch_session' - from_account = StringField('FromKfAccount') - to_account = StringField('ToKfAccount') + event = "kf_switch_session" + from_account = StringField("FromKfAccount") + to_account = StringField("ToKfAccount") -@register_event('device_text') +@register_event("device_text") class DeviceTextEvent(BaseEvent): - event = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_bind') +@register_event("device_bind") class DeviceBindEvent(BaseEvent): - event = 'device_bind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_bind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_unbind') +@register_event("device_unbind") class DeviceUnbindEvent(BaseEvent): - event = 'device_unbind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_unbind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_subscribe_status') +@register_event("device_subscribe_status") class DeviceSubscribeStatusEvent(BaseEvent): - event = 'device_subscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_subscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('device_unsubscribe_status') +@register_event("device_unsubscribe_status") class DeviceUnsubscribeStatusEvent(BaseEvent): - event = 'device_unsubscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_unsubscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('shakearoundusershake') +@register_event("shakearoundusershake") class ShakearoundUserShakeEvent(BaseEvent): - event = 'shakearound_user_shake' - _chosen_beacon = BaseField('ChosenBeacon', {}) - _around_beacons = BaseField('AroundBeacons', {}) + event = "shakearound_user_shake" + _chosen_beacon = BaseField("ChosenBeacon", {}) + _around_beacons = BaseField("AroundBeacons", {}) @property def chosen_beacon(self): @@ -428,10 +449,10 @@ def chosen_beacon(self): if not beacon: return {} return { - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), } @property @@ -441,39 +462,41 @@ def around_beacons(self): return [] ret = [] - for beacon in beacons['AroundBeacon']: - ret.append({ - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), - }) + for beacon in beacons["AroundBeacon"]: + ret.append( + { + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), + } + ) return ret -@register_event('poi_check_notify') +@register_event("poi_check_notify") class PoiCheckNotifyEvent(BaseEvent): - event = 'poi_check_notify' - poi_id = StringField('PoiId') - uniq_id = StringField('UniqId') - result = StringField('Result') - message = StringField('Msg') + event = "poi_check_notify" + poi_id = StringField("PoiId") + uniq_id = StringField("UniqId") + result = StringField("Result") + message = StringField("Msg") -@register_event('wificonnected') +@register_event("wificonnected") class WiFiConnectedEvent(BaseEvent): - event = 'wificconnected' - connect_time = IntegerField('ConnectTime') - expire_time = IntegerField('ExpireTime') - vendor_id = StringField('VendorId') - shop_id = StringField('PlaceId') - bssid = StringField('DeviceNo') + event = "wificconnected" + connect_time = IntegerField("ConnectTime") + expire_time = IntegerField("ExpireTime") + vendor_id = StringField("VendorId") + shop_id = StringField("PlaceId") + bssid = StringField("DeviceNo") # ============================================================================ # 微信认证事件推送 # ============================================================================ -@register_event('qualification_verify_success') +@register_event("qualification_verify_success") class QualificationVerifySuccessEvent(BaseEvent): """ 资质认证成功事件 @@ -481,11 +504,12 @@ class QualificationVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "qualification_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('qualification_verify_fail') +@register_event("qualification_verify_fail") class QualificationVerifyFailEvent(BaseEvent): """ 资质认证失败事件 @@ -493,12 +517,13 @@ class QualificationVerifyFailEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "qualification_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('naming_verify_success') + +@register_event("naming_verify_success") class NamingVerifySuccessEvent(BaseEvent): """ 名称认证成功事件 @@ -506,11 +531,12 @@ class NamingVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "naming_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('naming_verify_fail') +@register_event("naming_verify_fail") class NamingVerifyFailEvent(BaseEvent): """ 名称认证失败事件 @@ -518,12 +544,13 @@ class NamingVerifyFailEvent(BaseEvent): 客户端不打勾,但仍有接口权限。详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "naming_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('annual_renew') + +@register_event("annual_renew") class AnnualRenewEvent(BaseEvent): """ 年审通知事件 @@ -531,11 +558,12 @@ class AnnualRenewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'annual_renew' - expired_time = DateTimeField('ExpiredTime') + + event = "annual_renew" + expired_time = DateTimeField("ExpiredTime") -@register_event('verify_expired') +@register_event("verify_expired") class VerifyExpiredEvent(BaseEvent): """ 认证过期失效通知 @@ -543,11 +571,12 @@ class VerifyExpiredEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'verify_expired' - expired_time = DateTimeField('ExpiredTime') + event = "verify_expired" + expired_time = DateTimeField("ExpiredTime") -@register_event('user_scan_product') + +@register_event("user_scan_product") class UserScanProductEvent(BaseEvent): """ 打开商品主页事件 @@ -555,17 +584,18 @@ class UserScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - country = StringField('Country') - province = StringField('Province') - city = StringField('City') - sex = IntegerField('Sex') - scene = IntegerField('Scene') + + event = "user_scan_product" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + country = StringField("Country") + province = StringField("Province") + city = StringField("City") + sex = IntegerField("Sex") + scene = IntegerField("Scene") -@register_event('user_scan_product_enter_session') +@register_event("user_scan_product_enter_session") class UserScanProductEnterSessionEvent(BaseEvent): """ 进入公众号事件 @@ -573,12 +603,13 @@ class UserScanProductEnterSessionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_enter_session' - standard = StringField('KeyStandard') - key = StringField('KeyStr') + event = "user_scan_product_enter_session" + standard = StringField("KeyStandard") + key = StringField("KeyStr") -@register_event('user_scan_product_async') + +@register_event("user_scan_product_async") class UserScanProductAsyncEvent(BaseEvent): """ 地理位置信息异步推送事件 @@ -586,13 +617,14 @@ class UserScanProductAsyncEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_async' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - region_code = StringField('RegionCode') + + event = "user_scan_product_async" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + region_code = StringField("RegionCode") -@register_event('user_scan_product_verify_action') +@register_event("user_scan_product_verify_action") class UserScanProductVerifyActionEvent(BaseEvent): """ 商品审核结果事件 @@ -600,14 +632,15 @@ class UserScanProductVerifyActionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_verify_action' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - result = StringField('Result') - reason = StringField('ReasonMsg') + + event = "user_scan_product_verify_action" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + result = StringField("Result") + reason = StringField("ReasonMsg") -@register_event('subscribe_scan_product') +@register_event("subscribe_scan_product") class SubscribeScanProductEvent(BaseEvent): """ 用户在商品主页中关注公众号事件 @@ -615,23 +648,24 @@ class SubscribeScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'subscribe_scan_product' - event_key = StringField('EventKey') + + event = "subscribe_scan_product" + event_key = StringField("EventKey") @property def scene(self): - return self.event_key.split('|', 1)[0] + return self.event_key.split("|", 1)[0] @property def standard(self): - return self.event_key.split('|')[1] + return self.event_key.split("|")[1] @property def key(self): - return self.event_key.split('|')[2] + return self.event_key.split("|")[2] -@register_event('user_authorize_invoice') +@register_event("user_authorize_invoice") class UserAuthorizeInvoiceEvent(BaseEvent): """ 用户授权发票事件 @@ -640,14 +674,15 @@ class UserAuthorizeInvoiceEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'user_authorize_invoice' - success_order_id = StringField('SuccOrderId') # 授权成功的订单号 - fail_order_id = StringField('FailOrderId') # 授权失败的订单号 - app_id = StringField('AppId') # 用于接收事件推送的公众号的AppId - auth_source = StringField('Source') # 授权来源,web表示来自微信内H5,app标识来自app + + event = "user_authorize_invoice" + success_order_id = StringField("SuccOrderId") # 授权成功的订单号 + fail_order_id = StringField("FailOrderId") # 授权失败的订单号 + app_id = StringField("AppId") # 用于接收事件推送的公众号的AppId + auth_source = StringField("Source") # 授权来源,web表示来自微信内H5,app标识来自app -@register_event('update_invoice_status') +@register_event("update_invoice_status") class UpdateInvoiceStatusEvent(BaseEvent): """ 发票状态更新事件 @@ -655,13 +690,14 @@ class UpdateInvoiceStatusEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'update_invoice_status' - status = StringField('Status') # 发票报销状态 - card_id = StringField('CardId') # 发票 Card ID - code = StringField('Code') # 发票 Code + event = "update_invoice_status" + status = StringField("Status") # 发票报销状态 + card_id = StringField("CardId") # 发票 Card ID + code = StringField("Code") # 发票 Code -@register_event('submit_invoice_title') + +@register_event("submit_invoice_title") class SubmitInvoiceTitleEvent(BaseEvent): """ 用户提交发票抬头事件 @@ -669,33 +705,38 @@ class SubmitInvoiceTitleEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0 """ - event = 'submit_invoice_title' - title = StringField('title') # 抬头 - phone = StringField('phone') # 联系方式 - tax_no = StringField('tax_no') # 税号 - addr = StringField('addr') # 地址 - bank_type = StringField('bank_type') # 银行类型 - bank_no = StringField('bank_no') # 银行号码 - attach = StringField('attach') # 附加字段 - title_type = StringField('title_type') # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType + + event = "submit_invoice_title" + title = StringField("title") # 抬头 + phone = StringField("phone") # 联系方式 + tax_no = StringField("tax_no") # 税号 + addr = StringField("addr") # 地址 + bank_type = StringField("bank_type") # 银行类型 + bank_no = StringField("bank_no") # 银行号码 + attach = StringField("attach") # 附加字段 + title_type = StringField( + "title_type" + ) # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType -@register_event('user_enter_tempsession') +@register_event("user_enter_tempsession") class UserEnterTempSessionEvent(BaseEvent): """ 小程序用户进入客服消息 详情请参阅 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/receive.html """ - event = 'user_enter_tempsession' - session_from = StringField('SessionFrom') + event = "user_enter_tempsession" + session_from = StringField("SessionFrom") -@register_event('view_miniprogram') + +@register_event("view_miniprogram") class ViewMiniProgramEvent(BaseEvent): """ 从菜单进入小程序事件 """ - event = 'view_miniprogram' - page_path = StringField('EventKey') # 小程序路径 - menu_id = StringField('MenuId') # 菜单ID + + event = "view_miniprogram" + page_path = StringField("EventKey") # 小程序路径 + menu_id = StringField("MenuId") # 菜单ID diff --git a/chapter12/booking_system/exts/wechatpy/exceptions.py b/chapter12/booking_system/exts/wechatpy/exceptions.py index 683da28..f347485 100644 --- a/chapter12/booking_system/exts/wechatpy/exceptions.py +++ b/chapter12/booking_system/exts/wechatpy/exceptions.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.exceptions - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.exceptions +~~~~~~~~~~~~~~~~~~~~ - Basic exceptions definition. +Basic exceptions definition. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -27,9 +27,8 @@ def __init__(self, errcode, errmsg): self.errmsg = errmsg def __str__(self): - _repr = 'Error code: {code}, message: {msg}'.format( - code=self.errcode, - msg=self.errmsg + _repr = "Error code: {code}, message: {msg}".format( + code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -37,10 +36,8 @@ def __str__(self): return to_text(_repr) def __repr__(self): - _repr = '{klass}({code}, {msg})'.format( - klass=self.__class__.__name__, - code=self.errcode, - msg=self.errmsg + _repr = "{klass}({code}, {msg})".format( + klass=self.__class__.__name__, code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -51,8 +48,7 @@ def __repr__(self): class WeChatClientException(WeChatException): """WeChat API client exception class""" - def __init__(self, errcode, errmsg, client=None, - request=None, response=None): + def __init__(self, errcode, errmsg, client=None, request=None, response=None): super(WeChatClientException, self).__init__(errcode, errmsg) self.client = client self.request = request @@ -62,38 +58,49 @@ def __init__(self, errcode, errmsg, client=None, class InvalidSignatureException(WeChatException): """Invalid signature exception class""" - def __init__(self, errcode=-40001, errmsg='Invalid signature'): + def __init__(self, errcode=-40001, errmsg="Invalid signature"): super(InvalidSignatureException, self).__init__(errcode, errmsg) class APILimitedException(WeChatClientException): """WeChat API call limited exception class""" + pass class InvalidAppIdException(WeChatException): """Invalid app_id exception class""" - def __init__(self, errcode=-40005, errmsg='Invalid AppId'): + def __init__(self, errcode=-40005, errmsg="Invalid AppId"): super(InvalidAppIdException, self).__init__(errcode, errmsg) class WeChatOAuthException(WeChatClientException): """WeChat OAuth API exception class""" + pass class WeChatComponentOAuthException(WeChatClientException): """WeChat Component OAuth API exception class""" + pass class WeChatPayException(WeChatClientException): """WeChat Pay API exception class""" - def __init__(self, return_code, result_code=None, return_msg=None, - errcode=None, errmsg=None, client=None, - request=None, response=None): + def __init__( + self, + return_code, + result_code=None, + return_msg=None, + errcode=None, + errmsg=None, + client=None, + request=None, + response=None, + ): """ :param return_code: 返回状态码 :param result_code: 业务结果 @@ -102,11 +109,7 @@ def __init__(self, return_code, result_code=None, return_msg=None, :param errmsg: 错误代码描述 """ super(WeChatPayException, self).__init__( - errcode, - errmsg, - client, - request, - response + errcode, errmsg, client, request, response ) self.return_code = return_code self.result_code = result_code @@ -114,27 +117,31 @@ def __init__(self, return_code, result_code=None, return_msg=None, def __str__(self): if six.PY2: - return to_binary('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_binary( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) else: - return to_text('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_text( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) def __repr__(self): - _repr = '{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})'.format( + _repr = "{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})".format( klass=self.__class__.__name__, code=self.return_code, msg=self.return_msg, pay_code=self.errcode, - pay_msg=self.errmsg + pay_msg=self.errmsg, ) if six.PY2: return to_binary(_repr) diff --git a/chapter12/booking_system/exts/wechatpy/fields.py b/chapter12/booking_system/exts/wechatpy/fields.py index 8db6847..9a4bdf9 100644 --- a/chapter12/booking_system/exts/wechatpy/fields.py +++ b/chapter12/booking_system/exts/wechatpy/fields.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.fields - ~~~~~~~~~~~~~~~~ +wechatpy.fields +~~~~~~~~~~~~~~~~ - This module defines some useful field types for parse WeChat messages +This module defines some useful field types for parse WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -19,7 +19,7 @@ from exts.wechatpy.utils import to_text, to_binary, ObjectDict, timezone -default_timezone = timezone('Asia/Shanghai') +default_timezone = timezone("Asia/Shanghai") class FieldDescriptor(object): @@ -36,8 +36,11 @@ def __get__(self, instance, instance_type=None): instance._data[self.attr_name] = value if isinstance(value, dict): value = ObjectDict(value) - if value and not isinstance(value, (dict, list, tuple)) and \ - six.callable(self.field.converter): + if ( + value + and not isinstance(value, (dict, list, tuple)) + and six.callable(self.field.converter) + ): value = self.field.converter(value) return value return self.field @@ -61,9 +64,8 @@ def from_xml(cls, value): raise NotImplementedError() def __repr__(self): - _repr = '{klass}({name})'.format( - klass=self.__class__.__name__, - name=repr(self.name) + _repr = "{klass}({name})".format( + klass=self.__class__.__name__, name=repr(self.name) ) if six.PY2: return to_binary(_repr) @@ -85,7 +87,7 @@ def __to_text(self, value): def to_xml(self, value): value = self.converter(value) - tpl = '<{name}>' + tpl = "<{name}>" return tpl.format(name=self.name, value=value) @classmethod @@ -98,7 +100,7 @@ class IntegerField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -110,12 +112,13 @@ class DateTimeField(BaseField): def __converter(self, value): v = int(value) return datetime.fromtimestamp(v, tz=default_timezone) + converter = __converter def to_xml(self, value): value = time.mktime(datetime.timetuple(value)) value = int(value) - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -128,7 +131,7 @@ class FloatField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -167,62 +170,66 @@ def from_xml(cls, value): class VideoField(StringField): def to_xml(self, value): - kwargs = dict(media_id=self.converter(value['media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' + kwargs = dict(media_id=self.converter(value["media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" tpl = """""".format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(media_id=value['MediaId']) - if 'Title' in value: - rv["title"] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] + rv = dict(media_id=value["MediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] return rv class MusicField(StringField): def to_xml(self, value): - kwargs = dict(thumb_media_id=self.converter(value['thumb_media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' - if 'music_url' in value: - kwargs['music_url'] = self.converter(value['music_url']) - content += '' - if 'hq_music_url' in value: - kwargs['hq_music_url'] = self.converter(value['hq_music_url']) - content += '' + kwargs = dict(thumb_media_id=self.converter(value["thumb_media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" + if "music_url" in value: + kwargs["music_url"] = self.converter(value["music_url"]) + content += "" + if "hq_music_url" in value: + kwargs["hq_music_url"] = self.converter(value["hq_music_url"]) + content += "" tpl = """ {content} - """.format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(thumb_media_id=value['ThumbMediaId']) - if 'Title' in value: - rv['title'] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] - if 'MusicUrl' in value: - rv['music_url'] = value['MusicUrl'] - if 'HQMusicUrl' in value: - rv['hq_music_url'] = value['HQMusicUrl'] + rv = dict(thumb_media_id=value["ThumbMediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] + if "MusicUrl" in value: + rv["music_url"] = value["MusicUrl"] + if "HQMusicUrl" in value: + rv["hq_music_url"] = value["HQMusicUrl"] return rv @@ -232,10 +239,10 @@ def to_xml(self, articles): article_count = len(articles) items = [] for article in articles: - title = self.converter(article.get('title', '')) - description = self.converter(article.get('description', '')) - image = self.converter(article.get('image', '')) - url = self.converter(article.get('url', '')) + title = self.converter(article.get("title", "")) + description = self.converter(article.get("description", "")) + image = self.converter(article.get("image", "")) + url = self.converter(article.get("url", "")) item_tpl = """ <![CDATA[{title}]]> @@ -243,28 +250,25 @@ def to_xml(self, articles): """ item = item_tpl.format( - title=title, - description=description, - image=image, - url=url + title=title, description=description, image=image, url=url ) items.append(item) - items_str = '\n'.join(items) + items_str = "\n".join(items) tpl = """{article_count} {items}""" - return tpl.format( - article_count=article_count, - items=items_str - ) + return tpl.format(article_count=article_count, items=items_str) @classmethod def from_xml(cls, value): - return [dict( - title=item["Title"], - description=item["Description"], - image=item["PicUrl"], - url=item["Url"] - ) for item in value["item"]] + return [ + dict( + title=item["Title"], + description=item["Description"], + image=item["PicUrl"], + url=item["Url"], + ) + for item in value["item"] + ] class Base64EncodeField(StringField): @@ -286,13 +290,11 @@ def __base64_decode(self, text): class HardwareField(StringField): def to_xml(self, value=None): - value = value or {'view': 'myrank', 'action': 'ranklist'} + value = value or {"view": "myrank", "action": "ranklist"} tpl = """<{name}> """ return tpl.format( - name=self.name, - view=value.get('view'), - action=value.get('action') + name=self.name, view=value.get("view"), action=value.get("action") ) diff --git a/chapter12/booking_system/exts/wechatpy/messages.py b/chapter12/booking_system/exts/wechatpy/messages.py index 04f4d0c..9e33666 100644 --- a/chapter12/booking_system/exts/wechatpy/messages.py +++ b/chapter12/booking_system/exts/wechatpy/messages.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.messages - ~~~~~~~~~~~~~~~~~~ +wechatpy.messages +~~~~~~~~~~~~~~~~~~ - This module defines all the messages you can get from WeChat server +This module defines all the messages you can get from WeChat server - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import copy @@ -17,7 +17,7 @@ StringField, IntegerField, DateTimeField, - FieldDescriptor + FieldDescriptor, ) from exts.wechatpy.utils import to_text, to_binary @@ -29,14 +29,16 @@ def register_message(msg_type): def register(cls): MESSAGE_TYPES[msg_type] = cls return cls + return register class MessageMetaClass(type): """Metaclass for all messages""" + def __new__(cls, name, bases, attrs): for b in bases: - if not hasattr(b, '_fields'): + if not hasattr(b, "_fields"): continue for k, v in b.__dict__.items(): @@ -56,20 +58,20 @@ def __new__(cls, name, bases, attrs): class BaseMessage(six.with_metaclass(MessageMetaClass)): """Base class for all messages and events""" - type = 'unknown' - id = IntegerField('MsgId', 0) - source = StringField('FromUserName') - target = StringField('ToUserName') - create_time = DateTimeField('CreateTime') - time = IntegerField('CreateTime') + + type = "unknown" + id = IntegerField("MsgId", 0) + source = StringField("FromUserName") + target = StringField("ToUserName") + create_time = DateTimeField("CreateTime") + time = IntegerField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -77,97 +79,105 @@ def __repr__(self): return to_text(_repr) -@register_message('text') +@register_message("text") class TextMessage(BaseMessage): """ 文本消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_message('image') + +@register_message("image") class ImageMessage(BaseMessage): """ 图片消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'image' - media_id = StringField('MediaId') - image = StringField('PicUrl') + + type = "image" + media_id = StringField("MediaId") + image = StringField("PicUrl") -@register_message('voice') +@register_message("voice") class VoiceMessage(BaseMessage): """ 语音消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'voice' - media_id = StringField('MediaId') - format = StringField('Format') - recognition = StringField('Recognition') + + type = "voice" + media_id = StringField("MediaId") + format = StringField("Format") + recognition = StringField("Recognition") -@register_message('shortvideo') +@register_message("shortvideo") class ShortVideoMessage(BaseMessage): """ 短视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'shortvideo' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + type = "shortvideo" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('video') + +@register_message("video") class VideoMessage(BaseMessage): """ 视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'video' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + + type = "video" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('location') +@register_message("location") class LocationMessage(BaseMessage): """ 地理位置消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'location' - location_x = StringField('Location_X') - location_y = StringField('Location_Y') - scale = StringField('Scale') - label = StringField('Label') + + type = "location" + location_x = StringField("Location_X") + location_y = StringField("Location_Y") + scale = StringField("Scale") + label = StringField("Label") @property def location(self): return self.location_x, self.location_y -@register_message('link') +@register_message("link") class LinkMessage(BaseMessage): """ 链接消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'link' - title = StringField('Title') - description = StringField('Description') - url = StringField('Url') + + type = "link" + title = StringField("Title") + description = StringField("Description") + url = StringField("Url") class UnknownMessage(BaseMessage): """未知消息类型""" + pass diff --git a/chapter12/booking_system/exts/wechatpy/oauth.py b/chapter12/booking_system/exts/wechatpy/oauth.py index db5743a..984cffa 100644 --- a/chapter12/booking_system/exts/wechatpy/oauth.py +++ b/chapter12/booking_system/exts/wechatpy/oauth.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.oauth - ~~~~~~~~~~~~~~~ +wechatpy.oauth +~~~~~~~~~~~~~~~ - This module provides OAuth2 library for WeChat +This module provides OAuth2 library for WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -18,16 +18,16 @@ class WeChatOAuth(object): - """ 微信公众平台 OAuth 网页授权 + """微信公众平台 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" - def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): + def __init__(self, app_id, secret, redirect_uri, scope="snsapi_base", state=""): """ :param app_id: 微信公众号 app_id @@ -44,24 +44,19 @@ def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): self._http = requests.Session() def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -70,29 +65,21 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result['errmsg'] + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result["errmsg"] raise WeChatOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) @property def authorize_url(self): @@ -100,20 +87,20 @@ def authorize_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - self.scope + "&response_type=code&scope=", + self.scope, ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) @property def qrconnect_url(self): @@ -121,20 +108,20 @@ def qrconnect_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'qrconnect?appid=', + "qrconnect?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - 'snsapi_login' # scope + "&response_type=code&scope=", + "snsapi_login", # scope ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -143,18 +130,18 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/access_token', + "sns/oauth2/access_token", params={ - 'appid': self.app_id, - 'secret': self.secret, - 'code': code, - 'grant_type': 'authorization_code' - } + "appid": self.app_id, + "secret": self.secret, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res def refresh_access_token(self, refresh_token): @@ -164,20 +151,20 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/refresh_token', + "sns/oauth2/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): """获取用户信息 :param openid: 可选,微信 openid,默认获取当前授权用户信息 @@ -188,12 +175,8 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def check_access_token(self, openid=None, access_token=None): @@ -206,12 +189,8 @@ def check_access_token(self, openid=None, access_token=None): openid = openid or self.open_id access_token = access_token or self.access_token res = self._get( - 'sns/auth', - params={ - 'access_token': access_token, - 'openid': openid - } + "sns/auth", params={"access_token": access_token, "openid": openid} ) - if res['errcode'] == 0: + if res["errcode"] == 0: return True return False diff --git a/chapter12/booking_system/exts/wechatpy/parser.py b/chapter12/booking_system/exts/wechatpy/parser.py index 11f3af7..0706fae 100644 --- a/chapter12/booking_system/exts/wechatpy/parser.py +++ b/chapter12/booking_system/exts/wechatpy/parser.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.parser - ~~~~~~~~~~~~~~~~ - This module provides functions for parsing WeChat messages +wechatpy.parser +~~~~~~~~~~~~~~~~ +This module provides functions for parsing WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import xmltodict @@ -24,28 +24,28 @@ def parse_message(xml): """ if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() event_type = None - if message_type == 'event' or message_type.startswith('device_'): - if 'Event' in message: - event_type = message['Event'].lower() + if message_type == "event" or message_type.startswith("device_"): + if "Event" in message: + event_type = message["Event"].lower() # special event type for device_event - if event_type is None and message_type.startswith('device_'): + if event_type is None and message_type.startswith("device_"): event_type = message_type - elif message_type.startswith('device_'): - event_type = 'device_{event}'.format(event=event_type) + elif message_type.startswith("device_"): + event_type = "device_{event}".format(event=event_type) - if event_type == 'subscribe' and message.get('EventKey'): - event_key = message['EventKey'] - if event_key.startswith(('scanbarcode|', 'scanimage|')): - event_type = 'subscribe_scan_product' - message['Event'] = event_type - elif event_key.startswith('qrscene_'): + if event_type == "subscribe" and message.get("EventKey"): + event_key = message["EventKey"] + if event_key.startswith(("scanbarcode|", "scanimage|")): + event_type = "subscribe_scan_product" + message["Event"] = event_type + elif event_key.startswith("qrscene_"): # Scan to subscribe with scene id event - event_type = 'subscribe_scan' - message['Event'] = event_type - message['EventKey'] = event_key[len('qrscene_'):] + event_type = "subscribe_scan" + message["Event"] = event_type + message["EventKey"] = event_key[len("qrscene_") :] message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter12/booking_system/exts/wechatpy/pay/__init__.py b/chapter12/booking_system/exts/wechatpy/pay/__init__.py index ff9dc96..e7ce60d 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/__init__.py +++ b/chapter12/booking_system/exts/wechatpy/pay/__init__.py @@ -11,7 +11,10 @@ from exts.wechatpy.utils import random_string from exts.wechatpy.exceptions import WeChatPayException, InvalidSignatureException from exts.wechatpy.pay.utils import ( - calculate_signature, calculate_signature_hmac, _check_signature, dict_to_xml + calculate_signature, + calculate_signature_hmac, + _check_signature, + dict_to_xml, ) from exts.wechatpy.pay.base import BaseWeChatPayAPI from exts.wechatpy.pay import api @@ -57,7 +60,7 @@ class WeChatPay(object): withhold = api.WeChatWithhold() """代扣接口""" - API_BASE_URL = 'https://api.mch.weixin.qq.com/' + API_BASE_URL = "https://api.mch.weixin.qq.com/" def __new__(cls, *args, **kwargs): self = super(WeChatPay, cls).__new__(cls) @@ -68,8 +71,18 @@ def __new__(cls, *args, **kwargs): setattr(self, name, _api) return self - def __init__(self, appid, api_key, mch_id, sub_mch_id=None, - mch_cert=None, mch_key=None, timeout=None, sandbox=False, sub_appid=None): + def __init__( + self, + appid, + api_key, + mch_id, + sub_mch_id=None, + mch_cert=None, + mch_key=None, + timeout=None, + sandbox=False, + sub_appid=None, + ): self.appid = appid self.sub_appid = sub_appid self.api_key = api_key @@ -84,56 +97,58 @@ def __init__(self, appid, api_key, mch_id, sub_mch_id=None, def _fetch_sandbox_api_key(self): nonce_str = random_string(32) - sign = calculate_signature({'mch_id': self.mch_id, 'nonce_str': nonce_str}, self.api_key) - payload = dict_to_xml({ - 'mch_id': self.mch_id, - 'nonce_str': nonce_str, - }, sign=sign) - headers = {'Content-Type': 'text/xml'} - api_url = '{base}sandboxnew/pay/getsignkey'.format(base=self.API_BASE_URL) + sign = calculate_signature( + {"mch_id": self.mch_id, "nonce_str": nonce_str}, self.api_key + ) + payload = dict_to_xml( + { + "mch_id": self.mch_id, + "nonce_str": nonce_str, + }, + sign=sign, + ) + headers = {"Content-Type": "text/xml"} + api_url = "{base}sandboxnew/pay/getsignkey".format(base=self.API_BASE_URL) response = self._http.post(api_url, data=payload, headers=headers) - return xmltodict.parse(response.text)['xml'].get('sandbox_signkey') + return xmltodict.parse(response.text)["xml"].get("sandbox_signkey") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) if self.sandbox: - api_base_url = '{url}sandboxnew/'.format(url=api_base_url) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + api_base_url = "{url}sandboxnew/".format(url=api_base_url) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - data = kwargs['data'] - if 'mchid' not in data: + if isinstance(kwargs.get("data", ""), dict): + data = kwargs["data"] + if "mchid" not in data: # Fuck Tencent - data.setdefault('mch_id', self.mch_id) - data.setdefault('sub_mch_id', self.sub_mch_id) - data.setdefault('nonce_str', random_string(32)) + data.setdefault("mch_id", self.mch_id) + data.setdefault("sub_mch_id", self.sub_mch_id) + data.setdefault("nonce_str", random_string(32)) data = optionaldict(data) - if data.get('sign_type', 'MD5') == 'HMAC-SHA256': - sign = calculate_signature_hmac(data, self.sandbox_api_key if self.sandbox else self.api_key) + if data.get("sign_type", "MD5") == "HMAC-SHA256": + sign = calculate_signature_hmac( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) else: - sign = calculate_signature(data, self.sandbox_api_key if self.sandbox else self.api_key) + sign = calculate_signature( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) body = dict_to_xml(data, sign) - body = body.encode('utf-8') - kwargs['data'] = body + body = body.encode("utf-8") + kwargs["data"] = body # 商户证书 if self.mch_cert and self.mch_key: - kwargs['cert'] = (self.mch_cert, self.mch_key) - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - logger.debug('Request to WeChat API: %s %s\n%s', method, url, kwargs) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + kwargs["cert"] = (self.mch_cert, self.mch_key) + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + logger.debug("Request to WeChat API: %s %s\n%s", method, url, kwargs) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -141,28 +156,28 @@ def _request(self, method, url_or_endpoint, **kwargs): return_code=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res) def _handle_result(self, res): - res.encoding = 'utf-8' + res.encoding = "utf-8" xml = res.text - logger.debug('Response from WeChat API \n %s', xml) + logger.debug("Response from WeChat API \n %s", xml) try: - data = xmltodict.parse(xml)['xml'] + data = xmltodict.parse(xml)["xml"] except (xmltodict.ParsingInterrupted, ExpatError): # 解析 XML 失败 - logger.debug('WeChat payment result xml parsing error', exc_info=True) + logger.debug("WeChat payment result xml parsing error", exc_info=True) return xml - return_code = data['return_code'] - return_msg = data.get('return_msg') - result_code = data.get('result_code') - errcode = data.get('err_code') - errmsg = data.get('err_code_des') - if return_code != 'SUCCESS' or result_code != 'SUCCESS': + return_code = data["return_code"] + return_msg = data.get("return_msg") + result_code = data.get("result_code") + errcode = data.get("err_code") + errmsg = data.get("err_code_des") + if return_code != "SUCCESS" or result_code != "SUCCESS": # 返回状态码不为成功 raise WeChatPayException( return_code, @@ -172,26 +187,20 @@ def _handle_result(self, res): errmsg, client=self, request=res.request, - response=res + response=res, ) return data def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def check_signature(self, params): - return _check_signature(params, self.api_key if not self.sandbox else self.sandbox_api_key) + return _check_signature( + params, self.api_key if not self.sandbox else self.sandbox_api_key + ) def parse_payment_result(self, xml): """解析微信支付结果通知""" @@ -200,22 +209,30 @@ def parse_payment_result(self, xml): except (xmltodict.ParsingInterrupted, ExpatError): raise InvalidSignatureException() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise InvalidSignatureException() - data = data['xml'] - sign = data.pop('sign', None) - if '#text' in data.keys(): + data = data["xml"] + sign = data.pop("sign", None) + if "#text" in data.keys(): pass - del data['#text'] - real_sign = calculate_signature(data, self.api_key if not self.sandbox else self.sandbox_api_key) + del data["#text"] + real_sign = calculate_signature( + data, self.api_key if not self.sandbox else self.sandbox_api_key + ) if sign != real_sign: raise InvalidSignatureException() - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) - data['sign'] = sign + data["sign"] = sign return data @property diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/coupon.py b/chapter12/booking_system/exts/wechatpy/pay/api/coupon.py index 53cd0bc..fe97cfd 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/coupon.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/coupon.py @@ -8,8 +8,9 @@ class WeChatCoupon(BaseWeChatPayAPI): - def send(self, user_id, stock_id, op_user_id=None, device_info=None, - out_trade_no=None): + def send( + self, user_id, stock_id, op_user_id=None, device_info=None, out_trade_no=None + ): """ 发放代金券 @@ -22,23 +23,21 @@ def send(self, user_id, stock_id, op_user_id=None, device_info=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'openid': user_id, - 'openid_count': 1, - 'partner_trade_no': out_trade_no, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "openid": user_id, + "openid_count": 1, + "partner_trade_no": out_trade_no, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/send_coupon', data=data) + return self._post("mmpaymkttransfers/send_coupon", data=data) def query_stock(self, stock_id, op_user_id=None, device_info=None): """ @@ -50,17 +49,16 @@ def query_stock(self, stock_id, op_user_id=None, device_info=None): :return: 返回的结果信息 """ data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/query_coupon_stock', data=data) + return self._post("mmpaymkttransfers/query_coupon_stock", data=data) - def query_coupon(self, coupon_id, user_id, - op_user_id=None, device_info=None): + def query_coupon(self, coupon_id, user_id, op_user_id=None, device_info=None): """ 查询代金券信息 @@ -71,12 +69,12 @@ def query_coupon(self, coupon_id, user_id, :return: 返回的结果信息 """ data = { - 'coupon_id': coupon_id, - 'openid': user_id, - 'appid': self.appid, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "coupon_id": coupon_id, + "openid": user_id, + "appid": self.appid, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('promotion/query_coupon', data=data) + return self._post("promotion/query_coupon", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/jsapi.py b/chapter12/booking_system/exts/wechatpy/pay/api/jsapi.py index 79ed209..a818fe8 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/jsapi.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/jsapi.py @@ -8,6 +8,7 @@ logger = logging.getLogger(__name__) + class WeChatJSAPI(BaseWeChatPayAPI): def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): @@ -20,15 +21,19 @@ def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } return calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=False): @@ -44,18 +49,22 @@ def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=Fals :return: 参数 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } sign = calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) - logger.debug('JSAPI payment parameters: data = %s, sign = %s', data, sign) - data['paySign'] = sign + logger.debug("JSAPI payment parameters: data = %s, sign = %s", data, sign) + data["paySign"] = sign if jssdk: - data['timestamp'] = data.pop('timeStamp') + data["timestamp"] = data.pop("timeStamp") return data diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/micropay.py b/chapter12/booking_system/exts/wechatpy/pay/api/micropay.py index 30e8714..439cf19 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/micropay.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/micropay.py @@ -8,8 +8,20 @@ class WeChatMicroPay(BaseWeChatPayAPI): - def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', goods_tag=None, device_info=None, limit_pay=None): + def create( + self, + body, + total_fee, + auth_code, + client_ip=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + device_info=None, + limit_pay=None, + ): """ 刷卡支付接口 :param device_info: 可选,终端设备号(商户自定义,如门店编号) @@ -27,26 +39,24 @@ def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, """ now = datetime.now() if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'total_fee': total_fee, - 'fee_type': fee_type, - 'spbill_create_ip': client_ip or get_external_ip(), - 'goods_tag': goods_tag, - 'limit_pay': limit_pay, - 'auth_code': auth_code, + "appid": self.appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "total_fee": total_fee, + "fee_type": fee_type, + "spbill_create_ip": client_ip or get_external_ip(), + "goods_tag": goods_tag, + "limit_pay": limit_pay, + "auth_code": auth_code, } - return self._post('pay/micropay', data=data) + return self._post("pay/micropay", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -57,8 +67,8 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/order.py b/chapter12/booking_system/exts/wechatpy/pay/api/order.py index ebc3549..68005fd 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/order.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/order.py @@ -13,10 +13,27 @@ class WeChatOrder(BaseWeChatPayAPI): - def create(self, trade_type, body, total_fee, notify_url, client_ip=None, - user_id=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', time_start=None, time_expire=None, goods_tag=None, - product_id=None, device_info=None, limit_pay=None, scene_info=None, sub_user_id=None): + def create( + self, + trade_type, + body, + total_fee, + notify_url, + client_ip=None, + user_id=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + time_start=None, + time_expire=None, + goods_tag=None, + product_id=None, + device_info=None, + limit_pay=None, + scene_info=None, + sub_user_id=None, + ): """ 统一下单接口 @@ -41,43 +58,41 @@ def create(self, trade_type, body, total_fee, notify_url, client_ip=None, :type scene_info: dict :return: 返回的结果数据 """ - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) hours_later = now + timedelta(hours=2) if time_start is None: time_start = now if time_expire is None: time_expire = hours_later if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) if scene_info is not None: scene_info = json.dumps(scene_info, ensure_ascii=False) data = { - 'appid': self.appid, - 'sub_appid': self.sub_appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'fee_type': fee_type, - 'total_fee': total_fee, - 'spbill_create_ip': client_ip or get_external_ip(), - 'time_start': time_start.strftime('%Y%m%d%H%M%S'), - 'time_expire': time_expire.strftime('%Y%m%d%H%M%S'), - 'goods_tag': goods_tag, - 'notify_url': notify_url, - 'trade_type': trade_type, - 'limit_pay': limit_pay, - 'product_id': product_id, - 'openid': user_id, - 'sub_openid': sub_user_id, - 'scene_info': scene_info, + "appid": self.appid, + "sub_appid": self.sub_appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "fee_type": fee_type, + "total_fee": total_fee, + "spbill_create_ip": client_ip or get_external_ip(), + "time_start": time_start.strftime("%Y%m%d%H%M%S"), + "time_expire": time_expire.strftime("%Y%m%d%H%M%S"), + "goods_tag": goods_tag, + "notify_url": notify_url, + "trade_type": trade_type, + "limit_pay": limit_pay, + "product_id": product_id, + "openid": user_id, + "sub_openid": sub_user_id, + "scene_info": scene_info, } - return self._post('pay/unifiedorder', data=data) + return self._post("pay/unifiedorder", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -88,11 +103,11 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) def close(self, out_trade_no): """ @@ -102,10 +117,10 @@ def close(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "out_trade_no": out_trade_no, } - return self._post('pay/closeorder', data=data) + return self._post("pay/closeorder", data=data) def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): """ @@ -117,15 +132,15 @@ def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appid': self.appid, - 'partnerid': self.mch_id, - 'prepayid': prepay_id, - 'package': 'Sign=WXPay', - 'timestamp': timestamp or to_text(int(time.time())), - 'noncestr': nonce_str or random_string(32) + "appid": self.appid, + "partnerid": self.mch_id, + "prepayid": prepay_id, + "package": "Sign=WXPay", + "timestamp": timestamp or to_text(int(time.time())), + "noncestr": nonce_str or random_string(32), } sign = calculate_signature(data, self._client.api_key) - data['sign'] = sign + data["sign"] = sign return data def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): @@ -138,14 +153,14 @@ def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'package': 'prepay_id='+prepay_id, - 'signType': 'MD5' + "appId": self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "package": "prepay_id=" + prepay_id, + "signType": "MD5", } sign = calculate_signature(data, self._client.api_key) - data['paySign'] = sign + data["paySign"] = sign return data def reverse(self, transaction_id=None, out_trade_no=None): @@ -159,8 +174,8 @@ def reverse(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('secapi/pay/reverse', data=data) + return self._post("secapi/pay/reverse", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/redpack.py b/chapter12/booking_system/exts/wechatpy/pay/api/redpack.py index c888b97..5a779f7 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/redpack.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/redpack.py @@ -9,9 +9,20 @@ class WeChatRedpack(BaseWeChatPayAPI): - def send(self, user_id, total_amount, send_name, act_name, - wishing, remark, total_num=1, client_ip=None, - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num=1, + client_ip=None, + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送现金红包 @@ -30,31 +41,41 @@ def send(self, user_id, total_amount, send_name, act_name, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'client_ip': client_ip or get_external_ip(), - 'total_num': total_num, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "client_ip": client_ip or get_external_ip(), + "total_num": total_num, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendredpack', data=data) + return self._post("mmpaymkttransfers/sendredpack", data=data) - def send_group(self, user_id, total_amount, send_name, act_name, wishing, - remark, total_num, client_ip=None, amt_type="ALL_RAND", - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send_group( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num, + client_ip=None, + amt_type="ALL_RAND", + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送裂变红包 @@ -75,30 +96,30 @@ def send_group(self, user_id, total_amount, send_name, act_name, wishing, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( + out_trade_no = "{0}{1}{2}".format( self._client.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now.strftime("%Y%m%d%H%M%S"), + random.randint(1000, 10000), ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'total_num': total_num, - 'client_ip': client_ip or get_external_ip(), - 'amt_type': amt_type, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "total_num": total_num, + "client_ip": client_ip or get_external_ip(), + "amt_type": amt_type, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendgroupredpack', data=data) + return self._post("mmpaymkttransfers/sendgroupredpack", data=data) - def query(self, out_trade_no, bill_type='MCHT'): + def query(self, out_trade_no, bill_type="MCHT"): """ 查询红包发放记录 @@ -107,8 +128,8 @@ def query(self, out_trade_no, bill_type='MCHT'): :return: 返回的红包发放记录信息 """ data = { - 'mch_billno': out_trade_no, - 'bill_type': bill_type, - 'appid': self.appid, + "mch_billno": out_trade_no, + "bill_type": bill_type, + "appid": self.appid, } - return self._post('mmpaymkttransfers/gethbinfo', data=data) + return self._post("mmpaymkttransfers/gethbinfo", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/refund.py b/chapter12/booking_system/exts/wechatpy/pay/api/refund.py index 8d9a5d1..9dec65b 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/refund.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/refund.py @@ -6,10 +6,19 @@ class WeChatRefund(BaseWeChatPayAPI): - def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, - out_trade_no=None, fee_type='CNY', op_user_id=None, - device_info=None, refund_account='REFUND_SOURCE_UNSETTLED_FUNDS', - notify_url=None): + def apply( + self, + total_fee, + refund_fee, + out_refund_no, + transaction_id=None, + out_trade_no=None, + fee_type="CNY", + op_user_id=None, + device_info=None, + refund_account="REFUND_SOURCE_UNSETTLED_FUNDS", + notify_url=None, + ): """ 申请退款 @@ -26,22 +35,28 @@ def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'total_fee': total_fee, - 'refund_fee': refund_fee, - 'refund_fee_type': fee_type, - 'op_user_id': op_user_id if op_user_id else self.mch_id, - 'refund_account': refund_account, - 'notify_url': notify_url, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "total_fee": total_fee, + "refund_fee": refund_fee, + "refund_fee_type": fee_type, + "op_user_id": op_user_id if op_user_id else self.mch_id, + "refund_account": refund_account, + "notify_url": notify_url, } - return self._post('secapi/pay/refund', data=data) + return self._post("secapi/pay/refund", data=data) - def query(self, refund_id=None, out_refund_no=None, transaction_id=None, - out_trade_no=None, device_info=None): + def query( + self, + refund_id=None, + out_refund_no=None, + transaction_id=None, + out_trade_no=None, + device_info=None, + ): """ 查询退款 @@ -53,11 +68,11 @@ def query(self, refund_id=None, out_refund_no=None, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'refund_id': refund_id, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "refund_id": refund_id, } - return self._post('pay/refundquery', data=data) + return self._post("pay/refundquery", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/tools.py b/chapter12/booking_system/exts/wechatpy/pay/api/tools.py index 75ffc33..1c76797 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/tools.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/tools.py @@ -15,12 +15,12 @@ def short_url(self, long_url): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'long_url': long_url, + "appid": self.appid, + "long_url": long_url, } - return self._post('tools/shorturl', data=data) + return self._post("tools/shorturl", data=data) - def download_bill(self, bill_date, bill_type='ALL', device_info=None): + def download_bill(self, bill_date, bill_type="ALL", device_info=None): """ 下载对账单 @@ -33,18 +33,17 @@ def download_bill(self, bill_date, bill_type='ALL', device_info=None): :return: 返回的结果数据 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'bill_type': bill_type, - 'device_info': device_info, + "appid": self.appid, + "bill_date": bill_date, + "bill_type": bill_type, + "device_info": device_info, } - return self._post('pay/downloadbill', data=data) + return self._post("pay/downloadbill", data=data) - def download_fundflow(self, bill_date, account_type='Basic', - tar_type=None): + def download_fundflow(self, bill_date, account_type="Basic", tar_type=None): """ 下载资金账单 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7 @@ -58,17 +57,17 @@ def download_fundflow(self, bill_date, account_type='Basic', 不传则默认为数据流形式。 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'account_type': account_type, - 'sign_type': 'HMAC-SHA256' + "appid": self.appid, + "bill_date": bill_date, + "account_type": account_type, + "sign_type": "HMAC-SHA256", } if tar_type is not None: - data['tar_type'] = tar_type - return self._post('pay/downloadfundflow', data=data) + data["tar_type"] = tar_type + return self._post("pay/downloadfundflow", data=data) def auto_code_to_openid(self, auth_code): """ @@ -78,7 +77,7 @@ def auto_code_to_openid(self, auth_code): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'auth_code': auth_code, + "appid": self.appid, + "auth_code": auth_code, } - return self._post('tools/authcodetoopenid', data=data) + return self._post("tools/authcodetoopenid", data=data) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/transfer.py b/chapter12/booking_system/exts/wechatpy/pay/api/transfer.py index 0b49951..13701fe 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/transfer.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/transfer.py @@ -9,9 +9,17 @@ class WeChatTransfer(BaseWeChatPayAPI): - def transfer(self, user_id, amount, desc, client_ip=None, - check_name='OPTION_CHECK', real_name=None, - out_trade_no=None, device_info=None): + def transfer( + self, + user_id, + amount, + desc, + client_ip=None, + check_name="OPTION_CHECK", + real_name=None, + out_trade_no=None, + device_info=None, + ): """ 企业付款接口 @@ -32,24 +40,22 @@ def transfer(self, user_id, amount, desc, client_ip=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_appid': self.appid, - 'mchid': self.mch_id, - 'device_info': device_info, - 'partner_trade_no': out_trade_no, - 'openid': user_id, - 'check_name': check_name, - 're_user_name': real_name, - 'amount': amount, - 'desc': desc, - 'spbill_create_ip': client_ip or get_external_ip(), + "mch_appid": self.appid, + "mchid": self.mch_id, + "device_info": device_info, + "partner_trade_no": out_trade_no, + "openid": user_id, + "check_name": check_name, + "re_user_name": real_name, + "amount": amount, + "desc": desc, + "spbill_create_ip": client_ip or get_external_ip(), } - return self._post('mmpaymkttransfers/promotion/transfers', data=data) + return self._post("mmpaymkttransfers/promotion/transfers", data=data) def query(self, out_trade_no): """ @@ -59,12 +65,14 @@ def query(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'partner_trade_no': out_trade_no, + "appid": self.appid, + "partner_trade_no": out_trade_no, } - return self._post('mmpaymkttransfers/gettransferinfo', data=data) + return self._post("mmpaymkttransfers/gettransferinfo", data=data) - def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None): + def transfer_bankcard( + self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None + ): """ 企业付款到银行卡接口 @@ -78,21 +86,19 @@ def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=Non """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, - 'amount': amount, - 'desc': desc, - 'enc_bank_no': self._rsa_encrypt(bank_card_no), - 'enc_true_name': self._rsa_encrypt(true_name), - 'bank_code': bank_code, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, + "amount": amount, + "desc": desc, + "enc_bank_no": self._rsa_encrypt(bank_card_no), + "enc_true_name": self._rsa_encrypt(true_name), + "bank_code": bank_code, } - return self._post('mmpaysptrans/pay_bank', data=data) + return self._post("mmpaysptrans/pay_bank", data=data) def query_bankcard(self, out_trade_no): """ @@ -102,19 +108,21 @@ def query_bankcard(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, } - return self._post('mmpaysptrans/query_bank', data=data) + return self._post("mmpaysptrans/query_bank", data=data) def get_rsa_public_key(self): data = { - 'mch_id': self.mch_id, - 'sign_type': 'MD5', + "mch_id": self.mch_id, + "sign_type": "MD5", } - return self._post('https://fraud.mch.weixin.qq.com/risk/getpublickey', data=data) + return self._post( + "https://fraud.mch.weixin.qq.com/risk/getpublickey", data=data + ) def _rsa_encrypt(self, data): - if not getattr(self, '_rsa_public_key', None): - self._rsa_public_key = self.get_rsa_public_key()['pub_key'] + if not getattr(self, "_rsa_public_key", None): + self._rsa_public_key = self.get_rsa_public_key()["pub_key"] return rsa_encrypt(data, self._rsa_public_key) diff --git a/chapter12/booking_system/exts/wechatpy/pay/api/withhold.py b/chapter12/booking_system/exts/wechatpy/pay/api/withhold.py index 3e9f2e7..e629d80 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/api/withhold.py +++ b/chapter12/booking_system/exts/wechatpy/pay/api/withhold.py @@ -13,9 +13,23 @@ class WeChatWithhold(BaseWeChatPayAPI): - def apply_signing(self, plan_id, contract_code, contract_display_account, notify_url, - version="1.0", clientip=None, deviceid=None, mobile=None, email=None, qq=None, - request_serial=None, openid=None, creid=None, outerid=None): + def apply_signing( + self, + plan_id, + contract_code, + contract_display_account, + notify_url, + version="1.0", + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + request_serial=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请签约 api @@ -65,10 +79,17 @@ def apply_signing(self, plan_id, contract_code, contract_display_account, notify data["sign"] = sign return { "base_url": "{}papay/entrustweb".format(self._client.API_BASE_URL), - "data": data + "data": data, } - def query_signing(self, contract_id=None, plan_id=None, contract_code=None, openid=None, version="1.0"): + def query_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + openid=None, + version="1.0", + ): """ 查询签约关系 api @@ -79,8 +100,14 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open :param version: 版本号 固定值1.0 :return: 返回的结果信息 """ - if not contract_id and not (plan_id and contract_code) and not (plan_id and openid): - raise ValueError("contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice.") + if ( + not contract_id + and not (plan_id and contract_code) + and not (plan_id and openid) + ): + raise ValueError( + "contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, @@ -91,11 +118,28 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open "version": version, "nonce_str": None, } - return self._post('papay/querycontract', data=data) - - def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=None, - detail=None, attach=None, fee_type='CNY', goods_tag=None, clientip=None, deviceid=None, - mobile=None, email=None, qq=None, openid=None, creid=None, outerid=None): + return self._post("papay/querycontract", data=data) + + def apply_deduct( + self, + body, + total_fee, + contract_id, + notify_url, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请扣款 api @@ -118,15 +162,13 @@ def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=No :param outerid: 可选 商户侧用户标识 用户在商户侧的标识 :return: 返回的结果信息 """ - trade_type = 'PAP' # 交易类型 交易类型PAP-微信委托代扣支付 + trade_type = "PAP" # 交易类型 交易类型PAP-微信委托代扣支付 timestamp = int(time.time()) # 10位时间戳 spbill_create_ip = get_external_ip() # 终端IP 调用微信支付API的机器IP if not out_trade_no: - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { @@ -173,8 +215,14 @@ def query_order(self, transaction_id=None, out_trade_no=None): } return self._post("pay/paporderquery", data=data) - def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=None, - contract_termination_remark=None, version="1.0"): + def apply_cancel_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + contract_termination_remark=None, + version="1.0", + ): """ 申请解约 @@ -188,7 +236,9 @@ def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=Non :return: """ if not (contract_id or (plan_id and contract_code)): - raise ValueError("contract_id and (plan_id, contract_code) must be a choice.") + raise ValueError( + "contract_id and (plan_id, contract_code) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, diff --git a/chapter12/booking_system/exts/wechatpy/pay/base.py b/chapter12/booking_system/exts/wechatpy/pay/base.py index 6184fa9..25c7830 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/base.py +++ b/chapter12/booking_system/exts/wechatpy/pay/base.py @@ -3,18 +3,19 @@ class BaseWeChatPayAPI(object): - """ WeChat Pay API base class """ + """WeChat Pay API base class""" + def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.post(url, **kwargs) @property diff --git a/chapter12/booking_system/exts/wechatpy/pay/utils.py b/chapter12/booking_system/exts/wechatpy/pay/utils.py index 4c1d05d..194be89 100644 --- a/chapter12/booking_system/exts/wechatpy/pay/utils.py +++ b/chapter12/booking_system/exts/wechatpy/pay/utils.py @@ -13,19 +13,22 @@ logger = logging.getLogger(__name__) + def format_url(params, api_key=None): # if '#text' in params: # print(params['#text']) # del params['#text'] # print( params['#text']) - data = [to_binary('{0}={1}'.format(k, params[k])) for k in sorted(params) if params[k]] + data = [ + to_binary("{0}={1}".format(k, params[k])) for k in sorted(params) if params[k] + ] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # del data[0] if api_key: - data.append(to_binary('key={0}'.format(api_key))) + data.append(to_binary("key={0}".format(api_key))) return b"&".join(data) @@ -37,42 +40,45 @@ def calculate_signature(params, api_key): def calculate_signature_hmac(params, api_key): url = format_url(params, api_key) - sign = to_text(hmac.new(api_key.encode(), msg=url, - digestmod=hashlib.sha256).hexdigest().upper()) + sign = to_text( + hmac.new(api_key.encode(), msg=url, digestmod=hashlib.sha256) + .hexdigest() + .upper() + ) return sign def _check_signature(params, api_key): _params = copy.deepcopy(params) - sign = _params.pop('sign', '') + sign = _params.pop("sign", "") return sign == calculate_signature(_params, api_key) def dict_to_xml(d, sign): - xml = ['\n'] + xml = ["\n"] for k in sorted(d): # use sorted to avoid test error on Py3k v = d[k] - if isinstance(v, six.integer_types) or (isinstance(v, six.string_types) and v.isdigit()): - xml.append('<{0}>{1}\n'.format(to_text(k), to_text(v))) + if isinstance(v, six.integer_types) or ( + isinstance(v, six.string_types) and v.isdigit() + ): + xml.append("<{0}>{1}\n".format(to_text(k), to_text(v))) else: - xml.append( - '<{0}>\n'.format(to_text(k), to_text(v)) - ) - xml.append('\n'.format(to_text(sign))) - return ''.join(xml) + xml.append("<{0}>\n".format(to_text(k), to_text(v))) + xml.append("\n".format(to_text(sign))) + return "".join(xml) def get_external_ip(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: - wechat_ip = socket.gethostbyname('api.mch.weixin.qq.com') + wechat_ip = socket.gethostbyname("api.mch.weixin.qq.com") sock.connect((wechat_ip, 80)) addr, port = sock.getsockname() sock.close() return addr except socket.error: - return '127.0.0.1' + return "127.0.0.1" def rsa_encrypt(data, pem, b64_encode=True): @@ -87,6 +93,7 @@ def rsa_encrypt(data, pem, b64_encode=True): from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding + encoded_data = to_binary(data) pem = to_binary(pem) public_key = serialization.load_pem_public_key(pem, backend=default_backend()) @@ -96,10 +103,10 @@ def rsa_encrypt(data, pem, b64_encode=True): mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) if b64_encode: - encrypted_data = base64.b64encode(encrypted_data).decode('utf-8') + encrypted_data = base64.b64encode(encrypted_data).decode("utf-8") return encrypted_data @@ -118,13 +125,15 @@ def rsa_decrypt(encrypted_data, pem, password=None): encrypted_data = to_binary(encrypted_data) pem = to_binary(pem) - private_key = serialization.load_pem_private_key(pem, password, backend=default_backend()) + private_key = serialization.load_pem_private_key( + pem, password, backend=default_backend() + ) data = private_key.decrypt( encrypted_data, padding=padding.OAEP( mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) return data diff --git a/chapter12/booking_system/exts/wechatpy/replies.py b/chapter12/booking_system/exts/wechatpy/replies.py index 9a48d71..3365edc 100644 --- a/chapter12/booking_system/exts/wechatpy/replies.py +++ b/chapter12/booking_system/exts/wechatpy/replies.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.replies - ~~~~~~~~~~~~~~~~~~ - This module defines all kinds of replies you can send to WeChat +wechatpy.replies +~~~~~~~~~~~~~~~~~~ +This module defines all kinds of replies you can send to WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -34,28 +34,30 @@ def register_reply(reply_type): def register(cls): REPLY_TYPES[reply_type] = cls return cls + return register class BaseReply(six.with_metaclass(MessageMetaClass)): """Base class for all replies""" - source = StringField('FromUserName') - target = StringField('ToUserName') - time = IntegerField('CreateTime', time.time()) - type = 'unknown' + + source = StringField("FromUserName") + target = StringField("ToUserName") + time = IntegerField("CreateTime", time.time()) + type = "unknown" def __init__(self, **kwargs): self._data = {} - message = kwargs.pop('message', None) + message = kwargs.pop("message", None) if message and isinstance(message, BaseMessage): - if 'source' not in kwargs: - kwargs['source'] = message.target - if 'target' not in kwargs: - kwargs['target'] = message.source - if hasattr(message, 'agent') and 'agent' not in kwargs: - kwargs['agent'] = message.agent - if 'time' not in kwargs: - kwargs['time'] = time.time() + if "source" not in kwargs: + kwargs["source"] = message.target + if "target" not in kwargs: + kwargs["target"] = message.source + if hasattr(message, "agent") and "agent" not in kwargs: + kwargs["agent"] = message.agent + if "time" not in kwargs: + kwargs["time"] = time.time() for name, value in kwargs.items(): field = self._fields.get(name) if field: @@ -65,9 +67,9 @@ def __init__(self, **kwargs): def render(self): """Render reply from Python object to XML string""" - tpl = '\n{data}\n' + tpl = "\n{data}\n" nodes = [] - msg_type = ''.format( + msg_type = "".format( msg_type=self.type ) nodes.append(msg_type) @@ -75,7 +77,7 @@ def render(self): value = getattr(self, name, field.default) node_xml = field.to_xml(value) nodes.append(node_xml) - data = '\n'.join(nodes) + data = "\n".join(nodes) return tpl.format(data=data) def __str__(self): @@ -85,39 +87,42 @@ def __str__(self): return to_text(self.render()) -@register_reply('empty') +@register_reply("empty") class EmptyReply(BaseReply): """ 回复空串 微信服务器不会对此作任何处理,并且不会发起重试 """ + def __init__(self): pass def render(self): - return '' + return "" -@register_reply('text') +@register_reply("text") class TextReply(BaseReply): """ 文本回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_reply('image') + +@register_reply("image") class ImageReply(BaseReply): """ 图片回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'image' - image = ImageField('Image') + + type = "image" + image = ImageField("Image") @property def media_id(self): @@ -128,15 +133,16 @@ def media_id(self, value): self.image = value -@register_reply('voice') +@register_reply("voice") class VoiceReply(BaseReply): """ 语音回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'voice' - voice = VoiceField('Voice') + + type = "voice" + voice = VoiceField("Voice") @property def media_id(self): @@ -147,169 +153,174 @@ def media_id(self, value): self.voice = value -@register_reply('video') +@register_reply("video") class VideoReply(BaseReply): """ 视频回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'video' - video = VideoField('Video', {}) + + type = "video" + video = VideoField("Video", {}) @property def media_id(self): - return self.video.get('media_id') + return self.video.get("media_id") @media_id.setter def media_id(self, value): video = self.video - video['media_id'] = value + video["media_id"] = value self.video = video @property def title(self): - return self.video.get('title') + return self.video.get("title") @title.setter def title(self, value): video = self.video - video['title'] = value + video["title"] = value self.video = video @property def description(self): - return self.video.get('description') + return self.video.get("description") @description.setter def description(self, value): video = self.video - video['description'] = value + video["description"] = value self.video = video -@register_reply('music') +@register_reply("music") class MusicReply(BaseReply): """ 音乐回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'music' - music = MusicField('Music', {}) + + type = "music" + music = MusicField("Music", {}) @property def thumb_media_id(self): - return self.music.get('thumb_media_id') + return self.music.get("thumb_media_id") @thumb_media_id.setter def thumb_media_id(self, value): music = self.music - music['thumb_media_id'] = value + music["thumb_media_id"] = value self.music = music @property def title(self): - return self.music.get('title') + return self.music.get("title") @title.setter def title(self, value): music = self.music - music['title'] = value + music["title"] = value self.music = music @property def description(self): - return self.music.get('description') + return self.music.get("description") @description.setter def description(self, value): music = self.music - music['description'] = value + music["description"] = value self.music = music @property def music_url(self): - return self.music.get('music_url') + return self.music.get("music_url") @music_url.setter def music_url(self, value): music = self.music - music['music_url'] = value + music["music_url"] = value self.music = music @property def hq_music_url(self): - return self.music.get('hq_music_url') + return self.music.get("hq_music_url") @hq_music_url.setter def hq_music_url(self, value): music = self.music - music['hq_music_url'] = value + music["hq_music_url"] = value self.music = music -@register_reply('news') +@register_reply("news") class ArticlesReply(BaseReply): """ 图文回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'news' - articles = ArticlesField('Articles', []) + + type = "news" + articles = ArticlesField("Articles", []) def add_article(self, article): if len(self.articles) == 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) articles = self.articles articles.append(article) self.articles = articles -@register_reply('transfer_customer_service') +@register_reply("transfer_customer_service") class TransferCustomerServiceReply(BaseReply): """ 将消息转发到多客服 详情请参阅 http://mp.weixin.qq.com/wiki/5/ae230189c9bd07a6b221f48619aeef35.html """ - type = 'transfer_customer_service' + type = "transfer_customer_service" -@register_reply('device_text') + +@register_reply("device_text") class DeviceTextReply(BaseReply): - type = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_event') +@register_reply("device_event") class DeviceEventReply(BaseReply): - type = 'device_event' - event = StringField('Event') - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_event" + event = StringField("Event") + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_status') +@register_reply("device_status") class DeviceStatusReply(BaseReply): - type = 'device_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - status = IntegerField('DeviceStatus') + type = "device_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + status = IntegerField("DeviceStatus") -@register_reply('hardware') +@register_reply("hardware") class HardwareReply(BaseReply): - type = 'hardware' - func_flag = IntegerField('FuncFlag', 0) - hardware = HardwareField('HardWare') + type = "hardware" + func_flag = IntegerField("FuncFlag", 0) + hardware = HardwareField("HardWare") def create_reply(reply, message=None, render=False): @@ -325,18 +336,13 @@ def create_reply(reply, message=None, render=False): r.source = message.target r.target = message.source elif isinstance(reply, six.string_types): - r = TextReply( - message=message, - content=reply - ) + r = TextReply(message=message, content=reply) elif isinstance(reply, (tuple, list)): if len(reply) > 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") - r = ArticlesReply( - message=message, - articles=reply - ) + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) + r = ArticlesReply(message=message, articles=reply) if r and render: return r.render() return r diff --git a/chapter12/booking_system/exts/wechatpy/session/memcachedstorage.py b/chapter12/booking_system/exts/wechatpy/session/memcachedstorage.py index e9d7b33..15bd06d 100644 --- a/chapter12/booking_system/exts/wechatpy/session/memcachedstorage.py +++ b/chapter12/booking_system/exts/wechatpy/session/memcachedstorage.py @@ -8,14 +8,14 @@ class MemcachedStorage(SessionStorage): - def __init__(self, mc, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, mc, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(mc, method_name) self.mc = mc self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter12/booking_system/exts/wechatpy/session/redisstorage.py b/chapter12/booking_system/exts/wechatpy/session/redisstorage.py index 7412929..c931e64 100644 --- a/chapter12/booking_system/exts/wechatpy/session/redisstorage.py +++ b/chapter12/booking_system/exts/wechatpy/session/redisstorage.py @@ -7,14 +7,14 @@ class RedisStorage(SessionStorage): - def __init__(self, redis, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, redis, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(redis, method_name) self.redis = redis self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter12/booking_system/exts/wechatpy/session/shovestorage.py b/chapter12/booking_system/exts/wechatpy/session/shovestorage.py index 2e0ffbf..1efda82 100644 --- a/chapter12/booking_system/exts/wechatpy/session/shovestorage.py +++ b/chapter12/booking_system/exts/wechatpy/session/shovestorage.py @@ -5,12 +5,12 @@ class ShoveStorage(SessionStorage): - def __init__(self, shove, prefix='wechatpy'): + def __init__(self, shove, prefix="wechatpy"): self.shove = shove self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter12/booking_system/exts/wechatpy/utils.py b/chapter12/booking_system/exts/wechatpy/utils.py index 74480ed..ee02ada 100644 --- a/chapter12/booking_system/exts/wechatpy/utils.py +++ b/chapter12/booking_system/exts/wechatpy/utils.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.utils - ~~~~~~~~~~~~~~~ +wechatpy.utils +~~~~~~~~~~~~~~~ - This module provides some useful utilities. +This module provides some useful utilities. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import string @@ -14,7 +14,7 @@ import hashlib try: - '''Use simplejson if we can, fallback to json otherwise.''' + """Use simplejson if we can, fallback to json otherwise.""" import simplejson as json except ImportError: import json # NOQA @@ -24,8 +24,7 @@ class ObjectDict(dict): - """Makes a dictionary behave like an object, with attribute-style access. - """ + """Makes a dictionary behave like an object, with attribute-style access.""" def __getattr__(self, key): if key in self: @@ -39,7 +38,7 @@ def __setattr__(self, key, value): class WeChatSigner(object): """WeChat data signer""" - def __init__(self, delimiter=b''): + def __init__(self, delimiter=b""): self._data = [] self._delimiter = to_binary(delimiter) @@ -73,14 +72,14 @@ def check_signature(token, signature, timestamp, nonce): raise InvalidSignatureException() -def to_text(value, encoding='utf-8'): +def to_text(value, encoding="utf-8"): """Convert value to unicode, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return '' + return "" if isinstance(value, six.text_type): return value if isinstance(value, six.binary_type): @@ -88,14 +87,14 @@ def to_text(value, encoding='utf-8'): return six.text_type(value) -def to_binary(value, encoding='utf-8'): +def to_binary(value, encoding="utf-8"): """Convert value to binary string, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return b'' + return b"" if isinstance(value, six.binary_type): return value if isinstance(value, six.text_type): @@ -111,11 +110,13 @@ def timezone(zone): """ try: import pytz + return pytz.timezone(zone) except ImportError: pass try: from dateutil.tz import gettz + return gettz(zone) except ImportError: return None @@ -124,7 +125,7 @@ def timezone(zone): def random_string(length=16): rule = string.ascii_letters + string.digits rand_list = random.sample(rule, length) - return ''.join(rand_list) + return "".join(rand_list) def get_querystring(uri): diff --git a/chapter12/booking_system/main.py b/chapter12/booking_system/main.py index ec3f1e1..b0c5d55 100644 --- a/chapter12/booking_system/main.py +++ b/chapter12/booking_system/main.py @@ -1,12 +1,14 @@ from app import creat_app -app =creat_app() + +app = creat_app() if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) # tree -I "node_modules|cache|test_*" -# tree -I "__pycache__" \ No newline at end of file +# tree -I "__pycache__" diff --git a/chapter12/booking_system/middlewares/loger/middleware.py b/chapter12/booking_system/middlewares/loger/middleware.py index dca0ac5..e74aaef 100644 --- a/chapter12/booking_system/middlewares/loger/middleware.py +++ b/chapter12/booking_system/middlewares/loger/middleware.py @@ -15,87 +15,107 @@ request: Request = bind_contextvar(request_var) - - def setup_ext_loguru(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(log_file_path, format=format2, rotation='00:00', encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file - + logger.add( + log_file_path, + format=format2, + rotation="00:00", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, - + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str(getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) class LogerMiddleware: def __init__( - self, - *, - app: ASGIApp, - log_pro_path: str, - is_record_useragent=False, - is_record_headers=False, - nesss_access_heads_keys=[], - ignore_url: typing.List = ['/favicon.ico', 'websocket'], + self, + *, + app: ASGIApp, + log_pro_path: str, + is_record_useragent=False, + is_record_headers=False, + nesss_access_heads_keys=[], + ignore_url: typing.List = ["/favicon.ico", "websocket"], ) -> None: self.app = app self.is_record_useragent = is_record_useragent @@ -105,11 +125,11 @@ def __init__( setup_ext_loguru(log_pro_path) def make_traceid(self, request) -> None: - ''' + """ 生成追踪链路ID :param request: :return: - ''' + """ request.state.traceid = shortuuid.uuid() # 追踪索引序号 request.state.trace_links_index = 0 @@ -119,36 +139,35 @@ def make_traceid(self, request) -> None: request.state.start_time = perf_counter() def make_token_request(self, request): - ''' + """ 生成当前请求上下文对象request :param request: :return: - ''' + """ return request_var.set(request) def reset_token_request(self, token_request): - ''' + """ 重置当前请求上下文对象request :param request: :return: - ''' + """ request_var.reset(token_request) - async def get_request_body(self, request) -> typing.AnyStr: body = None try: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass request.state.body = body @@ -189,77 +208,102 @@ async def make_request_log_msg(self, request) -> typing.Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") except: log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, - 'url': url, - 'method': method, - 'ip': ip, - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), + "url": url, + "method": method, + "ip": ip, + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - print('log_msg', log_msg) + print("log_msg", log_msg) # 对于没有的数据清除 - if 'headers' in log_msg and not log_msg['headers']: - log_msg.pop('headers') - if log_msg['params']: - if 'query_params' in log_msg['params'] and not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - print(log_msg['params']) - if 'from' in log_msg['params'] and not log_msg['params']['from']: - log_msg['params'].pop('from') - if 'body' in log_msg['params'] and not log_msg['params']['body']: - log_msg['params'].pop('body') + if "headers" in log_msg and not log_msg["headers"]: + log_msg.pop("headers") + if log_msg["params"]: + if ( + "query_params" in log_msg["params"] + and not log_msg["params"]["query_params"] + ): + log_msg["params"].pop("query_params") + print(log_msg["params"]) + if "from" in log_msg["params"] and not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if "body" in log_msg["params"] and not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] != "http": # pragma: no cover await self.app(scope, receive, send) @@ -284,9 +328,9 @@ async def receive(): # 生成日志记录 log_msg = await self.make_request_log_msg(request) # 开始写日志信息到文件中 - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) try: response = await self.app(scope, receive, send) return response finally: - self.reset_token_request(token_request) + self.reset_token_request(token_request) diff --git a/chapter12/booking_system/order_consumer.py b/chapter12/booking_system/order_consumer.py index d417a2f..88d332f 100644 --- a/chapter12/booking_system/order_consumer.py +++ b/chapter12/booking_system/order_consumer.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/10/19 ------------------------------------------------- - 修改描述-2021/10/19: + 修改描述-2021/10/19: ------------------------------------------------- """ import pika @@ -21,24 +21,33 @@ credentials = pika.PlainCredentials("guest", "guest") # 创建连接http://47.99.189.42:30100/ connection = pika.BlockingConnection( - pika.ConnectionParameters(host='localhost', port=5672, virtual_host='yuyueguahao', credentials=credentials)) + pika.ConnectionParameters( + host="localhost", port=5672, virtual_host="yuyueguahao", credentials=credentials + ) +) # 通过连接创建信道 channel = connection.channel() # 通过信道创建我们的队列 其中名称是task_queue,并且这个队列的消息是需要持久化的!PS:持久化存储存到磁盘会占空间, # 队列不能由持久化变为普通队列,反过来也是!否则会报错!所以队列类型创建的开始必须确定的! -order_dead_letter_exchange_name = 'xz-dead-letter-exchange' -order_dead_letter_exchange_type = 'fanout' -order_dead_letter_queue_name = 'xz-dead-letter-queue' -order_dead_letter_routing_key = 'xz-dead-letter-queue' +order_dead_letter_exchange_name = "xz-dead-letter-exchange" +order_dead_letter_exchange_type = "fanout" +order_dead_letter_queue_name = "xz-dead-letter-queue" +order_dead_letter_routing_key = "xz-dead-letter-queue" # 相对比只要交换机名称即可接收到消息的广播模式(fanout),direct模式在其基础上,多加了一层密码限制(routingKey) -channel.exchange_declare(exchange=order_dead_letter_exchange_name, durable=True, - exchange_type=order_dead_letter_exchange_type) +channel.exchange_declare( + exchange=order_dead_letter_exchange_name, + durable=True, + exchange_type=order_dead_letter_exchange_type, +) channel.queue_declare(queue=order_dead_letter_queue_name, durable=True) -channel.queue_bind(exchange=order_dead_letter_exchange_name, queue=order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) +channel.queue_bind( + exchange=order_dead_letter_exchange_name, + queue=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, +) -print(' [*] 死信队列里面的死信消息的消费. To exit press CTRL+C') +print(" [*] 死信队列里面的死信消息的消费. To exit press CTRL+C") # 初始化数据库的链接处理 @@ -50,11 +59,17 @@ def callback(ch, method, properties, body): # 获取当前的订单支付状态信息,如果当前处于没支付的状态的话,则需要回滚我们的库存 with sync_context_get_db() as session: - _result = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'), - DoctorSubscribeinfo.visit_uopenid == mesgg.get( - 'visit_uopenid'), - DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).one_or_none() + _result = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.visit_uopenid == mesgg.get("visit_uopenid"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ) + .one_or_none() + ) if _result: @@ -65,9 +80,12 @@ def callback(ch, method, properties, body): pass # 更新订单状态 print("更新状态!!!!!!!!!!!!!") - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'),DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).update({DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) elif _result.statue == 3: pass elif _result.statue == 5: @@ -84,7 +102,7 @@ def callback(ch, method, properties, body): channel.basic_qos(prefetch_count=1) # await channel.set_qos(prefetch_count=1) # 开始进行订阅消费 -ack = channel.basic_consume(queue='xz-dead-letter-queue', on_message_callback=callback) -print('s', ack) +ack = channel.basic_consume(queue="xz-dead-letter-queue", on_message_callback=callback) +print("s", ack) # 消费者会阻塞在这里,一直等待消息,队列中有消息了,就会执行消息的回调函数 channel.start_consuming() diff --git a/chapter12/booking_system/plugins/base.py b/chapter12/booking_system/plugins/base.py index 847db87..72827ca 100644 --- a/chapter12/booking_system/plugins/base.py +++ b/chapter12/booking_system/plugins/base.py @@ -3,12 +3,21 @@ import typing import abc + class PluginBase(abc.ABC): - def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): + def __init__( + self, app: fastapi.FastAPI = None, config: pydantic.BaseSettings = None + ): if app is not None: self.init_app(app) @abc.abstractmethod - def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: - raise NotImplementedError('需要实现初始化') + def init_app( + self, + app: fastapi.FastAPI, + config: pydantic.BaseSettings = None, + *args, + **kwargs + ) -> None: + raise NotImplementedError("需要实现初始化") diff --git a/chapter12/booking_system/plugins/request_hook.py b/chapter12/booking_system/plugins/request_hook.py index 5cc23e7..c43f5ee 100644 --- a/chapter12/booking_system/plugins/request_hook.py +++ b/chapter12/booking_system/plugins/request_hook.py @@ -1,4 +1,3 @@ - from plugins.base import PluginBase from fastapi import FastAPI from pydantic import BaseSettings @@ -10,15 +9,24 @@ class HookPluginClient(PluginBase): # 设置插件默认的参数信息 - def __init__(self, - on_before_request: typing.Sequence[typing.Callable] = None, - on_after_request: typing.Sequence[typing.Callable] = None, - on_teardown_appcontext: typing.Sequence[typing.Callable] = None, - *args, **kwargs): + def __init__( + self, + on_before_request: typing.Sequence[typing.Callable] = None, + on_after_request: typing.Sequence[typing.Callable] = None, + on_teardown_appcontext: typing.Sequence[typing.Callable] = None, + *args, + **kwargs + ): super().__init__(*args, **kwargs) - self.on_before_request = [] if on_before_request is None else list(on_before_request) - self.on_after_request = [] if on_after_request is None else list(on_after_request) - self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + self.on_before_request = ( + [] if on_before_request is None else list(on_before_request) + ) + self.on_after_request = ( + [] if on_after_request is None else list(on_after_request) + ) + self.on_teardown_appcontext = ( + [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + ) def init_app(self, app: FastAPI, *args, **kwargs): pass @@ -50,6 +58,7 @@ def on_event(self, event_type: str) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_event_handler(event_type, func) return func + return decorator async def before_request(self, request) -> None: @@ -72,4 +81,4 @@ async def teardown_appcontext(self, request, response) -> None: if asyncio.iscoroutinefunction(handler): await handler(request, response) else: - handler(request, response) \ No newline at end of file + handler(request, response) diff --git a/chapter12/booking_system/utils/cast_helper.py b/chapter12/booking_system/utils/cast_helper.py index c0803c1..4693ad3 100644 --- a/chapter12/booking_system/utils/cast_helper.py +++ b/chapter12/booking_system/utils/cast_helper.py @@ -1,2 +1,2 @@ -def add(a,b): - return a+b; \ No newline at end of file +def add(a, b): + return a + b diff --git a/chapter12/booking_system/utils/datatime_helper.py b/chapter12/booking_system/utils/datatime_helper.py index ab77882..c6e1e6c 100644 --- a/chapter12/booking_system/utils/datatime_helper.py +++ b/chapter12/booking_system/utils/datatime_helper.py @@ -5,48 +5,58 @@ def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False return True - def get_timestamp10(): """获取当前时间长度为10位长度的时间戳""" return int(time.time()) def str_to_datatime(srr_time, strftime="%Y-%m-%d"): - print('strftimestrftimestrftime',strftime) + print("strftimestrftimestrftime", strftime) return datetime.datetime.strptime(srr_time, strftime) -str_to_datatime('2021-12-27 10:00:00',strftime='%Y-%m-%d %H:%M:%S') + +str_to_datatime("2021-12-27 10:00:00", strftime="%Y-%m-%d %H:%M:%S") + def datatime_to_str(data_time: datetime.datetime, strftime="%Y-%m-%d"): return data_time.strftime(strftime) def diff_days_for_now_time(srr_time): - ''' + """ 对比当前的传入日期和当前系统时间的相差的天数 :param srr_time: :return: - ''' - return (datetime.datetime.strptime(srr_time, "%Y-%m-%d") - datetime.datetime.combine(datetime.datetime.now().date(), - datetime.time())).days + """ + return ( + datetime.datetime.strptime(srr_time, "%Y-%m-%d") + - datetime.datetime.combine(datetime.datetime.now().date(), datetime.time()) + ).days # 获取当前日期 # today=time.strftime('%Y-%m-%d',time.localtime(time.time())) + def currday_time_info(): - return time.strftime('%Y-%m-%d', time.localtime(time.time())) + return time.strftime("%Y-%m-%d", time.localtime(time.time())) def currday_time_info_tochane_datetime(today): @@ -55,11 +65,17 @@ def currday_time_info_tochane_datetime(today): def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False @@ -68,9 +84,9 @@ def effectiveness_tiempm(tiempm): # 根据给定的日期,获取前n天或后n天的日期,n为正数则是以后的n天,n为负数则是以前的n天,不包括当天 def get_day_of_day(str2date, n=0): - if (n < 0): + if n < 0: n = abs(n) - return (str2date - timedelta(days=n)) + return str2date - timedelta(days=n) else: return str2date + timedelta(days=n) @@ -83,7 +99,7 @@ def num_to_string(num): 3: "周三", 4: "周四", 5: "周五", - 6: "周六" + 6: "周六", } return numbers.get(num, None) @@ -93,9 +109,9 @@ def get_7day_info_list(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = { - 'weekday': num_to_string(datatime.isoweekday()), - 'datetimeday': datatime.strftime('%Y-%m-%d') + ditcs[datatime.strftime("%Y-%m-%d")] = { + "weekday": num_to_string(datatime.isoweekday()), + "datetimeday": datatime.strftime("%Y-%m-%d"), } return ditcs @@ -105,6 +121,5 @@ def get_7day_info_list_only_data(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = {} + ditcs[datatime.strftime("%Y-%m-%d")] = {} return ditcs - diff --git a/chapter12/booking_system/utils/json_helper.py b/chapter12/booking_system/utils/json_helper.py index f8a3fd2..6a1de21 100644 --- a/chapter12/booking_system/utils/json_helper.py +++ b/chapter12/booking_system/utils/json_helper.py @@ -8,16 +8,16 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) if isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") if isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") if isinstance(obj, decimal.Decimal): return float(obj) if isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") return json.JSONEncoder.default(self, obj) @@ -61,7 +61,7 @@ def class_to_dict(obj): else: dict = {} dict.update(obj.__dict__) - return dict.get('__data__') + return dict.get("__data__") import base64 @@ -125,4 +125,4 @@ def dumps( default=default, sort_keys=sort_keys, **kw - ) \ No newline at end of file + ) diff --git a/chapter12/booking_system/utils/ordernum_helper.py b/chapter12/booking_system/utils/ordernum_helper.py index 6723543..80ec95c 100644 --- a/chapter12/booking_system/utils/ordernum_helper.py +++ b/chapter12/booking_system/utils/ordernum_helper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -37,27 +37,42 @@ def order_num_1(package_id=12345, user_num=56789): # 商品id后1位+下单时间的年月日12+用户2后四位+随机数3位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(100, 999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(100, 999)) + ) return result def order_num_2(package_id=12345, user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(1000, 9999)) + ) return result def order_num_3(user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =f'{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}' + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = f"{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}" return result -def order_num_srt(user_num='56789'): +def order_num_srt(user_num="56789"): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =str(user_num)[-2:] + str(random.randint(100, 999)) + local_time + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(user_num)[-2:] + + str(random.randint(100, 999)) + + local_time + + str(random.randint(1000, 9999)) + ) return result diff --git a/chapter12/booking_system/utils/run_with_asyncio.py b/chapter12/booking_system/utils/run_with_asyncio.py index 0d845ba..edf6416 100644 --- a/chapter12/booking_system/utils/run_with_asyncio.py +++ b/chapter12/booking_system/utils/run_with_asyncio.py @@ -2,11 +2,15 @@ import asyncio from functools import wraps from typing import Any, Awaitable, Callable, TypeVar + T = TypeVar("T") __all__ = ["run_with_asyncio"] + + def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> T: print("pajinlail") return asyncio.run(f(*args, **kwargs)) - return wrapper \ No newline at end of file + + return wrapper diff --git a/chapter12/booking_system/utils/xmlhelper.py b/chapter12/booking_system/utils/xmlhelper.py index a831fd9..883bb15 100644 --- a/chapter12/booking_system/utils/xmlhelper.py +++ b/chapter12/booking_system/utils/xmlhelper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -43,10 +43,16 @@ def parse_xml_data(xml): except (xmltodict.ParsingInterrupted, ExpatError): raise Exception() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise Exception() - data = data['xml'] - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + data = data["xml"] + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) return data diff --git a/chapter13/booking_system/apis/doctor/api/__init__.py b/chapter13/booking_system/apis/doctor/api/__init__.py index 3159d25..61c5882 100644 --- a/chapter13/booking_system/apis/doctor/api/__init__.py +++ b/chapter13/booking_system/apis/doctor/api/__init__.py @@ -1,3 +1,6 @@ from fastapi import APIRouter -router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) -from ..api import doctor_api \ No newline at end of file + +router_docrot = APIRouter( + prefix="/api/v1", tags=["医生信息模块"], include_in_schema=True +) +from ..api import doctor_api diff --git a/chapter13/booking_system/apis/doctor/api/doctor_api.py b/chapter13/booking_system/apis/doctor/api/doctor_api.py index c3993ed..ae96995 100644 --- a/chapter13/booking_system/apis/doctor/api/doctor_api.py +++ b/chapter13/booking_system/apis/doctor/api/doctor_api.py @@ -8,19 +8,22 @@ from utils.datatime_helper import diff_days_for_now_time -@router_docrot.get("/doctor_list", summary='获取可以预约医生列表信息') +@router_docrot.get("/doctor_list", summary="获取可以预约医生列表信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): - ''' + """ 获取可以预约医生列表信息\n\n :param db_session: 数据库连接依赖注入对象\n\n :return: 返回可以预约医生列表信息\n\n - ''' + """ info = await DoctorServeries.get_doctor_list_infos(db_session) return Success(result=info) -@router_docrot.get("/doctor_scheduling_info", summary='获取医生排班信息') -async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = Depends(depends_get_db_session)): +@router_docrot.get("/doctor_scheduling_info", summary="获取医生排班信息") +async def callbadk( + forms: SchedulingInfo = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), +): # 当前系统日期对比,判断当前是否是否已操作系统时间,超过系统时间预约信息则无法查询 if forms.start_time: try: @@ -30,25 +33,26 @@ async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = except: return Fail(message="当前日期无效,日期格式错误!") # 查询排班信息 - doctor_result, doctor_scheduling_result = await DoctorServeries.get_doctor_scheduling_info(db_session, - dno=forms.dno, - start_time=forms.start_time) + doctor_result, doctor_scheduling_result = ( + await DoctorServeries.get_doctor_scheduling_info( + db_session, dno=forms.dno, start_time=forms.start_time + ) + ) scheduling_info = {} for item in doctor_scheduling_result: - if item.ampm == 'am': - if 'am' not in scheduling_info: - scheduling_info['am'] = [] - scheduling_info['am'].append(item) + if item.ampm == "am": + if "am" not in scheduling_info: + scheduling_info["am"] = [] + scheduling_info["am"].append(item) else: - scheduling_info['am'].append(item) - if item.ampm == 'pm': - if 'pm' not in scheduling_info: - scheduling_info['pm'] = [] - scheduling_info['pm'].append(item) + scheduling_info["am"].append(item) + if item.ampm == "pm": + if "pm" not in scheduling_info: + scheduling_info["pm"] = [] + scheduling_info["pm"].append(item) else: - scheduling_info['pm'].append(item) - backinfo = { - 'doctor': doctor_result, - 'scheduling_info': scheduling_info - } - return Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + scheduling_info["pm"].append(item) + backinfo = {"doctor": doctor_result, "scheduling_info": scheduling_info} + return ( + Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + ) diff --git a/chapter13/booking_system/apis/doctor/repository/__init__.py b/chapter13/booking_system/apis/doctor/repository/__init__.py index b0f4153..2753d20 100644 --- a/chapter13/booking_system/apis/doctor/repository/__init__.py +++ b/chapter13/booking_system/apis/doctor/repository/__init__.py @@ -1,6 +1,6 @@ from sqlalchemy import select, update, delete from sqlalchemy.ext.asyncio import AsyncSession -from db.models import Doctorinfo, DoctorScheduling,DoctorSubscribeinfo +from db.models import Doctorinfo, DoctorScheduling, DoctorSubscribeinfo from typing import Optional from utils.datatime_helper import str_to_datatime, datatime_to_str, datetime @@ -13,73 +13,118 @@ async def get_doctor_list_infos(async_session: AsyncSession, enable: int = 1): # query =select(Doctor).with_only_columns(Doctor.dno,Doctor.dnname,Doctor.fee,Doctor.pic,Doctor.rank) # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.fee, Doctorinfo.pic, Doctorinfo.rank) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.fee, + Doctorinfo.pic, + Doctorinfo.rank, + ) _result = await async_session.execute(query.where(Doctorinfo.enable == enable)) # 调用.scalars()这样会返回的是标量值,不是ROW== return _result.all() @staticmethod - async def get_doctor_scheduling_info(async_session: AsyncSession, dno, enable: int = 1, start_time=None): - ''' + async def get_doctor_scheduling_info( + async_session: AsyncSession, dno, enable: int = 1, start_time=None + ): + """ 返回预约医生的排班信息 :param async_session: :param enable: :param start_time: 当前医生的排班时间起点 默认查询当天的时间排班 :param end_time: 当前医生的排班截止时间点 默认查询当天的时间排班 :return: - ''' + """ # 获取排班信息 # 查询出当前医生的信息 - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.destag, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.describe) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.destag, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.describe, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_scheduling_result = [] if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.nsnum, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.tiempm, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.nsnum, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.tiempm, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno) + query = query.where( + DoctorScheduling.enable == enable, DoctorScheduling.dno == dno + ) if start_time: # 格式化时间处理 start_time = str_to_datatime(start_time) - end_time = str_to_datatime(datatime_to_str((start_time + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str((start_time + datetime.timedelta(days=1))) + ) else: # 格式化时间处理 start_time = str_to_datatime(datatime_to_str(datetime.datetime.now())) - end_time = str_to_datatime(datatime_to_str((datetime.datetime.now() + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str( + (datetime.datetime.now() + datetime.timedelta(days=1)) + ) + ) - - query = query.where(DoctorScheduling.dnotime >= start_time, DoctorScheduling.dnotime < end_time) + query = query.where( + DoctorScheduling.dnotime >= start_time, + DoctorScheduling.dnotime < end_time, + ) _result = await async_session.execute(query) doctor_scheduling_result = _result.all() return doctor_result, doctor_scheduling_result @staticmethod - async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, dno, nsindex, enable: int = 1): - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.addr,Doctorinfo.fee) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + async def get_doctor_curr_nsindex_scheduling_info( + async_session: AsyncSession, dno, nsindex, enable: int = 1 + ): + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.addr, + Doctorinfo.fee, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_nsnuminfo_result: Optional[DoctorScheduling] = None if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.nsnum, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiempm, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.nsnum, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiempm, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno, - DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.enable == enable, + DoctorScheduling.dno == dno, + DoctorScheduling.nsindex == nsindex, + ) _result = await async_session.execute(query) doctor_nsnuminfo_result = _result.first() @@ -87,11 +132,19 @@ async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, d return doctor_result, doctor_nsnuminfo_result @staticmethod - async def updata_nusnum_info_dno(async_session: AsyncSession, dno, nsindex,isup=True): - response = update(DoctorSubscribeinfo).where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + async def updata_nusnum_info_dno( + async_session: AsyncSession, dno, nsindex, isup=True + ): + response = update(DoctorSubscribeinfo).where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) if isup: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum + 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum + 1) + ) else: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum - 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum - 1) + ) await async_session.commit() return result.rowcount diff --git a/chapter13/booking_system/apis/hospital/api/__init__.py b/chapter13/booking_system/apis/hospital/api/__init__.py index c4f3dac..51d08b3 100644 --- a/chapter13/booking_system/apis/hospital/api/__init__.py +++ b/chapter13/booking_system/apis/hospital/api/__init__.py @@ -1,4 +1,5 @@ from fastapi import APIRouter -router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) + +router_hospital = APIRouter(prefix="/api/v1", tags=["医院信息模块"]) # 導入模塊 -from apis.hospital.api import get_hospital_info \ No newline at end of file +from apis.hospital.api import get_hospital_info diff --git a/chapter13/booking_system/apis/hospital/api/get_hospital_info.py b/chapter13/booking_system/apis/hospital/api/get_hospital_info.py index 64dd0dc..c01c2cb 100644 --- a/chapter13/booking_system/apis/hospital/api/get_hospital_info.py +++ b/chapter13/booking_system/apis/hospital/api/get_hospital_info.py @@ -6,7 +6,7 @@ from ..api import router_hospital -@router_hospital.get("/hospital_info", summary='获取医院信息') +@router_hospital.get("/hospital_info", summary="获取医院信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): info = await HospitalServeries.get_hospital_info(db_session, id=1) return Success(result=info) diff --git a/chapter13/booking_system/apis/hospital/repository/__init__.py b/chapter13/booking_system/apis/hospital/repository/__init__.py index 2c5bacd..56c2393 100644 --- a/chapter13/booking_system/apis/hospital/repository/__init__.py +++ b/chapter13/booking_system/apis/hospital/repository/__init__.py @@ -9,7 +9,10 @@ class HospitalServeries: @staticmethod async def get_hospital_info(async_session: AsyncSession, id: int): _result = await async_session.execute( - select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) + select( + Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages + ).where(Hospitalinfo.id == id) + ) scalars_result = _result.first() # scalars_result = _result.scalars().first() return scalars_result diff --git a/chapter13/booking_system/apis/payorders/api/__init__.py b/chapter13/booking_system/apis/payorders/api/__init__.py index 2b58ff6..df56d75 100644 --- a/chapter13/booking_system/apis/payorders/api/__init__.py +++ b/chapter13/booking_system/apis/payorders/api/__init__.py @@ -1,7 +1,8 @@ from fastapi import APIRouter -router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) + +router_payorders = APIRouter(prefix="/api/v1", tags=["支付订单模块"]) from apis.payorders.api import doctor_reserve_order from apis.payorders.api import payback_reserve_order from apis.payorders.api import reserve_order_info from apis.payorders.api import doctor_reserve_reorder -from apis.payorders.api import doctor_order_check \ No newline at end of file +from apis.payorders.api import doctor_order_check diff --git a/chapter13/booking_system/apis/payorders/api/doctor_order_check.py b/chapter13/booking_system/apis/payorders/api/doctor_order_check.py index c5a7c3f..b9536b5 100644 --- a/chapter13/booking_system/apis/payorders/api/doctor_order_check.py +++ b/chapter13/booking_system/apis/payorders/api/doctor_order_check.py @@ -15,19 +15,28 @@ from apis.payorders.repository import PayOrderServeries -@router_payorders.post("/doctor_order_check", summary='订单状态查询') -async def callbadk(forms: SubscribeOrderCheckForm=Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): - +@router_payorders.post("/doctor_order_check", summary="订单状态查询") +async def callbadk( + forms: SubscribeOrderCheckForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(db_session,forms.dno, - forms.visit_uopenid, - forms.orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, forms.dno, forms.visit_uopenid, forms.orderid + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") - return Success(api_code=200, result={'status': doctor_nsnum_info_result.statue}, - message='查询成功') if doctor_nsnum_info_result else Fail(api_code=200, result=None, - message='无排班记录信息,或已过有效期') + return ( + Success( + api_code=200, + result={"status": doctor_nsnum_info_result.statue}, + message="查询成功", + ) + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无排班记录信息,或已过有效期") + ) diff --git a/chapter13/booking_system/apis/payorders/api/doctor_reserve_order.py b/chapter13/booking_system/apis/payorders/api/doctor_reserve_order.py index 7d7e810..91826ec 100644 --- a/chapter13/booking_system/apis/payorders/api/doctor_reserve_order.py +++ b/chapter13/booking_system/apis/payorders/api/doctor_reserve_order.py @@ -8,60 +8,79 @@ from apis.payorders.api import router_payorders from apis.payorders.schemas import PayReserveOrderForm from utils.datatime_helper import datetime -from utils import ordernum_helper,json_helper +from utils import ordernum_helper, json_helper from exts.wechatpy.pay import WeChatPay, WeChatPayException from config.config import get_settings from apis.payorders.dependencies import get_client_ip + # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client from exts.async_rabbit import async_rabbit_client import decimal from asgiref.sync import sync_to_async -@router_payorders.post("/doctor_reserve_order", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + +@router_payorders.post( + "/doctor_reserve_order", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -72,7 +91,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -80,118 +99,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 60 * 15 - order_exchange_name = 'xz-order-exchange' - order_routing_key = 'order_handler' - sync_rabbit_client.send_basic_publish(exchange_name=order_exchange_name, routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange" + order_routing_key = "order_handler" + sync_rabbit_client.send_basic_publish( + exchange_name=order_exchange_name, + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -202,7 +258,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -210,122 +266,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async_as_tarn", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async_as_tarn", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - - - - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -336,7 +425,8 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 - pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)(trade_type='JSAPI', + pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)( + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -344,7 +434,8 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid) + out_trade_no=orderid, + ) # pay_wx_res_result = wx_pay.order.create( # trade_type='JSAPI', @@ -360,64 +451,83 @@ async def callbadk(forms: PayReserveOrderForm, pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter13/booking_system/apis/payorders/api/doctor_reserve_reorder.py b/chapter13/booking_system/apis/payorders/api/doctor_reserve_reorder.py index 2df8b1f..b098b40 100644 --- a/chapter13/booking_system/apis/payorders/api/doctor_reserve_reorder.py +++ b/chapter13/booking_system/apis/payorders/api/doctor_reserve_reorder.py @@ -12,70 +12,96 @@ import decimal -@router_payorders.get("/doctor_reserve_order", summary='未支付订单重新发起支付') -async def callbadk(forms: PayCancelPayOrderForm = Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): +@router_payorders.get("/doctor_reserve_order", summary="未支付订单重新发起支付") +async def callbadk( + forms: PayCancelPayOrderForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 获取预约详情信息列表 - doctor_order_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_order_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) print(doctor_order_info_result.dno) # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) # 先查询出上次下单的记录到的信息 if not doctor_order_info_result: - return Fail(api_code=200, result=None, message='无此订单记录信息!') + return Fail(api_code=200, result=None, message="无此订单记录信息!") if doctor_order_info_result.statue == 4: - return Fail(api_code=200, result=None, message='订单已超时未支付!建议取消重新下单!') + return Fail( + api_code=200, result=None, message="订单已超时未支付!建议取消重新下单!" + ) # 对订单信息进行校验,只有未付款的清单信息才可以继续下一步的支付的操作 if doctor_order_info_result.statue != 1: - return Fail(api_code=200, result=None, message='订单信息状态异常信息!无法继续支付!建议取消重新下单!') + return Fail( + api_code=200, + result=None, + message="订单信息状态异常信息!无法继续支付!建议取消重新下单!", + ) # 查询当前预约时段 nsindex = doctor_order_info_result.nsindex # 查询排班信息 - doctor_nsnum_info_result = await PayOrderServeries.get_doctor_scheduling_info_info_order(db_session, dno=forms.dno, - nsindex=nsindex) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_doctor_scheduling_info_info_order( + db_session, dno=forms.dno, nsindex=nsindex + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='无排班记录信息!') + return Fail(api_code=200, result=None, message="无排班记录信息!") # 对比当前的预约时段是否有效 - print('doctor_nsnum_info_result.tiempm', doctor_nsnum_info_result.tiempm) + print("doctor_nsnum_info_result.tiempm", doctor_nsnum_info_result.tiempm) if not datatime_helper.effectiveness_tiempm(str(doctor_nsnum_info_result.tiempm)): - return Fail(api_code=200, result=None, message='当前预约时段无效!请更换另一个时段进行预约!') + return Fail( + api_code=200, + result=None, + message="当前预约时段无效!请更换另一个时段进行预约!", + ) order_info = { - 'dno': forms.dno, - 'nsindex': nsindex, - 'orderid': doctor_order_info_result.orderid if doctor_order_info_result.orderid else None, - 'visit_uphone': doctor_order_info_result.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': doctor_order_info_result.visittime + "dno": forms.dno, + "nsindex": nsindex, + "orderid": ( + doctor_order_info_result.orderid + if doctor_order_info_result.orderid + else None + ), + "visit_uphone": doctor_order_info_result.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": doctor_order_info_result.visittime, } # 新手支付生成 try: - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, - mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) orderid = doctor_order_info_result.orderid order_info_json = json_helper.dict_to_json(order_info) payfee = doctor_order_info_result.payfee visittime = doctor_order_info_result.visittime # ================= - doctor_info_result = await PayOrderServeries.get_doctor_info(db_session, dno=forms.dno) + doctor_info_result = await PayOrderServeries.get_doctor_info( + db_session, dno=forms.dno + ) dnname = doctor_info_result.dnname # 解决办法:01商户订单号重复 问题 # 保证再次支付下单时发起的请求参数和第一次一样。 # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -86,7 +112,7 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), attach = f"{forms.dno}|{orderid}|{nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -94,49 +120,72 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.errmsg'] = wcpayex.errmsg - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}') + order_info["wcpayex.errmsg"] = wcpayex.errmsg + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}", + ) except Exception: import traceback + traceback.print_exc() - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(datatime_helper.get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) # 更新当前支付的订单信息 # 更新没有支付的成功的订单的,状态! - doctor_nsnum_info_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, - dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=1, - ) + doctor_nsnum_info_result = ( + await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=1, + ) + ) if doctor_nsnum_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, - message='您已提交订单,请尽快支付哟!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="您已提交订单,请尽快支付哟!", + ) else: - order_info['creat_order_info_error'] = '创建订单到数据库的时候异常' - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["creat_order_info_error"] = "创建订单到数据库的时候异常" + return Fail( + api_code=200, + result=None, + message="微信服务请求处理异常,请稍后重试!!", + ) else: # 记录请求异常回调信息 - order_info['wx_return_code'] = pay_wx_res_result.get('return_code') - order_info['wx_return_msg'] = pay_wx_res_result.get('return_msg') - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["wx_return_code"] = pay_wx_res_result.get("return_code") + order_info["wx_return_msg"] = pay_wx_res_result.get("return_msg") + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter13/booking_system/apis/payorders/api/payback_reserve_order.py b/chapter13/booking_system/apis/payorders/api/payback_reserve_order.py index 7089a56..8edef4c 100644 --- a/chapter13/booking_system/apis/payorders/api/payback_reserve_order.py +++ b/chapter13/booking_system/apis/payorders/api/payback_reserve_order.py @@ -10,60 +10,80 @@ from exts.wechatpy.client import WeChatClient - -@router_payorders.post("/payback_reserve_order", summary='支付订单回调处理') -async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_get_db_session)): - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) +@router_payorders.post("/payback_reserve_order", summary="支付订单回调处理") +async def callbadk( + request: Request, db_session: AsyncSession = Depends(depends_get_db_session) +): + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) body = await request.body() try: _result = wx_pay.parse_payment_result(body) except InvalidSignatureException as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - out_trade_no = _result.get('out_trade_no') + out_trade_no = _result.get("out_trade_no") # 微信要求的回复的模式 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="application/xml") except Exception as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") if _result: # 返回状态码信息 - return_code = _result.get('return_code') + return_code = _result.get("return_code") # 处理状态码 - if return_code != 'SUCCESS': + if return_code != "SUCCESS": # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 业务错误处理结果 - result_code = _result.get('result_code') + result_code = _result.get("result_code") # 业务支付成功处理 - if result_code == 'SUCCESS': + if result_code == "SUCCESS": pass - wx_gzx_id = _result.get('appid') - attach = _result.get('attach') - bank_type = _result.get('bank_type') - cash_fee = _result.get('cash_fee') - fee_type = _result.get('fee_type') - is_subscribe = _result.get('is_subscribe') - wx_mch_id = _result.get('mch_id') - nonce_str = _result.get('nonce_str') - openid = _result.get('openid') - out_trade_no = _result.get('out_trade_no') - time_end = _result.get('time_end') - total_fee = _result.get('total_fee') - trade_type = _result.get('trade_type') - transaction_id = _result.get('transaction_id') + wx_gzx_id = _result.get("appid") + attach = _result.get("attach") + bank_type = _result.get("bank_type") + cash_fee = _result.get("cash_fee") + fee_type = _result.get("fee_type") + is_subscribe = _result.get("is_subscribe") + wx_mch_id = _result.get("mch_id") + nonce_str = _result.get("nonce_str") + openid = _result.get("openid") + out_trade_no = _result.get("out_trade_no") + time_end = _result.get("time_end") + total_fee = _result.get("total_fee") + trade_type = _result.get("trade_type") + transaction_id = _result.get("transaction_id") # 回调透传信息 attach-在查询API和支付通知中原样返回,可作为自定义参数使用。 - #attach = f"{forms.dno}|{orderid}|{forms.nsindex}" + # attach = f"{forms.dno}|{orderid}|{forms.nsindex}" attach_info = attach.split("|") attach_dno = attach_info[0] attach_orderid = attach_info[1] @@ -71,73 +91,103 @@ async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_ attach_nsindex = attach_info[2] # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_byorder_dno_state(db_session, attach_dno, - attach_orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_byorder_dno_state( + db_session, attach_dno, attach_orderid + ) + ) if not doctor_nsnum_info_result: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 订单信息存在 # 更新支付的成功状态! # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) if doctor_nsnum_info_result.statue == 2: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") - isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, dno=attach_dno, - orderid=attach_orderid, - visit_uopenid=attach_visit_uopenid, - updata={ - 'statue': 2, - # 标记已支付,待就诊! - 'visit_statue': 1, - 'notify_callback_time': 'now()', - 'is_subscribe': is_subscribe, - } - ) + isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=attach_dno, + orderid=attach_orderid, + visit_uopenid=attach_visit_uopenid, + updata={ + "statue": 2, + # 标记已支付,待就诊! + "visit_statue": 1, + "notify_callback_time": "now()", + "is_subscribe": is_subscribe, + }, + ) # 设置具体的点击通知URL地址为,查询订单详情页信息地址 visittime = doctor_nsnum_info_result.visittime visitday = doctor_nsnum_info_result.visitday # 模板订单跳转地址详情信息 - template_url = f'http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}' + template_url = f"http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}" if isok: # 开发发送预约成功的模板通知信息 - client = WeChatClient(appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET) + client = WeChatClient( + appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET + ) # client.session = sync_redis_client - resulst = client.message.send_template(to_user_openid=attach_visit_uopenid, - template_id='XXXXXXXXXXXXXXXXXXXXXX', - url=template_url, - data={ - "first": { - "value": f"您预约挂号{visitday}{visittime}成功!", - "color": "#173177" - }, - # 科室 - "keyword2": { - "value": "中医科", - "color": "#173177" - }, - # 就诊地址 - "keyword3": { - "value": "XXXXXXXXXXXXXX中医馆", - "color": "#173177" - }, - # 备注信息 - "remark": { - "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", - "color": "#173177" - } - } - ) + resulst = client.message.send_template( + to_user_openid=attach_visit_uopenid, + template_id="XXXXXXXXXXXXXXXXXXXXXX", + url=template_url, + data={ + "first": { + "value": f"您预约挂号{visitday}{visittime}成功!", + "color": "#173177", + }, + # 科室 + "keyword2": {"value": "中医科", "color": "#173177"}, + # 就诊地址 + "keyword3": { + "value": "XXXXXXXXXXXXXX中医馆", + "color": "#173177", + }, + # 备注信息 + "remark": { + "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", + "color": "#173177", + }, + }, + ) # 响应微信支付回调处理 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") diff --git a/chapter13/booking_system/apis/payorders/api/reserve_order_info.py b/chapter13/booking_system/apis/payorders/api/reserve_order_info.py index e5f9139..2f621e0 100644 --- a/chapter13/booking_system/apis/payorders/api/reserve_order_info.py +++ b/chapter13/booking_system/apis/payorders/api/reserve_order_info.py @@ -9,13 +9,17 @@ from utils.datatime_helper import diff_days_for_now_time - -@router_payorders.post("/reserve_order_info", summary='获取预约订单信息') -async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_payorders.post("/reserve_order_info", summary="获取预约订单信息") +async def callbadk( + forms: MakeReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 查询预约信息 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_result: return Fail(message="当前医生信息不存在!") if not doctor_nsnuminfo_result: @@ -28,11 +32,15 @@ async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depen if is_limt_start_time < 0: return Fail(message="当前日期无效,无排班信息!") backresult = { - 'dnotime': str(doctor_nsnuminfo_result.dnotime), - 'dnoampm_tag': '{} {} {}'.format( + "dnotime": str(doctor_nsnuminfo_result.dnotime), + "dnoampm_tag": "{} {} {}".format( num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', - doctor_nsnuminfo_result.tiemampmstr - ) + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + doctor_nsnuminfo_result.tiemampmstr, + ), } - return Success(result={**doctor_result, **backresult}) if doctor_result else Fail(message="无当前医生排班信息") \ No newline at end of file + return ( + Success(result={**doctor_result, **backresult}) + if doctor_result + else Fail(message="无当前医生排班信息") + ) diff --git a/chapter13/booking_system/apis/payorders/dependencies/__init__.py b/chapter13/booking_system/apis/payorders/dependencies/__init__.py index 3d64412..60365ca 100644 --- a/chapter13/booking_system/apis/payorders/dependencies/__init__.py +++ b/chapter13/booking_system/apis/payorders/dependencies/__init__.py @@ -1,5 +1,6 @@ from starlette.requests import Request + def get_client_ip(request: Request): """ 获取客户端真实ip @@ -9,4 +10,4 @@ def get_client_ip(request: Request): forwarded = request.headers.get("X-Forwarded-For") if forwarded: return forwarded.split(",")[0] - return request.client.host \ No newline at end of file + return request.client.host diff --git a/chapter13/booking_system/apis/payorders/repository/__init__.py b/chapter13/booking_system/apis/payorders/repository/__init__.py index 26c9bda..f853035 100644 --- a/chapter13/booking_system/apis/payorders/repository/__init__.py +++ b/chapter13/booking_system/apis/payorders/repository/__init__.py @@ -4,78 +4,91 @@ from typing import Optional from db.async_database import async_context_get_db + class PayOrderServeries: @staticmethod - async def get_order_info_dno_orderid_visituopenid_state(async_session: AsyncSession, dno, visit_uopenid, - orderid)->DoctorSubscribeinfo: + async def get_order_info_dno_orderid_visituopenid_state( + async_session: AsyncSession, dno, visit_uopenid, orderid + ) -> DoctorSubscribeinfo: query = select(DoctorSubscribeinfo) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) _result = await async_session.execute(query) # 如果查询时整个模型的需要.scalar() # 如果是查询指定选择某些字段的是则不需要.scalar() # .scalar() 和 _result.scalars().first() 是一样效果 return _result.scalars().first() - - @staticmethod - async def get_doctor_info(async_session: AsyncSession, dno)->Doctorinfo: - - query = select( Doctorinfo.dnname, - Doctorinfo.pic, - Doctorinfo.dno, - Doctorinfo.rank, - Doctorinfo.fee, - Doctorinfo.destag, - Doctorinfo.describe) + async def get_doctor_info(async_session: AsyncSession, dno) -> Doctorinfo: + + query = select( + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.dno, + Doctorinfo.rank, + Doctorinfo.fee, + Doctorinfo.destag, + Doctorinfo.describe, + ) # 查询当前医生排班信息归属 query = query.where(Doctorinfo.dno == dno) _result = await async_session.execute(query) return _result.first() - - @staticmethod - async def get_doctor_scheduling_info_info_order(async_session: AsyncSession, dno, nsindex) -> DoctorScheduling: - query = select(DoctorScheduling.dnotime, - DoctorScheduling.ampm, - DoctorScheduling.tiempm, - DoctorScheduling.dnotime, - DoctorScheduling.tiemampmstr, - ) + async def get_doctor_scheduling_info_info_order( + async_session: AsyncSession, dno, nsindex + ) -> DoctorScheduling: + query = select( + DoctorScheduling.dnotime, + DoctorScheduling.ampm, + DoctorScheduling.tiempm, + DoctorScheduling.dnotime, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) _result = await async_session.execute(query) return _result.first() @staticmethod - async def get_order_info_byvisit_uopenid_state(async_session: AsyncSession, visit_uopenid, statue=1): - ''' + async def get_order_info_byvisit_uopenid_state( + async_session: AsyncSession, visit_uopenid, statue=1 + ): + """ 判断是否存在存在未支付的订单 :param async_session: 数据库会话对象 :param visit_uopenid: 当前用户opendi :param statue: 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 :return: - ''' + """ # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = select(DoctorSubscribeinfo.id) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.statue == statue, DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.statue == statue, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) _result = await async_session.execute(query) return _result.first() @staticmethod async def creat_order_info(async_session: AsyncSession, **kwargs): - ''' + """ 开始创建订单内容,并添加到数据库 :param async_session: :param kwargs: :return: - ''' + """ new_order = DoctorSubscribeinfo(**kwargs) async_session.add(new_order) await async_session.commit() @@ -83,40 +96,57 @@ async def creat_order_info(async_session: AsyncSession, **kwargs): return new_order @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno(async_session: AsyncSession, dno, orderid, visit_uopenid, **updata): + async def updata_order_info_byorder_dno( + async_session: AsyncSession, dno, orderid, visit_uopenid, **updata + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = update(DoctorSubscribeinfo) - query = query.where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) result = await async_session.execute(query.values(updata)) await async_session.commit() # result.rowcount 1:更新成功 0 更新失败 return result.rowcount -if __name__ == '__main__': +if __name__ == "__main__": import asyncio + async def sdsdf(): async with async_context_get_db() as session: - asdas = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(session, - dno='10001', - visit_uopenid='orE7I56mAt_dvtRoXkMw-hY8FkwM', - orderid='2207081548588935269') + asdas = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + session, + dno="10001", + visit_uopenid="orE7I56mAt_dvtRoXkMw-hY8FkwM", + orderid="2207081548588935269", + ) + ) print(asdas.orderid) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter13/booking_system/apis/payorders/schemas/__init__.py b/chapter13/booking_system/apis/payorders/schemas/__init__.py index f9db523..d79c74a 100644 --- a/chapter13/booking_system/apis/payorders/schemas/__init__.py +++ b/chapter13/booking_system/apis/payorders/schemas/__init__.py @@ -6,7 +6,7 @@ class SchedulingInfo(BaseModel): # 预约医生编号 dno: str # 预约时间 - start_time:str = None + start_time: str = None class MakeReserveOrderForm(BaseModel): @@ -16,16 +16,13 @@ class MakeReserveOrderForm(BaseModel): nsindex: str - class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") - - class PayReserveOrderForm(BaseModel): # 预约医生编号 dno: str @@ -34,18 +31,18 @@ class PayReserveOrderForm(BaseModel): # 预约人信息 visit_uname: str visit_uphone: str - visit_uopenid:str =None - visit_usex:str - visit_uage:str + visit_uopenid: str = None + visit_usex: str + visit_uage: str class PayCancelPayOrderForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - orderid:str + orderid: str # 预约医生的编号 - dno:str - + dno: str diff --git a/chapter13/booking_system/apis/userorders/api/__init__.py b/chapter13/booking_system/apis/userorders/api/__init__.py index 5cf6f5a..1226a32 100644 --- a/chapter13/booking_system/apis/userorders/api/__init__.py +++ b/chapter13/booking_system/apis/userorders/api/__init__.py @@ -1,4 +1,10 @@ from fastapi import APIRouter -router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) -from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ - wxauth_login + +router_userorders = APIRouter(prefix="/api/v1", tags=["用户订单模块"]) +from apis.userorders.api import ( + refund_reserve_order, + unpay_reserve_order, + user_order_info, + user_order_list, + wxauth_login, +) diff --git a/chapter13/booking_system/apis/userorders/api/refund_reserve_order.py b/chapter13/booking_system/apis/userorders/api/refund_reserve_order.py index dd9f94f..4d7b772 100644 --- a/chapter13/booking_system/apis/userorders/api/refund_reserve_order.py +++ b/chapter13/booking_system/apis/userorders/api/refund_reserve_order.py @@ -10,54 +10,78 @@ import time -@router_userorders.put("/refund_reserve_order", summary='订单退款申请') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/refund_reserve_order", summary="订单退款申请") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 1: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单还为支付!无法申请退款!') + return Fail(api_code=200, result=None, message="该订单还为支付!无法申请退款!") if doctor_nsnum_info_result.statue == 5: pass - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该已超时未支付,订单已过有效期!不可操作!') + return Fail( + api_code=200, + result=None, + message="该已超时未支付,订单已过有效期!不可操作!", + ) # 已经支付的订单信息 if doctor_nsnum_info_result.statue == 2: pass # 来获取时间差中的秒数。注意,seconds获得的秒只是时间差中的小时、分钟和秒部分的和,并没有包含时间差的天数(既是两个时间点不是同一天,失效) - today = time.strftime('%Y%m%d %H:%M:%S', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 - datiem = (currday_time_info_tochane_datetime(doctor_nsnum_info_result.visitday) - datetime.timedelta(days=1)) - subscribe_times = datetime.datetime.strptime(f"{str(datiem).replace('00:00:00', '')}23:59:59", - "%Y-%m-%d %H:%M:%S") + today = time.strftime("%Y%m%d %H:%M:%S", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 + datiem = currday_time_info_tochane_datetime( + doctor_nsnum_info_result.visitday + ) - datetime.timedelta(days=1) + subscribe_times = datetime.datetime.strptime( + f"{str(datiem).replace('00:00:00', '')}23:59:59", "%Y-%m-%d %H:%M:%S" + ) # 当前时间小于预约时间的最后截止时间之后就不可以预约 if todaydate >= subscribe_times: - return Fail(api_code=200, result=None, message='非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!') - - isok = Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - updata={ - 'statue': 5, - 'refund_statue': 1, - 'apply_refund_time': 'now()' - } - ) - return Success(api_code=200, result=None, message='申请退款成功!已提交审核!') if isok else Fail(api_code=200, result=None, - message='申请退款失败!') + return Fail( + api_code=200, + result=None, + message="非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!", + ) + + isok = Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + updata={"statue": 5, "refund_statue": 1, "apply_refund_time": "now()"}, + ) + return ( + Success(api_code=200, result=None, message="申请退款成功!已提交审核!") + if isok + else Fail(api_code=200, result=None, message="申请退款失败!") + ) diff --git a/chapter13/booking_system/apis/userorders/api/unpay_reserve_order.py b/chapter13/booking_system/apis/userorders/api/unpay_reserve_order.py index 871cc7f..3534acf 100644 --- a/chapter13/booking_system/apis/userorders/api/unpay_reserve_order.py +++ b/chapter13/booking_system/apis/userorders/api/unpay_reserve_order.py @@ -7,40 +7,57 @@ from ..repository import Serveries -@router_userorders.put("/unpay_reserve_order", summary='取消订单支付') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/unpay_reserve_order", summary="取消订单支付") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已过有效期!不可操作!') + return Fail(api_code=200, result=None, message="订单已过有效期!不可操作!") if doctor_nsnum_info_result.statue == 2: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已支付成功!如需取消,请申请操作退款!') + return Fail( + api_code=200, + result=None, + message="该订单已支付成功!如需取消,请申请操作退款!", + ) if doctor_nsnum_info_result.statue == 5: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) # 更新没有支付的成功的订单的,状态! - isok = await Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=3 - ) - - return Success(api_code=200, result=None, message='订单取消成功') if isok else Fail(api_code=200, result=None, - message='订单取消失败') + isok = await Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=3, + ) + + return ( + Success(api_code=200, result=None, message="订单取消成功") + if isok + else Fail(api_code=200, result=None, message="订单取消失败") + ) diff --git a/chapter13/booking_system/apis/userorders/api/user_order_info.py b/chapter13/booking_system/apis/userorders/api/user_order_info.py index 8db523d..4c3b182 100644 --- a/chapter13/booking_system/apis/userorders/api/user_order_info.py +++ b/chapter13/booking_system/apis/userorders/api/user_order_info.py @@ -10,15 +10,23 @@ import time -@router_userorders.post("/user_order_info", summary='用户订单详情查看') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.post("/user_order_info", summary="用户订单详情查看") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 获取预约详情信息列表 - doctor_nsnum_info_result = await Serveries.get_order_info_list_by_visit_uopenid_detailt( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_nsnum_info_result = ( + await Serveries.get_order_info_list_by_visit_uopenid_detailt( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=doctor_nsnum_info_result, message='查询成功') if doctor_nsnum_info_result else Fail( - api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=doctor_nsnum_info_result, message="查询成功") + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter13/booking_system/apis/userorders/api/user_order_list.py b/chapter13/booking_system/apis/userorders/api/user_order_list.py index fd87bf8..d4a574b 100644 --- a/chapter13/booking_system/apis/userorders/api/user_order_list.py +++ b/chapter13/booking_system/apis/userorders/api/user_order_list.py @@ -6,10 +6,20 @@ from ..schemas import UserOrderIonfoListForm from ..repository import Serveries -@router_userorders.post("/user_order_list", summary='用户自己订单列表') -async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): + +@router_userorders.post("/user_order_list", summary="用户自己订单列表") +async def callbadk( + forms: UserOrderIonfoListForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测用户的有消息 # 判断当前用户是否已经被拉黑啦,禁用了! - result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) + result = await Serveries.get_order_info_list_by_visit_uopenid_select( + db_session, visit_uopenid=forms.visit_uopenid, statue=forms.statue + ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=result, message="查询成功") + if result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter13/booking_system/apis/userorders/api/wxauth_login.py b/chapter13/booking_system/apis/userorders/api/wxauth_login.py index fda5814..e7e2ca3 100644 --- a/chapter13/booking_system/apis/userorders/api/wxauth_login.py +++ b/chapter13/booking_system/apis/userorders/api/wxauth_login.py @@ -3,42 +3,58 @@ from ..api import router_userorders from ..schemas import WxCodeForm from config.config import get_settings -from exts.wechatpy import WeChatClient, WeChatOAuth, WeChatOAuthException, WeChatException +from exts.wechatpy import ( + WeChatClient, + WeChatOAuth, + WeChatOAuthException, + WeChatException, +) def getWeChatOAuth(redirect_url): - return WeChatOAuth(get_settings().GZX_ID, get_settings().GZX_SECRET, redirect_url, 'snsapi_userinfo') + return WeChatOAuth( + get_settings().GZX_ID, + get_settings().GZX_SECRET, + redirect_url, + "snsapi_userinfo", + ) -@router_userorders.get("/login", summary='微信授权登入') +@router_userorders.get("/login", summary="微信授权登入") async def callbadk(*, forms: WxCodeForm = Depends(WxCodeForm)): wechat_oauth = None try: CODE = forms.code.strip() - wechat_oauth = getWeChatOAuth(redirect_url='') + wechat_oauth = getWeChatOAuth(redirect_url="") # 第二步:通过code换取网页授权access_token res_openid = wechat_oauth.fetch_access_token(CODE) except WeChatOAuthException as wcpayex: if not wcpayex.errcode: pass - return Fail(api_code=200, result=None, message='授权处理失败,原因:{}'.format(str(wcpayex.errmsg))) + return Fail( + api_code=200, + result=None, + message="授权处理失败,原因:{}".format(str(wcpayex.errmsg)), + ) except Exception as ex: - return Fail(api_code=200, result=None, message='授权处理失败,原因:未知异常的错误信息') + return Fail( + api_code=200, result=None, message="授权处理失败,原因:未知异常的错误信息" + ) user_info = wechat_oauth.get_user_info() # 正常的获取到用户信息 - openid = user_info.get('openid') - avatar_url = user_info.get('headimgurl') - city = user_info.get('city') - coutry = user_info.get('country') - nick_name = user_info.get('nickname') - province = user_info.get('province') - sex = '男' if user_info.get('sex') == 1 else '女' + openid = user_info.get("openid") + avatar_url = user_info.get("headimgurl") + city = user_info.get("city") + coutry = user_info.get("country") + nick_name = user_info.get("nickname") + province = user_info.get("province") + sex = "男" if user_info.get("sex") == 1 else "女" data = { "openid": openid, "nick_name": nick_name, "avatar_url": avatar_url, - "usex": sex + "usex": sex, } - return Success(api_code=200, result=data, message='获取成功') + return Success(api_code=200, result=data, message="获取成功") diff --git a/chapter13/booking_system/apis/userorders/repository/__init__.py b/chapter13/booking_system/apis/userorders/repository/__init__.py index fcb74e6..cbd7ed0 100644 --- a/chapter13/booking_system/apis/userorders/repository/__init__.py +++ b/chapter13/booking_system/apis/userorders/repository/__init__.py @@ -7,62 +7,86 @@ from typing import Optional - - - - class Serveries: @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno_olny(async_session: AsyncSession, dno, visit_uopenid, orderid, **updata): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny( + async_session: AsyncSession, dno, visit_uopenid, orderid, **updata + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(updata)) await async_session.commit() return result.rowcount @staticmethod - async def updata_order_info_byorder_dno_olny_dict(async_session: AsyncSession, dno, visit_uopenid, orderid, - updata={}): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny_dict( + async_session: AsyncSession, dno, visit_uopenid, orderid, updata={} + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(**updata)) await async_session.commit() return result.rowcount @staticmethod - async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSession, visit_uopenid, statue=1) -> list: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.dnname, - Doctorinfo.addr, - Doctorinfo.rank, - Doctorinfo.pic - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.statue == statue, - ) - - _subscribe_info_result:AsyncResult = await async_session.execute(query_subscribe_info) + async def get_order_info_list_by_visit_uopenid_select( + async_session: AsyncSession, visit_uopenid, statue=1 + ) -> list: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.dnname, + Doctorinfo.addr, + Doctorinfo.rank, + Doctorinfo.pic, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.statue == statue, + ) + ) + + _subscribe_info_result: AsyncResult = await async_session.execute( + query_subscribe_info + ) _rows = _subscribe_info_result.mappings() return [_row for _row in _rows] @@ -77,35 +101,41 @@ async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSessio # _rows = _subscribe_info_result.all() # return [item._mapping for item in _rows] - - - @staticmethod - async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSession, visit_uopenid, orderid, - dno) -> dict: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.addr, - Doctorinfo.dnname, - Doctorinfo.rank, - Doctorinfo.pic, - DoctorSubscribeinfo.create_time, - DoctorSubscribeinfo.visit_uname, - DoctorSubscribeinfo.visit_uphone, - DoctorSubscribeinfo.visit_usex, - DoctorSubscribeinfo.visit_uage, - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.dno == dno - ) + async def get_order_info_list_by_visit_uopenid_detailt( + async_session: AsyncSession, visit_uopenid, orderid, dno + ) -> dict: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.addr, + Doctorinfo.dnname, + Doctorinfo.rank, + Doctorinfo.pic, + DoctorSubscribeinfo.create_time, + DoctorSubscribeinfo.visit_uname, + DoctorSubscribeinfo.visit_uphone, + DoctorSubscribeinfo.visit_usex, + DoctorSubscribeinfo.visit_uage, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.dno == dno, + ) + ) _subscribe_info_result = await async_session.execute(query_subscribe_info) _row = _subscribe_info_result.first() return {} if not _row else _row._mapping @@ -129,14 +159,15 @@ async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSessi # } -if __name__ == '__main__': +if __name__ == "__main__": + async def sdsdf(): async with async_context_get_db() as session: - asdas = await Serveries.get_order_info_list_by_visit_uopenid_select(session, - visit_uopenid='orE7I59UwXdWzfSK9QGK2fHGtPZ8') + asdas = await Serveries.get_order_info_list_by_visit_uopenid_select( + session, visit_uopenid="orE7I59UwXdWzfSK9QGK2fHGtPZ8" + ) print(asdas) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter13/booking_system/apis/userorders/schemas/__init__.py b/chapter13/booking_system/apis/userorders/schemas/__init__.py index ad3861b..fb1607c 100644 --- a/chapter13/booking_system/apis/userorders/schemas/__init__.py +++ b/chapter13/booking_system/apis/userorders/schemas/__init__.py @@ -1,4 +1,3 @@ - from pydantic import BaseModel from fastapi import Depends, Query from pydantic.dataclasses import dataclass @@ -6,35 +5,38 @@ class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") + class UserOrderIonfoListForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - statue:int = None + statue: int = None class WxCodeForm(BaseModel): - code: str = Query(..., min_length=1,description="微信CODE") + code: str = Query(..., min_length=1, description="微信CODE") @dataclass class GetOrderinfos(BaseModel): - ''' + """ 连表查询出来的位置要字段要保持一致信息 - ''' + """ + orderid: str - statue:int - dno:str - visittime:str - visitday:str - visit_statue:int - dnname:str - addr:str - rank:str - pic:str + statue: int + dno: str + visittime: str + visitday: str + visit_statue: int + dnname: str + addr: str + rank: str + pic: str diff --git a/chapter13/booking_system/app.py b/chapter13/booking_system/app.py index 0536a07..de683f5 100644 --- a/chapter13/booking_system/app.py +++ b/chapter13/booking_system/app.py @@ -2,20 +2,29 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) try: - app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") + app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" + ) except: pass -@app.get('/docs', include_in_schema=False) + +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -23,8 +32,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -50,35 +61,53 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.async_rabbit import async_rabbit_client + # 启动成功的后的回调 from exts.rabbit import sync_rabbit_client + async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange1' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue1' - order_dead_letter_routing_key = 'xz-dead-letter-queue1' - await async_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) + order_dead_letter_exchange_name = "xz-dead-letter-exchange1" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue1" + order_dead_letter_routing_key = "xz-dead-letter-queue1" + await async_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_dead_letter_queue_name + ) - await async_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - routing_key=order_dead_letter_routing_key) + await async_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange1' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue1' - order_routing_key = 'order_handler1' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await async_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await async_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, routing_key=order_routing_key) + order_exchange_name = "xz-order-exchange1" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue1" + order_routing_key = "order_handler1" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await async_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await async_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, routing_key=order_routing_key + ) + -async_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) +async_rabbit_client.init_app( + app=app, rabbitconf=get_settings(), startup_callback=startup_callback_init_data +) def startup_callback_init_data_sync(): @@ -86,32 +115,45 @@ def startup_callback_init_data_sync(): # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' - sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" + sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) - sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - queue_name = order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) + sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name,queue_name=order_queue_name,routing_key=order_routing_key) -#try: -# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) -#except: -# pass + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) +# try: +# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) +# except: +# pass def creat_app(): diff --git a/chapter13/booking_system/app_sync.py b/chapter13/booking_system/app_sync.py index 7b50432..4c20432 100644 --- a/chapter13/booking_system/app_sync.py +++ b/chapter13/booking_system/app_sync.py @@ -2,17 +2,25 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") -app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) +app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" +) -@app.get('/docs', include_in_schema=False) +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -20,8 +28,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -29,8 +39,11 @@ async def custom_swagger_ui_html(): # app.router.route_class = ContextLogerRoute # app.add_middleware(BindContextvarMiddleware) -from middlewares.loger.middleware import LogerMiddleware -app.add_middleware(LogerMiddleware,log_pro_path=os.path.split(os.path.realpath(__file__))[0]) +from middlewares.loger.middleware import LogerMiddleware + +app.add_middleware( + LogerMiddleware, log_pro_path=os.path.split(os.path.realpath(__file__))[0] +) from apis.hospital.api import router_hospital @@ -46,34 +59,55 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client + + # 启动成功的后的回调 async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" # 创建交换机 - await sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) # 设置队列 await sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) # 绑定交换机和队列 - await sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name,queue_name=order_dead_letter_queue_name,routing_key=order_dead_letter_routing_key) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, queue_name=order_queue_name, routing_key=order_routing_key) - -sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) + + +sync_rabbit_client.init_app( + app=app, rabbitconf=get_settings(), startup_callback=startup_callback_init_data +) + def creat_app(): return app diff --git a/chapter13/booking_system/config/config.py b/chapter13/booking_system/config/config.py index 511f29c..bef9399 100644 --- a/chapter13/booking_system/config/config.py +++ b/chapter13/booking_system/config/config.py @@ -1,6 +1,7 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 连接数据库引擎 @@ -23,25 +24,27 @@ class Settings(BaseSettings): DB_POOL_SIZE: int = 60 DB_MAX_OVERFLOW: int = 0 - #公众号-开发者ID(AppID) - GZX_ID: str = 'wx91df1c5a300ddc3d' # 微信公众号ID - #公众号-开发者密码 - GZX_SECRET:str = '1f484aa3403b7c867d13a5e10c193191' - GZX_PAY_KEY: str = '0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh' # 微信支付秘钥 - MCH_ID: str = '1613748420' # 微信支付ID - NOTIFY_URL = 'http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback' #支付回调 + # 公众号-开发者ID(AppID) + GZX_ID: str = "wx91df1c5a300ddc3d" # 微信公众号ID + # 公众号-开发者密码 + GZX_SECRET: str = "1f484aa3403b7c867d13a5e10c193191" + GZX_PAY_KEY: str = "0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh" # 微信支付秘钥 + MCH_ID: str = "1613748420" # 微信支付ID + NOTIFY_URL = ( + "http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback" # 支付回调 + ) # 没有值的情况下的默认值--默认情况下读取的环境变量的值 # 链接用户名 - RABBIT_USERNAME: str = 'admin' + RABBIT_USERNAME: str = "admin" # 链接密码 - RABBIT_PASSWORD: str = 'admin' + RABBIT_PASSWORD: str = "admin" # 链接的主机 - RABBIT_HOST: str = 'rabbit' + RABBIT_HOST: str = "rabbit" # 链接端口 RABBIT_PORT: int = 5672 # 要链接租户空间名称 - VIRTUAL_HOST: str = 'yuyueguahao' + VIRTUAL_HOST: str = "yuyueguahao" # 心跳检测 RABBIT_HEARTBEAT = 5 diff --git a/chapter13/booking_system/db/async_database.py b/chapter13/booking_system/db/async_database.py index 0f9517b..998bd26 100644 --- a/chapter13/booking_system/db/async_database.py +++ b/chapter13/booking_system/db/async_database.py @@ -8,27 +8,39 @@ from contextlib import asynccontextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings # 创建异步引擎对象 settings = get_settings() -async_engine = create_async_engine(url=URL.create(settings.ASYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +async_engine = create_async_engine( + url=URL.create( + settings.ASYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) # 创建异步的会话管理对象 -AsyncSessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession,autocommit=False,autoflush=False, future=False) +AsyncSessionLocal = sessionmaker( + bind=async_engine, + expire_on_commit=False, + class_=AsyncSession, + autocommit=False, + autoflush=False, + future=False, +) async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: @@ -48,7 +60,7 @@ async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: # 需要使用这个来装饰一下,才可以使用with @asynccontextmanager async def async_context_get_db() -> AsyncGenerator: - ''' + """ async def init() -> None: pass async with get_db() as session: @@ -60,7 +72,7 @@ async def init() -> None: # loop = asyncio.get_event_loop() # loop.run_until_complete(init()) :return: - ''' + """ session = AsyncSessionLocal() try: yield session diff --git a/chapter13/booking_system/db/models.py b/chapter13/booking_system/db/models.py index 4749ca8..1bf4496 100644 --- a/chapter13/booking_system/db/models.py +++ b/chapter13/booking_system/db/models.py @@ -1,76 +1,157 @@ # coding: utf-8 -from sqlalchemy import Column, Date, DateTime, Integer, SmallInteger, Text, UniqueConstraint, text,DECIMAL,Numeric +from sqlalchemy import ( + Column, + Date, + DateTime, + Integer, + SmallInteger, + Text, + UniqueConstraint, + text, + DECIMAL, + Numeric, +) from sqlalchemy.dialects.postgresql import TIMESTAMP from db.async_database import Base + metadata = Base.metadata class DoctorScheduling(Base): - __tablename__ = 'doctor_scheduling' - __table_args__ = {'comment': '医生排班信息表'} + __tablename__ = "doctor_scheduling" + __table_args__ = {"comment": "医生排班信息表"} + + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + nsnum = Column(Integer, comment="号源总数") + nsnumstock = Column(Integer, comment="号源库存数") + nsindex = Column( + Text, unique=True, server_default=text("''::text"), comment="号源编号" + ) + dnotime = Column(Date, comment="排班日期,年-月-日") + tiemampmstr = Column( + Text, server_default=text("''::text"), comment="号源时段字符串显示" + ) + ampm = Column( + Text, server_default=text("''::text"), comment="医生工作日:上午 还是 下午" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + enable = Column(Integer, comment="是否可用(1:是 0 否)") + tiempm = Column( + TIMESTAMP(precision=6), comment="医生工作日:号源时段(年-月-日 时:分)" + ) - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - nsnum = Column(Integer, comment='号源总数') - nsnumstock = Column(Integer, comment='号源库存数') - nsindex = Column(Text, unique=True, server_default=text("''::text"), comment='号源编号') - dnotime = Column(Date, comment='排班日期,年-月-日') - tiemampmstr = Column(Text, server_default=text("''::text"), comment='号源时段字符串显示') - ampm = Column(Text, server_default=text("''::text"), comment='医生工作日:上午 还是 下午') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - tiempm = Column(TIMESTAMP(precision=6), comment='医生工作日:号源时段(年-月-日 时:分)') class DoctorSubscribeinfo(Base): - __tablename__ = 'doctor_subscribeinfo' - __table_args__ = {'comment': '预约信息详情表'} + __tablename__ = "doctor_subscribeinfo" + __table_args__ = {"comment": "预约信息详情表"} - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - orderid = Column(Text, index=True, server_default=text("''::text"), comment='订单编号') - nsindex = Column(Text, server_default=text("''::text"), comment='订单编号') - statue = Column(Integer, server_default=text("1"), comment='订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单') - visitday = Column(Text, server_default=text("''::text"), comment='就诊日期') - visittime = Column(Text, server_default=text("''::text"), comment='就诊时段') - payfee = Column(Text, server_default=text("''::text"), comment='支付诊费') - visit_uopenid = Column(Text, server_default=text("''::text"), comment='就诊人微信ID') - visit_uname = Column(Text, server_default=text("''::text"), comment='就诊人姓名') - visit_uphone = Column(Text, server_default=text("''::text"), comment='就诊人联系电话') - visit_usex = Column(Text, server_default=text("''::text"), comment='就诊人性别') - visit_uage = Column(Text, server_default=text("''::text"), comment='就诊人年龄') - visit_statue = Column(Integer, server_default=text("1"), comment='订单所属-就诊状态(1:待就诊 2:已就诊)') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - notify_callback_time = Column(TIMESTAMP(precision=0), comment='支付回调时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + orderid = Column( + Text, index=True, server_default=text("''::text"), comment="订单编号" + ) + nsindex = Column(Text, server_default=text("''::text"), comment="订单编号") + statue = Column( + Integer, + server_default=text("1"), + comment="订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单", + ) + visitday = Column(Text, server_default=text("''::text"), comment="就诊日期") + visittime = Column(Text, server_default=text("''::text"), comment="就诊时段") + payfee = Column(Text, server_default=text("''::text"), comment="支付诊费") + visit_uopenid = Column( + Text, server_default=text("''::text"), comment="就诊人微信ID" + ) + visit_uname = Column(Text, server_default=text("''::text"), comment="就诊人姓名") + visit_uphone = Column( + Text, server_default=text("''::text"), comment="就诊人联系电话" + ) + visit_usex = Column(Text, server_default=text("''::text"), comment="就诊人性别") + visit_uage = Column(Text, server_default=text("''::text"), comment="就诊人年龄") + visit_statue = Column( + Integer, + server_default=text("1"), + comment="订单所属-就诊状态(1:待就诊 2:已就诊)", + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + notify_callback_time = Column(TIMESTAMP(precision=0), comment="支付回调时间") class Doctorinfo(Base): - __tablename__ = 'doctorinfo' - __table_args__ = {'comment': '医生信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('doctorinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, unique=True, server_default=text("''::text"), comment='医生编号') - dnname = Column(Text, server_default=text("''::text"), comment='医生名称') - dnmobile = Column(Text, server_default=text("''::text"), comment='医生号码') - sex = Column(Integer, comment='医生性别:1: 男 2: 女 3:保密') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - rank = Column(Text, server_default=text("''::text"), comment='职称') - fee = Column(Numeric, comment='医生诊费') - grade = Column(Text, server_default=text("''::text"), comment='等级') - destag = Column(Text, server_default=text("''::text"), comment='专业擅长标签') - addr = Column(Text, server_default=text("''::text"), comment='开诊地点') - pic = Column(Text, server_default=text("''::text"), comment='医生图片') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - describe = Column(Text, comment='说明信息') + __tablename__ = "doctorinfo" + __table_args__ = {"comment": "医生信息表"} -class Hospitalinfo(Base): - __tablename__ = 'hospitalinfo' - __table_args__ = {'comment': '医院信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), comment='主键Id') - name = Column(Text, server_default=text("''::text"), comment='医院名称') - describe = Column(Text, server_default=text("''::text"), comment='医院描述') - describeimages = Column(Text, server_default=text("''::text"), comment='describeimages') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctorinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + unique=True, + server_default=text("''::text"), + comment="医生编号", + ) + dnname = Column(Text, server_default=text("''::text"), comment="医生名称") + dnmobile = Column(Text, server_default=text("''::text"), comment="医生号码") + sex = Column(Integer, comment="医生性别:1: 男 2: 女 3:保密") + enable = Column(Integer, comment="是否可用(1:是 0 否)") + rank = Column(Text, server_default=text("''::text"), comment="职称") + fee = Column(Numeric, comment="医生诊费") + grade = Column(Text, server_default=text("''::text"), comment="等级") + destag = Column(Text, server_default=text("''::text"), comment="专业擅长标签") + addr = Column(Text, server_default=text("''::text"), comment="开诊地点") + pic = Column(Text, server_default=text("''::text"), comment="医生图片") + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + describe = Column(Text, comment="说明信息") +class Hospitalinfo(Base): + __tablename__ = "hospitalinfo" + __table_args__ = {"comment": "医院信息表"} + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), + comment="主键Id", + ) + name = Column(Text, server_default=text("''::text"), comment="医院名称") + describe = Column(Text, server_default=text("''::text"), comment="医院描述") + describeimages = Column( + Text, server_default=text("''::text"), comment="describeimages" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) diff --git a/chapter13/booking_system/db/sync_database.py b/chapter13/booking_system/db/sync_database.py index 8e30c82..072840d 100644 --- a/chapter13/booking_system/db/sync_database.py +++ b/chapter13/booking_system/db/sync_database.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings from sqlalchemy import create_engine @@ -14,20 +15,29 @@ metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) -sync_engine = create_engine(url=URL.create(settings.SYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +sync_engine = create_engine( + url=URL.create( + settings.SYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) # 创建异步的会话管理对象 -SyncSessionLocal = sessionmaker(bind=sync_engine, expire_on_commit=False, autocommit=False, autoflush=False, - future=False) +SyncSessionLocal = sessionmaker( + bind=sync_engine, + expire_on_commit=False, + autocommit=False, + autoflush=False, + future=False, +) def depends_get_db_session(): @@ -56,20 +66,32 @@ def sync_context_get_db(): session.close() -if __name__ == '__main__': - from db.models import Hospitalinfo,DoctorSubscribeinfo +if __name__ == "__main__": + from db.models import Hospitalinfo, DoctorSubscribeinfo from sqlalchemy.sql import and_ with sync_context_get_db() as session: - ed_user = Hospitalinfo(name='ed', describe='Ed Jones', describeimages='edsnickname') + ed_user = Hospitalinfo( + name="ed", describe="Ed Jones", describeimages="edsnickname" + ) session.add(ed_user) - _result:DoctorSubscribeinfo = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).one_or_none() + _result: DoctorSubscribeinfo = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ) + .one_or_none() + ) print(_result.dno) - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).update( - {DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) \ No newline at end of file + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) diff --git a/chapter13/booking_system/exts/async_rabbit/__init__.py b/chapter13/booking_system/exts/async_rabbit/__init__.py index bd0a144..46598c3 100644 --- a/chapter13/booking_system/exts/async_rabbit/__init__.py +++ b/chapter13/booking_system/exts/async_rabbit/__init__.py @@ -32,35 +32,56 @@ async def shutdown_event(): await self._clear_all() async def init_sync_rabbit(self, rabbitconf): - self.connection = await aio_pika.connect_robust(host=rabbitconf.RABBIT_HOST, - port=rabbitconf.RABBIT_PORT, - virtualhost=rabbitconf.VIRTUAL_HOST, - login=rabbitconf.RABBIT_USERNAME, - loop=asyncio.get_event_loop(), - password=rabbitconf.RABBIT_PASSWORD - ) + self.connection = await aio_pika.connect_robust( + host=rabbitconf.RABBIT_HOST, + port=rabbitconf.RABBIT_PORT, + virtualhost=rabbitconf.VIRTUAL_HOST, + login=rabbitconf.RABBIT_USERNAME, + loop=asyncio.get_event_loop(), + password=rabbitconf.RABBIT_PASSWORD, + ) # channel_number: int = None, # publisher_confirms: bool = True, # on_return_raises: bool = False, - self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel(publisher_confirms=False) - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' + self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel( + publisher_confirms=False + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" # if auto_delete and durable is None: # durable = False - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,auto_delete=False,durable=durable) - - - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - self.queue = await self.channel.declare_queue(name=queue_name, durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, auto_delete=False, durable=durable + ) + + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" await self.queue.bind(exchange=exchange_name, routing_key=routing_key) - - async def send_basic_publish(self, routing_key, body, content_type="text/plain", content_encoding='utf-8', - message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 try: @@ -71,20 +92,17 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", expiration=message_ttl * 1000, content_type=content_type, content_encoding=content_encoding, - delivery_mode=delivery_mode + delivery_mode=delivery_mode, ), routing_key=routing_key, ) else: await self.exchange.publish( - Message( - bytes(body, "utf-8"), - delivery_mode=delivery_mode - ), + Message(bytes(body, "utf-8"), delivery_mode=delivery_mode), routing_key=routing_key, ) except UnroutableError: - print('消息发送失败') + print("消息发送失败") async def _close_connect(self): """ @@ -100,13 +118,13 @@ async def _close_channel(self): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") await self.channel.close() async def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" await self._close_connect() self.connection = None diff --git a/chapter13/booking_system/exts/exceptions/__init__.py b/chapter13/booking_system/exts/exceptions/__init__.py index 57d9d64..ecbfd6c 100644 --- a/chapter13/booking_system/exts/exceptions/__init__.py +++ b/chapter13/booking_system/exts/exceptions/__init__.py @@ -14,9 +14,15 @@ from fastapi import FastAPI, Request from starlette.exceptions import HTTPException as StarletteHTTPException from fastapi.exceptions import RequestValidationError -from exts.responses.json_response import InternalErrorException, \ - MethodnotallowedException, \ - NotfoundException, LimiterResException, BadrequestException, ParameterException, Businesserror +from exts.responses.json_response import ( + InternalErrorException, + MethodnotallowedException, + NotfoundException, + LimiterResException, + BadrequestException, + ParameterException, + Businesserror, +) from enum import Enum @@ -32,9 +38,14 @@ class ExceptionEnum(Enum): class BusinessError(Exception): - __slots__ = ['err_code', 'err_code_des'] + __slots__ = ["err_code", "err_code_des"] - def __init__(self, result: ExceptionEnum = None, err_code: str = "0000", err_code_des: str = ""): + def __init__( + self, + result: ExceptionEnum = None, + err_code: str = "0000", + err_code_des: str = "", + ): if result: self.err_code = result.value[0] self.err_code_des = err_code_des or result.value[1] @@ -52,24 +63,36 @@ def __init__(self, app=None, *args, **kwargs): def init_app(self, app: FastAPI): app.add_exception_handler(Exception, handler=self.all_exception_handler) - app.add_exception_handler(StarletteHTTPException, handler=self.http_exception_handler) + app.add_exception_handler( + StarletteHTTPException, handler=self.http_exception_handler + ) app.add_exception_handler(BusinessError, handler=self.all_businesserror_handler) - app.add_exception_handler(RequestValidationError, handler=self.validation_exception_handler) + app.add_exception_handler( + RequestValidationError, handler=self.validation_exception_handler + ) - async def validation_exception_handler(self, request: Request, exc: RequestValidationError): - return ParameterException(http_status_code=400, api_code=400, message='参数校验错误', result={ - "detail": exc.errors(), - "body": exc.body - }) + async def validation_exception_handler( + self, request: Request, exc: RequestValidationError + ): + return ParameterException( + http_status_code=400, + api_code=400, + message="参数校验错误", + result={"detail": exc.errors(), "body": exc.body}, + ) async def all_businesserror_handler(self, request: Request, exc: BusinessError): - return Businesserror(http_status_code=200, api_code=exc.err_code, message=exc.err_code_des) + return Businesserror( + http_status_code=200, api_code=exc.err_code, message=exc.err_code_des + ) async def all_exception_handler(self, request: Request, exc: Exception): return InternalErrorException() - async def http_exception_handler(self, request: Request, exc: StarletteHTTPException): + async def http_exception_handler( + self, request: Request, exc: StarletteHTTPException + ): if exc.status_code == 405: return MethodnotallowedException() if exc.status_code == 404: diff --git a/chapter13/booking_system/exts/logururoute/__init__.py b/chapter13/booking_system/exts/logururoute/__init__.py index 8deed65..76eaf24 100644 --- a/chapter13/booking_system/exts/logururoute/__init__.py +++ b/chapter13/booking_system/exts/logururoute/__init__.py @@ -13,7 +13,7 @@ from time import perf_counter from fastapi.routing import APIRoute -from typing import Callable, List, Dict,Optional +from typing import Callable, List, Dict, Optional from fastapi.responses import Response import shortuuid from datetime import datetime @@ -28,7 +28,8 @@ from fastapi.responses import StreamingResponse from exts.requestvar import request -__all__ = ("setup_ext_loguru", "ContextLogerRoute") +__all__ = ("setup_ext_loguru", "ContextLogerRoute") + class ContextLogerRoute(APIRoute): # 再静态的里面使用self来查询也可以,遵循从内到外的查询 @@ -41,11 +42,15 @@ class ContextLogerRoute(APIRoute): def filter_request_url(self): path_info = request.url.path # 过滤不需要记录日志请求地址URL - return path_info not in ['/favicon.ico'] and 'websocket' not in path_info and request.method != 'OPTIONS' + return ( + path_info not in ["/favicon.ico"] + and "websocket" not in path_info + and request.method != "OPTIONS" + ) - def filter_response_context(self,response: Response): + def filter_response_context(self, response: Response): # 过滤不需要记录日志响应体内容信息L - return 'image' not in response.media_type and hasattr(request.state, 'traceid') + return "image" not in response.media_type and hasattr(request.state, "traceid") async def make_request_start_time(self): pass @@ -55,7 +60,7 @@ async def make_request_start_time(self): # 计算时间 request.state.start_time = perf_counter() - async def make_request_log_msg(self)->Dict: + async def make_request_log_msg(self) -> Dict: log_msg = None if self.filter_request_url(): ip, method, url = request.client.host, request.method, request.url.path @@ -69,14 +74,14 @@ async def make_request_log_msg(self)->Dict: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass # 在这里记录下当前提交的body的数据,用于下文的提取 @@ -96,59 +101,75 @@ async def make_request_log_msg(self)->Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - async def before_request_record_loger(self,log_msg=None): + async def before_request_record_loger(self, log_msg=None): if self.filter_request_url() and log_msg: - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) - async def after_request_record_loger(self, response: Response): + async def after_request_record_loger(self, response: Response): if self.filter_response_context(response=response): - start_time = getattr(request.state, 'start_time') - end_time = f'{(perf_counter() - start_time):.2f}' + start_time = getattr(request.state, "start_time") + end_time = f"{(perf_counter() - start_time):.2f}" # 获取响应报文信息内容 rsp = None if not isinstance(response, StreamingResponse): if isinstance(response, Response): - rsp = str(response.body, encoding='utf-8') + rsp = str(response.body, encoding="utf-8") try: rsp = json_helper.json_to_dict(rsp) except: @@ -156,12 +177,12 @@ async def after_request_record_loger(self, response: Response): log_msg = { # 记录请求耗时 "status_code": response.status_code, - 'cost_time': end_time, + "cost_time": end_time, # 记录请求响应的最终报文信息--eval的作用是去除相关的 转义符号 "\"ok\""===》ok - 'rsp': rsp, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "rsp": rsp, + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - await async_trace_add_log_record(event_type='response', msg=log_msg) + await async_trace_add_log_record(event_type="response", msg=log_msg) async def teardown_requestcontext(self, request: Request, response: Response): pass @@ -192,44 +213,44 @@ async def custom_route_handler(request: Request) -> Response: return custom_route_handler - - - -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str( - getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - - - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) diff --git a/chapter13/booking_system/exts/logururoute/config.py b/chapter13/booking_system/exts/logururoute/config.py index 809ad95..b3aa37f 100644 --- a/chapter13/booking_system/exts/logururoute/config.py +++ b/chapter13/booking_system/exts/logururoute/config.py @@ -4,10 +4,10 @@ def setup_ext_loguru(app: FastAPI, log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ @app.on_event("startup") async def startup(): @@ -16,33 +16,52 @@ async def startup(): def init_loguru_handlers(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: # BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(log_file_path, format=format2, rotation='00:00', compression="zip", encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file \ No newline at end of file + logger.add( + log_file_path, + format=format2, + rotation="00:00", + compression="zip", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file diff --git a/chapter13/booking_system/exts/rabbit/__init__.py b/chapter13/booking_system/exts/rabbit/__init__.py index 7b5a3c9..4adb1c4 100644 --- a/chapter13/booking_system/exts/rabbit/__init__.py +++ b/chapter13/booking_system/exts/rabbit/__init__.py @@ -30,48 +30,81 @@ def shutdown_event(): self._clear_all() def init_sync_rabbit(self, rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() - @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - - self.channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type, durable=durable) + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + + self.channel.exchange_declare( + exchange=exchange_name, exchange_type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - '''创建队列''' + def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + """创建队列""" pass - self.channel.queue_declare(queue=queue_name, durable=durable, auto_delete=auto_delete, arguments=arguments) + self.channel.queue_declare( + queue=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + ) def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" pass - self.channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) + self.channel.queue_bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='', - content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -100,10 +133,11 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha message_id = str(uuid.uuid4()) if is_delay: - properties = pika.BasicProperties(content_type=content_type, - content_encoding=content_encoding, - delivery_mode=delivery_mode, - ) + properties = pika.BasicProperties( + content_type=content_type, + content_encoding=content_encoding, + delivery_mode=delivery_mode, + ) # expiration 字段以毫秒为单位表示 TTL 值,6 秒的 message properties.expiration = f"{message_ttl * 1000}" # 秒 self.channel.basic_publish( @@ -114,7 +148,7 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 发送的消息的内容 body=body, # 发现的消息的类型 - properties=properties + properties=properties, # pika.BasicProperties中的delivery_mode=2指明message为持久的,1 的话 表示不是持久化 2:表示持久化 ) else: @@ -124,13 +158,13 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 默认的匹配的key routing_key=routing_key, # 发送的消息的内容 - body=body + body=body, ) else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -150,13 +184,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None diff --git a/chapter13/booking_system/exts/rabbit2/__init__.py b/chapter13/booking_system/exts/rabbit2/__init__.py index a6bc476..907dc3d 100644 --- a/chapter13/booking_system/exts/rabbit2/__init__.py +++ b/chapter13/booking_system/exts/rabbit2/__init__.py @@ -17,63 +17,95 @@ def __init__(self, app: FastAPI = None): if app is not None: self.init_app(app, None, None) - def init_app(self, app: FastAPI,rabbitconf,startup_callback): + def init_app(self, app: FastAPI, rabbitconf, startup_callback): self.app = app + @app.on_event("startup") def startup_event(): self.init_sync_rabbit(rabbitconf) # 初始化回调 startup_callback() + @app.on_event("shutdown") def shutdown_event(): self._clear_all() - - def init_sync_rabbit(self,rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + def init_sync_rabbit(self, rabbitconf): + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' - - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,durable=durable) - + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" + + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - - - self.queue = await self.channel.declare_queue(name=queue_name,durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' - await self.queue.bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) - - + """同伙routing_key把交换机和队列的绑定""" + await self.queue.bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - async def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='',content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -88,14 +120,14 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", # mandatory: bool = True, # immediate: bool = False, # timeout: TimeoutType = None - await self.exchange.publish(message, routing_key=routing_key) + await self.exchange.publish(message, routing_key=routing_key) else: - pass + pass else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -115,13 +147,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None @@ -131,4 +163,4 @@ def _clear_all(self): self.channel = None -sync_rabbit_client = RabbitMQClintWithLock() \ No newline at end of file +sync_rabbit_client = RabbitMQClintWithLock() diff --git a/chapter13/booking_system/exts/requestvar/__init__.py b/chapter13/booking_system/exts/requestvar/__init__.py index 2f50ac3..c786445 100644 --- a/chapter13/booking_system/exts/requestvar/__init__.py +++ b/chapter13/booking_system/exts/requestvar/__init__.py @@ -3,12 +3,13 @@ import shortuuid from exts.requestvar.bing import bind_contextvar from starlette.types import ASGIApp, Receive, Scope, Send + request_var: ContextVar[Request] = ContextVar("request") request: Request = bind_contextvar(request_var) + class BindContextvarMiddleware: - def __init__( - self, app: ASGIApp) -> None: + def __init__(self, app: ASGIApp) -> None: self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: diff --git a/chapter13/booking_system/exts/responses/__init__.py b/chapter13/booking_system/exts/responses/__init__.py index f1c6644..1b80a76 100644 --- a/chapter13/booking_system/exts/responses/__init__.py +++ b/chapter13/booking_system/exts/responses/__init__.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/9/23 ------------------------------------------------- - 修改描述-2021/9/23: + 修改描述-2021/9/23: ------------------------------------------------- """ from . import json_response diff --git a/chapter13/booking_system/exts/responses/json_response.py b/chapter13/booking_system/exts/responses/json_response.py index 0a59c3e..5abd98f 100644 --- a/chapter13/booking_system/exts/responses/json_response.py +++ b/chapter13/booking_system/exts/responses/json_response.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/7/15 ------------------------------------------------- - 修改描述-2021/7/15: + 修改描述-2021/7/15: ------------------------------------------------- """ @@ -23,26 +23,30 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) elif isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") elif isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") elif isinstance(obj, datetime.time): return obj.isoformat() elif isinstance(obj, decimal.Decimal): return float(obj) elif isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") elif isinstance(obj.__class__, DeclarativeMeta): # 如果是查询返回所有的那种models类型的,需要处理些 # 将SqlAlchemy结果序列化为JSON--查询全部的时候的处理返回 - return self.default({i.name: getattr(obj, i.name) for i in obj.__table__.columns}) + return self.default( + {i.name: getattr(obj, i.name) for i in obj.__table__.columns} + ) elif isinstance(obj, dict): for k in obj: try: - if isinstance(obj[k], (datetime.datetime, datetime.date, DeclarativeMeta)): + if isinstance( + obj[k], (datetime.datetime, datetime.date, DeclarativeMeta) + ): obj[k] = self.default(obj[k]) else: obj[k] = obj[k] @@ -59,11 +63,19 @@ class ApiResponse(JSONResponse): api_code = 0 # 默认Node.如果是必选的,去掉默认值即可 result: Optional[Dict[str, Any]] = None # 结果可以是{} 或 [] - message = '成功' + message = "成功" success = True timestamp = int(time.time() * 1000) - def __init__(self, success=None, http_status_code=None, api_code=None, result=None, message=None, **options): + def __init__( + self, + success=None, + http_status_code=None, + api_code=None, + result=None, + message=None, + **options + ): self.message = message or self.message self.api_code = api_code or self.api_code self.success = success or self.success @@ -76,9 +88,11 @@ def __init__(self, success=None, http_status_code=None, api_code=None, result=No code=self.api_code, success=self.success, result=self.result, - timestamp=self.timestamp + timestamp=self.timestamp, + ) + super(ApiResponse, self).__init__( + status_code=self.http_status_code, content=body, **options ) - super(ApiResponse, self).__init__(status_code=self.http_status_code, content=body, **options) # 这个render会自动调用,如果这里需要特殊的处理的话,可以重写这个地方 def render(self, content: typing.Any) -> bytes: @@ -88,7 +102,7 @@ def render(self, content: typing.Any) -> bytes: allow_nan=False, indent=None, separators=(",", ":"), - cls=CJsonEncoder + cls=CJsonEncoder, ).encode("utf-8") @@ -96,7 +110,7 @@ class BadrequestException(ApiResponse): http_status_code = 400 api_code = 10031 result = None # 结果可以是{} 或 [] - message = '错误的请求' + message = "错误的请求" success = False @@ -104,14 +118,14 @@ class LimiterResException(ApiResponse): http_status_code = 429 api_code = 429 result = None # 结果可以是{} 或 [] - message = '访问的速度过快' + message = "访问的速度过快" success = False class ParameterException(ApiResponse): http_status_code = 400 result = {} - message = '参数校验错误,请检查提交的参数信息' + message = "参数校验错误,请检查提交的参数信息" api_code = 10031 success = False @@ -119,7 +133,7 @@ class ParameterException(ApiResponse): class UnauthorizedException(ApiResponse): http_status_code = 401 result = {} - message = '未经许可授权' + message = "未经许可授权" api_code = 10032 success = False @@ -127,7 +141,7 @@ class UnauthorizedException(ApiResponse): class ForbiddenException(ApiResponse): http_status_code = 403 result = {} - message = '失败!当前访问没有权限,或操作的数据没权限!' + message = "失败!当前访问没有权限,或操作的数据没权限!" api_code = 10033 success = False @@ -135,7 +149,7 @@ class ForbiddenException(ApiResponse): class NotfoundException(ApiResponse): http_status_code = 404 result = {} - message = '访问地址不存在' + message = "访问地址不存在" api_code = 10034 success = False @@ -143,7 +157,7 @@ class NotfoundException(ApiResponse): class MethodnotallowedException(ApiResponse): http_status_code = 405 result = {} - message = '不允许使用此方法提交访问' + message = "不允许使用此方法提交访问" api_code = 10034 success = False @@ -151,7 +165,7 @@ class MethodnotallowedException(ApiResponse): class OtherException(ApiResponse): http_status_code = 800 result = {} - message = '未知的其他HTTPEOOER异常' + message = "未知的其他HTTPEOOER异常" api_code = 10034 success = False @@ -159,7 +173,7 @@ class OtherException(ApiResponse): class InternalErrorException(ApiResponse): http_status_code = 200 result = {} - message = '程序员哥哥睡眠不足,系统崩溃了!' + message = "程序员哥哥睡眠不足,系统崩溃了!" api_code = 200 success = False @@ -167,13 +181,13 @@ class InternalErrorException(ApiResponse): class InvalidTokenException(ApiResponse): http_status_code = 401 api_code = 401 - message = '很久没操作,令牌失效' + message = "很久没操作,令牌失效" success = False class ExpiredTokenException(ApiResponse): http_status_code = 422 - message = '很久没操作,令牌过期' + message = "很久没操作,令牌过期" api_code = 10050 success = False @@ -182,19 +196,19 @@ class FileTooLargeException(ApiResponse): http_status_code = 413 api_code = 413 result = None # 结果可以是{} 或 [] - message = '文件体积过大' + message = "文件体积过大" class FileTooManyException(ApiResponse): http_status_code = 413 - message = '文件数量过多' + message = "文件数量过多" api_code = 10120 result = None # 结果可以是{} 或 [] class FileExtensionException(ApiResponse): http_status_code = 401 - message = '文件扩展名不符合规范' + message = "文件扩展名不符合规范" api_code = 10121 result = None # 结果可以是{} 或 [] @@ -203,16 +217,15 @@ class Success(ApiResponse): http_status_code = 200 api_code = 200 result = None # 结果可以是{} 或 [] - message = '获取成功' + message = "获取成功" success = True - class Businesserror(ApiResponse): http_status_code = 200 - api_code = '0000' + api_code = "0000" result = None # 结果可以是{} 或 [] - message = '业务错误逻辑处理' + message = "业务错误逻辑处理" success = False @@ -220,5 +233,5 @@ class Fail(ApiResponse): http_status_code = 200 api_code = -1 result = None # 结果可以是{} 或 [] - message = '操作失败' + message = "操作失败" success = False diff --git a/chapter13/booking_system/exts/wechatpy/__init__.py b/chapter13/booking_system/exts/wechatpy/__init__.py index 61c0ac9..24ea439 100644 --- a/chapter13/booking_system/exts/wechatpy/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/__init__.py @@ -4,21 +4,28 @@ from exts.wechatpy.client import WeChatClient # NOQA from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA -from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA +from exts.wechatpy.exceptions import ( + WeChatClientException, + WeChatException, + WeChatOAuthException, + WeChatPayException, +) # NOQA from exts.wechatpy.oauth import WeChatOAuth # NOQA from exts.wechatpy.parser import parse_message # NOQA from exts.wechatpy.pay import WeChatPay # NOQA from exts.wechatpy.replies import create_reply # NOQA -__version__ = '1.8.2' -__author__ = 'messense' +__version__ = "1.8.2" +__author__ = "messense" # Set default logging handler to avoid "No handler found" warnings. try: # Python 2.7+ from logging import NullHandler except ImportError: + class NullHandler(logging.Handler): def emit(self, record): pass + logging.getLogger(__name__).addHandler(NullHandler()) diff --git a/chapter13/booking_system/exts/wechatpy/_compat.py b/chapter13/booking_system/exts/wechatpy/_compat.py index 2306499..87376ce 100644 --- a/chapter13/booking_system/exts/wechatpy/_compat.py +++ b/chapter13/booking_system/exts/wechatpy/_compat.py @@ -1,21 +1,24 @@ # -*- coding: utf-8 -*- """ - wechatpy._compat - ~~~~~~~~~~~~~~~~~ +wechatpy._compat +~~~~~~~~~~~~~~~~~ - This module makes it easy for wechatpy to run on both Python 2 and 3. +This module makes it easy for wechatpy to run on both Python 2 and 3. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import sys import six import warnings -warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" - "use `wechatpy.utils` instead", - DeprecationWarning, stacklevel=2) +warnings.warn( + "Module `wechatpy._compat` is deprecated, will be removed in 2.0" + "use `wechatpy.utils` instead", + DeprecationWarning, + stacklevel=2, +) from exts.wechatpy.utils import get_querystring from exts.wechatpy.utils import json diff --git a/chapter13/booking_system/exts/wechatpy/client/__init__.py b/chapter13/booking_system/exts/wechatpy/client/__init__.py index 18040c0..bcb4f00 100644 --- a/chapter13/booking_system/exts/wechatpy/client/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/client/__init__.py @@ -8,13 +8,12 @@ class WeChatClient(BaseWeChatClient): - """ 微信 API 操作类 通过这个类可以操作微信 API,发送主动消息、群发消息和创建自定义菜单等。 """ - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin/" # API_BASE_URL = 'http://47.99.189.42:30005/cgi-bin/' card = api.WeChatCard() @@ -42,8 +41,15 @@ class WeChatClient(BaseWeChatClient): wxa = api.WeChatWxa() marketing = api.WeChatMarketing() - def __init__(self, appid, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + appid, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( appid, access_token, session, timeout, auto_retry ) @@ -58,27 +64,31 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ return self._fetch_access_token( - url='https://api.weixin.qq.com/cgi-bin/token', + url="https://api.weixin.qq.com/cgi-bin/token", params={ - 'grant_type': 'client_credential', - 'appid': self.appid, - 'secret': self.secret - } + "grant_type": "client_credential", + "appid": self.appid, + "secret": self.secret, + }, ) class WeChatComponentClient(WeChatClient): - """ 开放平台代公众号调用客户端 """ - def __init__(self, appid, component, access_token=None, - refresh_token=None, session=None, timeout=None): + def __init__( + self, + appid, + component, + access_token=None, + refresh_token=None, + session=None, + timeout=None, + ): # 未用到secret,所以这里没有 - super(WeChatComponentClient, self).__init__( - appid, '', '', session, timeout - ) + super(WeChatComponentClient, self).__init__(appid, "", "", session, timeout) self.appid = appid self.component = component # 如果公众号是刚授权,外部还没有缓存access_token和refresh_token @@ -86,18 +96,20 @@ def __init__(self, appid, component, access_token=None, # 如果外部已经缓存,这里只需要传入 appid,component和session即可 cache_access_token = self.session.get(self.access_token_key) - if access_token and (not cache_access_token or cache_access_token != access_token): + if access_token and ( + not cache_access_token or cache_access_token != access_token + ): self.session.set(self.access_token_key, access_token, 7200) if refresh_token: self.session.set(self.refresh_token_key, refresh_token) @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) @property def refresh_token_key(self): - return '{0}_refresh_token'.format(self.appid) + return "{0}_refresh_token".format(self.appid) @property def access_token(self): @@ -123,14 +135,11 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ expires_in = 7200 - result = self.component.refresh_authorizer_token( - self.appid, self.refresh_token) - if 'expires_in' in result: - expires_in = result['expires_in'] + result = self.component.refresh_authorizer_token(self.appid, self.refresh_token) + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - self.access_token_key, - result['authorizer_access_token'], - expires_in + self.access_token_key, result["authorizer_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result diff --git a/chapter13/booking_system/exts/wechatpy/client/api/base.py b/chapter13/booking_system/exts/wechatpy/client/api/base.py index 10bbec4..66cb918 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/base.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/base.py @@ -3,21 +3,21 @@ class BaseWeChatAPI(object): - """ WeChat API base class """ + """WeChat API base class""" def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL - print("当前URL",url) + print("当前URL", url) return self._client.post(url, **kwargs) @property diff --git a/chapter13/booking_system/exts/wechatpy/client/api/card.py b/chapter13/booking_system/exts/wechatpy/client/api/card.py index 9dcb398..7b1b399 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/card.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/card.py @@ -6,7 +6,7 @@ class WeChatCard(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create(self, card_data): """ @@ -16,9 +16,7 @@ def create(self, card_data): :return: 创建的卡券 ID """ result = self._post( - 'card/create', - data=card_data, - result_processor=lambda x: x['card_id'] + "card/create", data=card_data, result_processor=lambda x: x["card_id"] ) return result @@ -30,9 +28,9 @@ def batch_add_locations(self, location_data): :return: 门店 ID 列表,插入失败的门店元素值为 -1 """ result = self._post( - 'card/location/batchadd', + "card/location/batchadd", data=location_data, - result_processor=lambda x: x['location_id_list'] + result_processor=lambda x: x["location_id_list"], ) return result @@ -41,11 +39,7 @@ def batch_get_locations(self, offset=0, count=0): 批量获取门店信息 """ return self._post( - 'card/location/batchget', - data={ - 'offset': offset, - 'count': count - } + "card/location/batchget", data={"offset": offset, "count": count} ) def get_colors(self): @@ -53,10 +47,7 @@ def get_colors(self): 获得卡券的最新颜色列表,用于创建卡券 :return: 颜色列表 """ - result = self._get( - 'card/getcolors', - result_processor=lambda x: x['colors'] - ) + result = self._get("card/getcolors", result_processor=lambda x: x["colors"]) return result def create_qrcode(self, qrcode_data): @@ -67,9 +58,9 @@ def create_qrcode(self, qrcode_data): :return: 二维码 ticket,可使用 :func:show_qrcode 换取二维码文件 """ result = self._post( - 'card/qrcode/create', + "card/qrcode/create", data=qrcode_data, - result_processor=lambda x: x['ticket'] + result_processor=lambda x: x["ticket"], ) return result @@ -77,10 +68,7 @@ def create_landingpage(self, buffer_data): """ 创建货架 """ - result = self._post( - 'card/landingpage/create', - data=buffer_data - ) + result = self._post("card/landingpage/create", data=buffer_data) return result def get_html(self, card_id): @@ -88,11 +76,9 @@ def get_html(self, card_id): 图文消息群发卡券 """ result = self._post( - 'card/mpnews/gethtml', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['content'] + "card/mpnews/gethtml", + data={"card_id": card_id}, + result_processor=lambda x: x["content"], ) return result @@ -100,26 +86,19 @@ def consume_code(self, code, card_id=None): """ 消耗 code """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/consume', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/consume", data=card_data) def decrypt_code(self, encrypt_code): """ 解码加密的 code """ result = self._post( - 'card/code/decrypt', - data={ - 'encrypt_code': encrypt_code - }, - result_processor=lambda x: x['code'] + "card/code/decrypt", + data={"encrypt_code": encrypt_code}, + result_processor=lambda x: x["code"], ) return result @@ -127,68 +106,43 @@ def delete(self, card_id): """ 删除卡券 """ - return self._post( - 'card/delete', - data={ - 'card_id': card_id - } - ) + return self._post("card/delete", data={"card_id": card_id}) def get_code(self, code, card_id=None, check_consume=True): """ 查询 code 信息 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id + card_data["card_id"] = card_id if not check_consume: - card_data['check_consume'] = check_consume - return self._post( - 'card/code/get', - data=card_data - ) + card_data["check_consume"] = check_consume + return self._post("card/code/get", data=card_data) def get_card_list(self, openid, card_id=None): """ 用于获取用户卡包里的,属于该appid下的卡券。 """ - card_data = { - 'openid': openid - } + card_data = {"openid": openid} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/order/getcardlist', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/order/getcardlist", data=card_data) def batch_get(self, offset=0, count=50, status_list=None): """ 批量查询卡券信息 """ - card_data = { - 'offset': offset, - 'count': count - } + card_data = {"offset": offset, "count": count} if status_list: - card_data['status_list'] = status_list - return self._post( - 'card/batchget', - data=card_data - ) + card_data["status_list"] = status_list + return self._post("card/batchget", data=card_data) def get(self, card_id): """ 查询卡券详情 """ result = self._post( - 'card/get', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['card'] + "card/get", data={"card_id": card_id}, result_processor=lambda x: x["card"] ) return result @@ -197,47 +151,31 @@ def update_code(self, card_id, old_code, new_code): 更新卡券 code """ return self._post( - 'card/code/update', - data={ - 'card_id': card_id, - 'code': old_code, - 'new_code': new_code - } + "card/code/update", + data={"card_id": card_id, "code": old_code, "new_code": new_code}, ) def invalid_code(self, code, card_id=None): """ 设置卡券失效 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/unavailable', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/unavailable", data=card_data) def update(self, card_data): """ 更新卡券信息 """ - return self._post( - 'card/update', - data=card_data - ) + return self._post("card/update", data=card_data) def set_paycell(self, card_id, is_open): """ 更新卡券信息 """ return self._post( - 'card/paycell/set', - data={ - 'card_id': card_id, - 'is_open': is_open - } + "card/paycell/set", data={"card_id": card_id, "is_open": is_open} ) def set_test_whitelist(self, openids=None, usernames=None): @@ -247,11 +185,7 @@ def set_test_whitelist(self, openids=None, usernames=None): openids = openids or [] usernames = usernames or [] return self._post( - 'card/testwhitelist/set', - data={ - 'openid': openids, - 'username': usernames - } + "card/testwhitelist/set", data={"openid": openids, "username": usernames} ) def activate_membercard(self, membership_number, code, **kwargs): @@ -282,12 +216,9 @@ def activate_membercard(self, membership_number, code, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “6 激活会员卡” 部分 :return: 参见返回示例 """ - kwargs['membership_number'] = membership_number - kwargs['code'] = code - return self._post( - 'card/membercard/activate', - data=kwargs - ) + kwargs["membership_number"] = membership_number + kwargs["code"] = code + return self._post("card/membercard/activate", data=kwargs) def update_membercard(self, code, card_id, **kwargs): """ @@ -334,14 +265,13 @@ def update_membercard(self, code, card_id, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “7 更新会员信息” 部分 :return: 参见返回示例 """ - kwargs.update({ - 'code': code, - 'card_id': card_id, - }) - return self._post( - 'card/membercard/updateuser', - data=kwargs + kwargs.update( + { + "code": code, + "card_id": card_id, + } ) + return self._post("card/membercard/updateuser", data=kwargs) def get_membercard_user_info(self, card_id, code): """ @@ -354,10 +284,10 @@ def get_membercard_user_info(self, card_id, code): :return: 会员信息,包括激活资料、积分信息以及余额等信息 """ return self._post( - 'card/membercard/userinfo/get', + "card/membercard/userinfo/get", data={ - 'card_id': card_id, - 'code': code, + "card_id": card_id, + "code": code, }, ) @@ -376,20 +306,20 @@ def add_pay_giftcard(self, base_info, extra_info, is_membercard): :return: 规则 ID, 设置成功的列表,以及设置失败的列表 """ if is_membercard: - rule_key = 'member_rule' - rule_type = 'RULE_TYPE_PAY_MEMBER_CARD' + rule_key = "member_rule" + rule_type = "RULE_TYPE_PAY_MEMBER_CARD" else: - rule_key = 'single_pay' - rule_type = 'RULE_TYPE_SINGLE_PAY' + rule_key = "single_pay" + rule_type = "RULE_TYPE_SINGLE_PAY" return self._post( - 'card/paygiftcard/add', + "card/paygiftcard/add", data={ - 'rule_info': { - 'type': rule_type, - 'base_info': base_info, + "rule_info": { + "type": rule_type, + "base_info": base_info, rule_key: extra_info, } - } + }, ) def del_pay_giftcard(self, rule_id): @@ -401,9 +331,9 @@ def del_pay_giftcard(self, rule_id): :param rule_id: 支付即会员的规则 ID """ return self._post( - 'card/paygiftcard/delete', + "card/paygiftcard/delete", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, ) @@ -418,11 +348,11 @@ def get_pay_giftcard(self, rule_id): :rtype: dict """ return self._post( - 'card/paygiftcard/getbyid', + "card/paygiftcard/getbyid", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, - result_processor=lambda x: x['rule_info'], + result_processor=lambda x: x["rule_info"], ) def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): @@ -441,75 +371,81 @@ def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): :return: 支付后投放卡券规则的总数,以及查询到的列表 """ return self._post( - 'card/paygiftcard/batchget', + "card/paygiftcard/batchget", data={ - 'type': 'RULE_TYPE_PAY_MEMBER_CARD', - 'effective': effective, - 'offset': offset, - 'count': count, + "type": "RULE_TYPE_PAY_MEMBER_CARD", + "effective": effective, + "offset": offset, + "count": count, }, ) - def update_movie_ticket(self, code, ticket_class, show_time, duration, - screening_room, seat_number, card_id=None): + def update_movie_ticket( + self, + code, + ticket_class, + show_time, + duration, + screening_room, + seat_number, + card_id=None, + ): """ 更新电影票 """ ticket = { - 'code': code, - 'ticket_class': ticket_class, - 'show_time': show_time, - 'duration': duration, - 'screening_room': screening_room, - 'seat_number': seat_number + "code": code, + "ticket_class": ticket_class, + "show_time": show_time, + "duration": duration, + "screening_room": screening_room, + "seat_number": seat_number, } if card_id: - ticket['card_id'] = card_id - return self._post( - 'card/movieticket/updateuser', - data=ticket - ) - - def checkin_boardingpass(self, code, passenger_name, seat_class, - etkt_bnr, seat='', gate='', boarding_time=None, - is_cancel=False, qrcode_data=None, card_id=None): + ticket["card_id"] = card_id + return self._post("card/movieticket/updateuser", data=ticket) + + def checkin_boardingpass( + self, + code, + passenger_name, + seat_class, + etkt_bnr, + seat="", + gate="", + boarding_time=None, + is_cancel=False, + qrcode_data=None, + card_id=None, + ): """ 飞机票接口 """ data = { - 'code': code, - 'passenger_name': passenger_name, - 'class': seat_class, - 'etkt_bnr': etkt_bnr, - 'seat': seat, - 'gate': gate, - 'is_cancel': is_cancel + "code": code, + "passenger_name": passenger_name, + "class": seat_class, + "etkt_bnr": etkt_bnr, + "seat": seat, + "gate": gate, + "is_cancel": is_cancel, } if boarding_time: - data['boarding_time'] = boarding_time + data["boarding_time"] = boarding_time if qrcode_data: - data['qrcode_data'] = qrcode_data + data["qrcode_data"] = qrcode_data if card_id: - data['card_id'] = card_id - return self._post( - 'card/boardingpass/checkin', - data=data - ) + data["card_id"] = card_id + return self._post("card/boardingpass/checkin", data=data) def update_luckymoney_balance(self, code, balance, card_id=None): """ 更新红包余额 """ - card_data = { - 'code': code, - 'balance': balance - } + card_data = {"code": code, "balance": balance} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/luckymoney/updateuserbalance', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/luckymoney/updateuserbalance", data=card_data) def get_redirect_url(self, url, encrypt_code, card_id): """ @@ -525,51 +461,33 @@ def get_redirect_url(self, url, encrypt_code, card_id): signer.add_data(card_id) signature = signer.signature - r = '{url}?encrypt_code={code}&card_id={card_id}&signature={signature}' + r = "{url}?encrypt_code={code}&card_id={card_id}&signature={signature}" return r.format( - url=url, - code=encrypt_code, - card_id=card_id, - signature=signature + url=url, code=encrypt_code, card_id=card_id, signature=signature ) def deposit_code(self, card_id, codes): """ 导入code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/deposit', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/deposit", data=card_data) def get_deposit_count(self, card_id): """ 查询导入code数目 """ card_data = { - 'card_id': card_id, + "card_id": card_id, } - return self._post( - 'card/code/getdepositcount', - data=card_data - ) + return self._post("card/code/getdepositcount", data=card_data) def check_code(self, card_id, codes): """ 核查code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/checkcode', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/checkcode", data=card_data) def modify_stock(self, card_id, n): """ @@ -578,16 +496,13 @@ def modify_stock(self, card_id, n): if n == 0: return card_data = { - 'card_id': card_id, + "card_id": card_id, } if n > 0: - card_data['increase_stock_value'] = n + card_data["increase_stock_value"] = n elif n < 0: - card_data['reduce_stock_value'] = -n - return self._post( - 'card/modifystock', - data=card_data - ) + card_data["reduce_stock_value"] = -n + return self._post("card/modifystock", data=card_data) def get_activate_url(self, card_id, outer_str=None): """ @@ -600,12 +515,12 @@ def get_activate_url(self, card_id, outer_str=None): :return: 内含调用开卡插件所需的参数的 Url """ return self._post( - 'card/membercard/activate/geturl', + "card/membercard/activate/geturl", data={ - 'card_id': card_id, - 'outer_str': outer_str, + "card_id": card_id, + "outer_str": outer_str, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_activate_info(self, activate_ticket): @@ -618,11 +533,11 @@ def get_activate_info(self, activate_ticket): :return: 用户开卡时填写的字段值 """ return self._post( - 'card/membercard/activatetempinfo/get', + "card/membercard/activatetempinfo/get", data={ - 'activate_ticket': activate_ticket, + "activate_ticket": activate_ticket, }, - result_processor=lambda x: x['info'], + result_processor=lambda x: x["info"], ) def set_activate_user_form(self, card_id, **kwargs): @@ -693,8 +608,5 @@ def set_activate_user_form(self, card_id, **kwargs): :param card_id: 卡券ID :param kwargs: 其他非必填参数,见微信文档 """ - kwargs['card_id'] = card_id - return self._post( - 'card/membercard/activateuserform/set', - data=kwargs - ) + kwargs["card_id"] = card_id + return self._post("card/membercard/activateuserform/set", data=kwargs) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/customservice.py b/chapter13/booking_system/exts/wechatpy/client/api/customservice.py index a5c2471..89d0cc4 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/customservice.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/customservice.py @@ -26,12 +26,8 @@ def add_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/add', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/add", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def update_account(self, account, nickname, password): @@ -48,12 +44,8 @@ def update_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/update', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/update", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def delete_account(self, account): @@ -66,13 +58,12 @@ def delete_account(self, account): :return: 返回的 JSON 数据包 """ params_data = [ - 'access_token={0}'.format(quote(self.access_token)), - 'kf_account={0}'.format(quote(to_binary(account), safe=b'/@')), + "access_token={0}".format(quote(self.access_token)), + "kf_account={0}".format(quote(to_binary(account), safe=b"/@")), ] - params = '&'.join(params_data) + params = "&".join(params_data) return self._get( - 'https://api.weixin.qq.com/customservice/kfaccount/del', - params=params + "https://api.weixin.qq.com/customservice/kfaccount/del", params=params ) def get_accounts(self): @@ -84,8 +75,7 @@ def get_accounts(self): :return: 客服账号列表 """ res = self._get( - 'customservice/getkflist', - result_processor=lambda x: x['kf_list'] + "customservice/getkflist", result_processor=lambda x: x["kf_list"] ) return res @@ -100,13 +90,9 @@ def upload_headimg(self, account, media_file): :return: 返回的 JSON 数据包 """ return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg', - params={ - 'kf_account': account - }, - files={ - 'media': media_file - } + "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg", + params={"kf_account": account}, + files={"media": media_file}, ) def get_online_accounts(self): @@ -118,8 +104,8 @@ def get_online_accounts(self): :return: 客服接待信息列表 """ res = self._get( - 'customservice/getonlinekflist', - result_processor=lambda x: x['kf_online_list'] + "customservice/getonlinekflist", + result_processor=lambda x: x["kf_online_list"], ) return res @@ -134,14 +120,9 @@ def create_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/create', - data=data + "https://api.weixin.qq.com/customservice/kfsession/create", data=data ) def close_session(self, openid, account, text=None): @@ -155,14 +136,9 @@ def close_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/close', - data=data + "https://api.weixin.qq.com/customservice/kfsession/close", data=data ) def get_session(self, openid): @@ -175,8 +151,8 @@ def get_session(self, openid): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsession', - params={'openid': openid} + "https://api.weixin.qq.com/customservice/kfsession/getsession", + params={"openid": openid}, ) def get_session_list(self, account): @@ -189,9 +165,9 @@ def get_session_list(self, account): :return: 客服的会话列表 """ res = self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsessionlist', - params={'kf_account': account}, - result_processor=lambda x: x['sessionlist'] + "https://api.weixin.qq.com/customservice/kfsession/getsessionlist", + params={"kf_account": account}, + result_processor=lambda x: x["sessionlist"], ) return res @@ -204,11 +180,10 @@ def get_wait_case(self): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getwaitcase' + "https://api.weixin.qq.com/customservice/kfsession/getwaitcase" ) - def get_records(self, start_time, end_time, msgid=1, - number=10000): + def get_records(self, start_time, end_time, msgid=1, number=10000): """ 获取客服聊天记录 @@ -224,13 +199,13 @@ def get_records(self, start_time, end_time, msgid=1, if isinstance(end_time, datetime.datetime): end_time = time.mktime(end_time.timetuple()) record_data = { - 'starttime': int(start_time), - 'endtime': int(end_time), - 'msgid': msgid, - 'number': number + "starttime": int(start_time), + "endtime": int(end_time), + "msgid": msgid, + "number": number, } res = self._post( - 'https://api.weixin.qq.com/customservice/msgrecord/getmsglist', + "https://api.weixin.qq.com/customservice/msgrecord/getmsglist", data=record_data, ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/datacube.py b/chapter13/booking_system/exts/wechatpy/client/api/datacube.py index ef80f89..d4fafac 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/datacube.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/datacube.py @@ -9,16 +9,16 @@ class WeChatDataCube(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/datacube/' + API_BASE_URL = "https://api.weixin.qq.com/datacube/" @classmethod def _to_date_str(cls, date): if isinstance(date, (datetime.datetime, datetime.date)): - return date.strftime('%Y-%m-%d') + return date.strftime("%Y-%m-%d") elif isinstance(date, six.string_types): return date else: - raise ValueError('Can not convert %s type to str', type(date)) + raise ValueError("Can not convert %s type to str", type(date)) def get_user_summary(self, begin_date, end_date): """ @@ -31,13 +31,13 @@ def get_user_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersummary', + "getusersummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) - } + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), + }, ) - return res['list'] + return res["list"] def get_user_cumulate(self, begin_date, end_date): """ @@ -50,12 +50,12 @@ def get_user_cumulate(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusercumulate', + "getusercumulate", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -70,12 +70,12 @@ def get_interface_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummary', + "getinterfacesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -90,12 +90,12 @@ def get_interface_summary_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummaryhour', + "getinterfacesummaryhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -110,12 +110,12 @@ def get_article_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticlesummary', + "getarticlesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -130,12 +130,12 @@ def get_article_total(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticletotal', + "getarticletotal", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -150,12 +150,12 @@ def get_user_read(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserread', + "getuserread", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -170,12 +170,12 @@ def get_user_read_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserreadhour', + "getuserreadhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -190,12 +190,12 @@ def get_user_share(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusershare', + "getusershare", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -210,12 +210,12 @@ def get_user_share_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersharehour', + "getusersharehour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -230,12 +230,12 @@ def get_upstream_msg(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsg', + "getupstreammsg", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -250,12 +250,12 @@ def get_upstream_msg_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsghour', + "getupstreammsghour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -270,12 +270,12 @@ def get_upstream_msg_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgweek', + "getupstreammsgweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -290,12 +290,12 @@ def get_upstream_msg_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgmonth', + "getupstreammsgmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -310,12 +310,12 @@ def get_upstream_msg_dist(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdist', + "getupstreammsgdist", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -330,12 +330,12 @@ def get_upstream_msg_dist_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistweek', + "getupstreammsgdistweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -350,11 +350,11 @@ def get_upstream_msg_dist_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistmonth', + "getupstreammsgdistmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/device.py b/chapter13/booking_system/exts/wechatpy/client/api/device.py index 01aecb2..be27851 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/device.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/device.py @@ -9,7 +9,7 @@ class WeChatDevice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/device/' + API_BASE_URL = "https://api.weixin.qq.com/device/" def send_message(self, device_type, device_id, user_id, content): """ @@ -25,16 +25,18 @@ def send_message(self, device_type, device_id, user_id, content): """ content = to_text(base64.b64encode(to_binary(content))) return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'content': content - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "content": content, + }, ) - def send_status_message(self, device_type, device_id, user_id, msg_type, device_status): + def send_status_message( + self, device_type, device_id, user_id, msg_type, device_status + ): """ 第三方主动发送设备状态消息给微信终端 详情请参考 @@ -48,14 +50,14 @@ def send_status_message(self, device_type, device_id, user_id, msg_type, device_ :return: 返回的 JSON 数据包 """ return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'msg_type': msg_type, - 'device_status': device_status, - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "msg_type": msg_type, + "device_status": device_status, + }, ) def create_qrcode(self, device_ids): @@ -68,11 +70,8 @@ def create_qrcode(self, device_ids): :return: 返回的 JSON 数据包 """ return self._post( - 'create_qrcode', - data={ - 'device_num': len(device_ids), - 'device_id_list': device_ids - } + "create_qrcode", + data={"device_num": len(device_ids), "device_id_list": device_ids}, ) def get_qrcode_url(self, ticket, data=None): @@ -85,12 +84,12 @@ def get_qrcode_url(self, ticket, data=None): :param data: 额外数据 :return: 二维码地址 """ - url = 'https://we.qq.com/d/{ticket}'.format(ticket=ticket) + url = "https://we.qq.com/d/{ticket}".format(ticket=ticket) if data: if isinstance(data, (dict, tuple, list)): data = urllib.urlencode(data) data = to_text(base64.b64encode(to_binary(data))) - url = '{base}#{data}'.format(base=url, data=data) + url = "{base}#{data}".format(base=url, data=data) return url def bind(self, ticket, device_id, user_id): @@ -105,12 +104,7 @@ def bind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'bind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "bind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def unbind(self, ticket, device_id, user_id): @@ -125,12 +119,7 @@ def unbind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'unbind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "unbind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def compel_bind(self, device_id, user_id): @@ -144,11 +133,7 @@ def compel_bind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_bind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_bind", data={"device_id": device_id, "openid": user_id} ) force_bind = compel_bind @@ -164,11 +149,7 @@ def compel_unbind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_unbind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_unbind", data={"device_id": device_id, "openid": user_id} ) force_unbind = compel_unbind @@ -182,10 +163,7 @@ def get_stat(self, device_id): :param device_id: 设备id :return: 返回的 JSON 数据包 """ - return self._get( - 'get_stat', - params={'device_id': device_id} - ) + return self._get("get_stat", params={"device_id": device_id}) def verify_qrcode(self, ticket): """ @@ -196,10 +174,7 @@ def verify_qrcode(self, ticket): :param ticket: 设备二维码的ticket :return: 返回的 JSON 数据包 """ - return self._post( - 'verify_qrcode', - data={'ticket': ticket} - ) + return self._post("verify_qrcode", data={"ticket": ticket}) def get_user_id(self, device_type, device_id): """ @@ -212,11 +187,7 @@ def get_user_id(self, device_type, device_id): :return: 返回的 JSON 数据包 """ return self._get( - 'get_openid', - params={ - 'device_type': device_type, - 'device_id': device_id - } + "get_openid", params={"device_type": device_type, "device_id": device_id} ) get_open_id = get_user_id @@ -230,10 +201,7 @@ def get_binded_devices(self, user_id): :param user_id: 要查询的用户的openid :return: 返回的 JSON 数据包 """ - return self._get( - 'get_bind_device', - params={'openid': user_id} - ) + return self._get("get_bind_device", params={"openid": user_id}) get_bind_device = get_binded_devices @@ -246,12 +214,12 @@ def get_qrcode(self, product_id=1): :param product_id: 设备的产品编号 :return: 返回的 JSON 数据包 """ - if product_id == '1' or product_id == 1: + if product_id == "1" or product_id == 1: params = None else: - params = {'product_id': product_id} + params = {"product_id": product_id} - return self._get('getqrcode', params=params) + return self._get("getqrcode", params=params) def authorize(self, devices, op_type=1): """ @@ -264,10 +232,10 @@ def authorize(self, devices, op_type=1): :return: 返回的 JSON 数据包 """ return self._post( - 'authorize_device', + "authorize_device", data={ - 'device_num': len(devices), - 'device_list': devices, - 'op_type': op_type - } + "device_num": len(devices), + "device_list": devices, + "op_type": op_type, + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/group.py b/chapter13/booking_system/exts/wechatpy/client/api/group.py index a3e5927..6dc4e94 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/group.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/group.py @@ -26,10 +26,7 @@ def create(self, name): """ name = to_text(name) - return self._post( - 'groups/create', - data={'group': {'name': name}} - ) + return self._post("groups/create", data={"group": {"name": name}}) def get(self, user_id=None): """ @@ -50,15 +47,12 @@ def get(self, user_id=None): """ if user_id is None: - res = self._get( - 'groups/get', - result_processor=lambda x: x['groups'] - ) + res = self._get("groups/get", result_processor=lambda x: x["groups"]) else: res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -83,13 +77,7 @@ def update(self, group_id, name): """ name = to_text(name) return self._post( - 'groups/update', - data={ - 'group': { - 'id': int(group_id), - 'name': name - } - } + "groups/update", data={"group": {"id": int(group_id), "name": name}} ) def move_user(self, user_id, group_id): @@ -111,13 +99,13 @@ def move_user(self, user_id, group_id): res = client.group.move_user('openid', 1234) """ - data = {'to_groupid': group_id} + data = {"to_groupid": group_id} if isinstance(user_id, (tuple, list)): - endpoint = 'groups/members/batchupdate' - data['openid_list'] = user_id + endpoint = "groups/members/batchupdate" + data["openid_list"] = user_id else: - endpoint = 'groups/members/update' - data['openid'] = user_id + endpoint = "groups/members/update" + data["openid"] = user_id return self._post(endpoint, data=data) def delete(self, group_id): @@ -138,11 +126,4 @@ def delete(self, group_id): res = client.group.delete(1234) """ - return self._post( - 'groups/delete', - data={ - 'group': { - 'id': group_id - } - } - ) + return self._post("groups/delete", data={"group": {"id": group_id}}) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/invoice.py b/chapter13/booking_system/exts/wechatpy/client/api/invoice.py index f0182d5..b2808c2 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/invoice.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/invoice.py @@ -5,7 +5,7 @@ class WeChatInvoice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/card/invoice/' + API_BASE_URL = "https://api.weixin.qq.com/card/invoice/" def get_url(self): """ @@ -16,9 +16,9 @@ def get_url(self): :return:该开票平台专用的授权链接 """ return self._post( - 'seturl', + "seturl", data={}, - result_processor=lambda x: x['invoice_url'], + result_processor=lambda x: x["invoice_url"], ) def create_card(self, base_info, payee, invoice_type, detail=None): @@ -36,19 +36,29 @@ def create_card(self, base_info, payee, invoice_type, detail=None): :return: 发票卡券模板的编号,用于后续该商户发票生成后,作为必填参数在调用插卡接口时传入 """ return self._post( - 'platform/createcard', + "platform/createcard", data={ - 'invoice_info': { - 'base_info': base_info, - 'payee': payee, - 'type': invoice_type, - 'detail': detail, + "invoice_info": { + "base_info": base_info, + "payee": payee, + "type": invoice_type, + "detail": detail, }, }, - result_processor=lambda x: x['card_id'], + result_processor=lambda x: x["card_id"], ) - def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, auth_type, redirect_url=None): + def get_auth_url( + self, + s_pappid, + order_id, + money, + timestamp, + source, + ticket, + auth_type, + redirect_url=None, + ): """ 获取授权页链接 详情请参考 @@ -67,25 +77,27 @@ def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, aut :param redirect_url: 授权成功后跳转页面。本字段只有在source为H5的时候需要填写。 :return: 获取授权页链接 """ - if source not in {'app', 'web', 'wap'}: - raise ValueError('Unsupported source. Valid sources are "app", "web" or "wap"') - if source == 'web' and redirect_url is None: - raise ValueError('redirect_url is required if source is web') + if source not in {"app", "web", "wap"}: + raise ValueError( + 'Unsupported source. Valid sources are "app", "web" or "wap"' + ) + if source == "web" and redirect_url is None: + raise ValueError("redirect_url is required if source is web") if not (0 <= auth_type <= 2): - raise ValueError('Unsupported auth type. Valid auth types are 0, 1 or 2') + raise ValueError("Unsupported auth type. Valid auth types are 0, 1 or 2") return self._post( - 'getauthurl', + "getauthurl", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'money': money, - 'timestamp': timestamp, - 'source': source, - 'ticket': ticket, - 'type': auth_type, - 'redirect_url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "money": money, + "timestamp": timestamp, + "source": source, + "ticket": ticket, + "type": auth_type, + "redirect_url": redirect_url, }, - result_processor=lambda x: x['auth_url'], + result_processor=lambda x: x["auth_url"], ) def set_auth_field(self, user_field, biz_field): @@ -100,14 +112,14 @@ def set_auth_field(self, user_field, biz_field): :type biz_field: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_auth_field', + "action": "set_auth_field", }, data={ - 'auth_field': { - 'user_field': user_field, - 'biz_field': biz_field, + "auth_field": { + "user_field": user_field, + "biz_field": biz_field, }, }, ) @@ -122,9 +134,9 @@ def get_auth_field(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_auth_field', + "action": "get_auth_field", }, data={}, ) @@ -141,10 +153,10 @@ def get_auth_data(self, s_pappid, order_id): :rtype: dict """ return self._post( - 'getauthdata', + "getauthdata", data={ - 's_pappid': s_pappid, - 'order_id': order_id, + "s_pappid": s_pappid, + "order_id": order_id, }, ) @@ -160,12 +172,12 @@ def reject_insert(self, s_pappid, order_id, reason, redirect_url=None): :param redirect_url: 跳转链接 """ return self._post( - 'rejectinsert', + "rejectinsert", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'reason': reason, - 'url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "reason": reason, + "url": redirect_url, }, ) @@ -183,12 +195,12 @@ def insert(self, order_id, card_id, appid, card_ext): :return: 随机防重字符串,以及用户 Open ID """ return self._post( - 'insert', + "insert", data={ - 'order_id': order_id, - 'card_id': card_id, - 'appid': appid, - 'card_ext': card_ext, + "order_id": order_id, + "card_id": card_id, + "appid": appid, + "card_ext": card_ext, }, ) @@ -202,11 +214,11 @@ def upload_pdf(self, pdf): :return: 64位整数,在将发票卡券插入用户卡包时使用用于关联pdf和发票卡券。有效期为3天。 """ return self._post( - 'platform/setpdf', + "platform/setpdf", files={ - 'pdf': pdf, + "pdf": pdf, }, - result_processor=lambda x: x['s_media_id'], + result_processor=lambda x: x["s_media_id"], ) def get_pdf(self, s_media_id): @@ -220,12 +232,12 @@ def get_pdf(self, s_media_id): :rtype: dict """ return self._post( - 'platform/getpdf', + "platform/getpdf", params={ - 'action': 'get_url', + "action": "get_url", }, data={ - 's_media_id': s_media_id, + "s_media_id": s_media_id, }, ) @@ -240,11 +252,11 @@ def update_status(self, card_id, code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'platform/updatestatus', + "platform/updatestatus", data={ - 'card_id': card_id, - 'code': code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "code": code, + "reimburse_status": reimburse_status, }, ) @@ -258,14 +270,14 @@ def set_pay_mch(self, mchid, s_pappid): :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供 """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_pay_mch', + "action": "set_pay_mch", }, data={ - 'paymch_info': { - 'mchid': mchid, - 's_pappid': s_pappid, + "paymch_info": { + "mchid": mchid, + "s_pappid": s_pappid, }, }, ) @@ -280,9 +292,9 @@ def get_pay_mch(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_pay_mch', + "action": "get_pay_mch", }, data={}, ) @@ -299,10 +311,10 @@ def get_reimburse(self, card_id, encrypt_code): :rtype: dict """ return self._post( - 'reimburse/getinvoiceinfo', + "reimburse/getinvoiceinfo", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, + "card_id": card_id, + "encrypt_code": encrypt_code, }, ) @@ -317,11 +329,11 @@ def update_reimburse(self, card_id, encrypt_code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'reimburse/updateinvoicestatus', + "reimburse/updateinvoicestatus", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "encrypt_code": encrypt_code, + "reimburse_status": reimburse_status, }, ) @@ -337,17 +349,25 @@ def batch_update_reimburse(self, openid, reimburse_status, invoice_list): :type invoice_list: list[dict] """ return self._post( - 'reimburse/updatestatusbatch', + "reimburse/updatestatusbatch", data={ - 'openid': openid, - 'reimburse_status': reimburse_status, - 'invoice_list': invoice_list, + "openid": openid, + "reimburse_status": reimburse_status, + "invoice_list": invoice_list, }, ) def get_user_title_url( - self, user_fill, title=None, phone=None, tax_no=None, addr=None, bank_type=None, bank_no=None, - out_title_id=None): + self, + user_fill, + title=None, + phone=None, + tax_no=None, + addr=None, + bank_type=None, + bank_no=None, + out_title_id=None, + ): """ 获取添加发票链接 获取链接,发送给用户。用户同意以后,发票抬头信息将会录入到用户微信中 @@ -366,20 +386,20 @@ def get_user_title_url( :return: 添加发票的链接 """ if user_fill and title is None: - raise ValueError('title is required when user_fill is False') + raise ValueError("title is required when user_fill is False") return self._post( - 'biz/getusertitleurl', + "biz/getusertitleurl", data={ - 'user_fill': int(user_fill), - 'title': title, - 'phone': phone, - 'tax_no': tax_no, - 'addr': addr, - 'bank_type': bank_type, - 'bank_no': bank_no, - 'out_title_id': out_title_id, + "user_fill": int(user_fill), + "title": title, + "phone": phone, + "tax_no": tax_no, + "addr": addr, + "bank_type": bank_type, + "bank_no": bank_no, + "out_title_id": out_title_id, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_select_title_url(self, attach=None): @@ -393,11 +413,11 @@ def get_select_title_url(self, attach=None): :return: 商户专属开票链接 """ return self._post( - 'biz/getselecttitleurl', + "biz/getselecttitleurl", data={ - 'attach': attach, + "attach": attach, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def scan_title(self, scan_text): @@ -412,8 +432,8 @@ def scan_title(self, scan_text): :rtype: dict """ return self._post( - 'scantitle', + "scantitle", data={ - 'scan_text': scan_text, + "scan_text": scan_text, }, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/jsapi.py b/chapter13/booking_system/exts/wechatpy/client/api/jsapi.py index 0bbcd5c..d7db0b9 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/jsapi.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/jsapi.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.client.jsapi - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.client.jsapi +~~~~~~~~~~~~~~~~~~~~ - This module provides some APIs for JS SDK +This module provides some APIs for JS SDK - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -19,16 +19,13 @@ class WeChatJSAPI(BaseWeChatAPI): - def get_ticket(self, type='jsapi'): + def get_ticket(self, type="jsapi"): """ 获取微信 JS-SDK ticket :return: 返回的 JSON 数据包 """ - return self._get( - 'ticket/getticket', - params={'type': type} - ) + return self._get("ticket/getticket", params={"type": type}) def get_jsapi_ticket(self): """ @@ -38,14 +35,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{0}_jsapi_ticket'.format(self.appid) - expires_at_key = '{0}_jsapi_ticket_expires_at'.format(self.appid) + ticket_key = "{0}_jsapi_ticket".format(self.appid) + expires_at_key = "{0}_jsapi_ticket_expires_at".format(self.appid) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): - jsapi_ticket_response = self.get_ticket('jsapi') - ticket = jsapi_ticket_response['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket_response['expires_in']) + jsapi_ticket_response = self.get_ticket("jsapi") + ticket = jsapi_ticket_response["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket_response["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -61,12 +58,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -78,15 +75,17 @@ def get_jsapi_card_ticket(self): :return: ticket """ - jsapi_card_ticket_key = '{0}_jsapi_card_ticket'.format(self.appid) - jsapi_card_ticket_expire_at_key = '{0}_jsapi_card_ticket_expires_at'.format(self.appid) + jsapi_card_ticket_key = "{0}_jsapi_card_ticket".format(self.appid) + jsapi_card_ticket_expire_at_key = "{0}_jsapi_card_ticket_expires_at".format( + self.appid + ) ticket = self.session.get(jsapi_card_ticket_key) expires_at = self.session.get(jsapi_card_ticket_expire_at_key, 0) if not ticket or int(expires_at) < int(time.time()): - ticket_response = self.get_ticket('wx_card') - ticket = ticket_response['ticket'] - expires_at = int(time.time()) + int(ticket_response['expires_in']) + ticket_response = self.get_ticket("wx_card") + ticket = ticket_response["ticket"] + expires_at = int(time.time()) + int(ticket_response["expires_in"]) self.session.set(jsapi_card_ticket_key, ticket) self.session.set(jsapi_card_ticket_expire_at_key, expires_at) return ticket @@ -95,18 +94,18 @@ def get_jsapi_card_params(self, card_ticket, card_type, **kwargs): """ 参数意义见微信文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html :param card_ticket: 用于卡券的微信 api_ticket - :param card_type: + :param card_type: :param kwargs: 非必须参数:noncestr, timestamp, code, openid, fixed_begintimestamp, outer_str :return: 包含调用jssdk所有所需参数的 dict """ card_signature_dict = { - 'card_type': card_type, - 'noncestr': kwargs.get('noncestr', random_string()), - 'api_ticket': card_ticket, - 'appid': self.appid, - 'timestamp': kwargs.get('timestamp', str(int(time.time()))), + "card_type": card_type, + "noncestr": kwargs.get("noncestr", random_string()), + "api_ticket": card_ticket, + "appid": self.appid, + "timestamp": kwargs.get("timestamp", str(int(time.time()))), } list_before_sign = sorted([str(x) for x in card_signature_dict.values()]) str_to_sign = "".join(list_before_sign).encode() - card_signature_dict['sign'] = hashlib.sha1(str_to_sign).hexdigest() + card_signature_dict["sign"] = hashlib.sha1(str_to_sign).hexdigest() return card_signature_dict diff --git a/chapter13/booking_system/exts/wechatpy/client/api/marketing.py b/chapter13/booking_system/exts/wechatpy/client/api/marketing.py index 4aa9461..5192f8a 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/marketing.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/marketing.py @@ -10,9 +10,9 @@ class WeChatMarketing(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/marketing/' + API_BASE_URL = "https://api.weixin.qq.com/marketing/" - def add_user_action_sets(self, _type, name, description, version='v1.0'): + def add_user_action_sets(self, _type, name, description, version="v1.0"): """ 创建数据源 https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 @@ -24,18 +24,15 @@ def add_user_action_sets(self, _type, name, description, version='v1.0'): :return: 数据源唯一ID """ return self._post( - 'user_action_sets/add', - params={'version': version}, + "user_action_sets/add", + params={"version": version}, json=optionaldict( - type=_type, - name=name, - description=description, - version=version + type=_type, name=name, description=description, version=version ), - result_processor=lambda x: x['data']['user_action_set_id'] + result_processor=lambda x: x["data"]["user_action_set_id"], ) - def get_user_action_sets(self, user_action_set_id, version='v1.0'): + def get_user_action_sets(self, user_action_set_id, version="v1.0"): """ 获取数据源信息 @@ -43,12 +40,12 @@ def get_user_action_sets(self, user_action_set_id, version='v1.0'): :param version: 版本号 v1.0 """ return self._get( - 'user_action_sets/get', - params={'version': version, 'user_action_set_id': user_action_set_id}, - result_processor=lambda x: x['data']['list'] + "user_action_sets/get", + params={"version": version, "user_action_set_id": user_action_set_id}, + result_processor=lambda x: x["data"]["list"], ) - def add_user_actions(self, actions=(), version='v1.0'): + def add_user_actions(self, actions=(), version="v1.0"): """ 回传数据 @@ -58,12 +55,18 @@ def add_user_actions(self, actions=(), version='v1.0'): :param version: 版本号 v1.0 """ return self._post( - 'user_actions/add', - params={'version': version}, - json={'actions': actions} + "user_actions/add", params={"version": version}, json={"actions": actions} ) - def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, page_size=100, version='v1.0'): + def get_ad_leads( + self, + start_date=None, + end_date=None, + filtering=(), + page=1, + page_size=100, + version="v1.0", + ): """ 获取朋友圈销售线索数据接口 @@ -85,13 +88,13 @@ def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, pag end_date = end_date.strftime("%Y-%m-%d") return self._get( - 'wechat_ad_leads/get', + "wechat_ad_leads/get", params=optionaldict( - date_range=json.dumps({'start_date': start_date, 'end_date': end_date}), + date_range=json.dumps({"start_date": start_date, "end_date": end_date}), filtering=json.dumps(filtering) if filtering else None, page=page, page_size=page_size, - version=version + version=version, ), - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/material.py b/chapter13/booking_system/exts/wechatpy/client/api/material.py index 9754776..af2b40e 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/material.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/material.py @@ -18,23 +18,22 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0), - 'need_open_comment': int(article.get('need_open_comment', False)), - 'only_fans_can_comment': int(article.get('only_fans_can_comment', False)), - }) - return self._post( - 'material/add_news', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + "need_open_comment": int(article.get("need_open_comment", False)), + "only_fans_can_comment": int( + article.get("only_fans_can_comment", False) + ), + } + ) + return self._post("material/add_news", data={"articles": articles_data}) def add(self, media_type, media_file, title=None, introduction=None): """ @@ -48,24 +47,14 @@ def add(self, media_type, media_file, title=None, introduction=None): :param introduction: 视频素材简介,仅上传视频素材时需要 :return: 返回的 JSON 数据包 """ - params = { - 'access_token': self.access_token, - 'type': media_type - } - if media_type == 'video': - assert title, 'Video title must be set' - assert introduction, 'Video introduction must be set' - description = { - 'title': title, - 'introduction': introduction - } - params['description'] = json.dumps(description) + params = {"access_token": self.access_token, "type": media_type} + if media_type == "video": + assert title, "Video title must be set" + assert introduction, "Video introduction must be set" + description = {"title": title, "introduction": introduction} + params["description"] = json.dumps(description) return self._post( - 'material/add_material', - params=params, - files={ - 'media': media_file - } + "material/add_material", params=params, files={"media": media_file} ) def get(self, media_id): @@ -77,19 +66,18 @@ def get(self, media_id): :param media_id: 素材的 media_id :return: 图文素材返回图文列表,其它类型为素材的内容 """ + def _processor(res): if isinstance(res, dict): - if 'news_item' in res: + if "news_item" in res: # 图文素材 - return res['news_item'] + return res["news_item"] return res res = self._post( - 'material/get_material', - data={ - 'media_id': media_id - }, - result_processor=_processor + "material/get_material", + data={"media_id": media_id}, + result_processor=_processor, ) return res @@ -102,12 +90,7 @@ def delete(self, media_id): :param media_id: 素材的 media_id :return: 返回的 JSON 数据包 """ - return self._post( - 'material/del_material', - data={ - 'media_id': media_id - } - ) + return self._post("material/del_material", data={"media_id": media_id}) def update_article(self, media_id, index, article): """ @@ -121,21 +104,17 @@ def update_article(self, media_id, index, article): :return: 返回的 JSON 数据包 """ article_data = { - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } return self._post( - 'material/update_news', - data={ - 'media_id': media_id, - 'index': index, - 'articles': article_data - } + "material/update_news", + data={"media_id": media_id, "index": index, "articles": article_data}, ) def update_articles(self, media_id, index, articles): @@ -163,12 +142,8 @@ def batchget(self, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget_material', - data={ - 'type': media_type, - 'offset': offset, - 'count': count - } + "material/batchget_material", + data={"type": media_type, "offset": offset, "count": count}, ) def get_count(self): @@ -179,7 +154,7 @@ def get_count(self): :return: 返回的 JSON 数据包 """ - return self._get('material/get_materialcount') + return self._get("material/get_materialcount") def open_comment(self, msg_data_id, index=1): """ @@ -187,94 +162,102 @@ def open_comment(self, msg_data_id, index=1): https://mp.weixin.qq.com/wiki?id=mp1494572718_WzHIY """ return self._post( - 'comment/open', + "comment/open", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def close_comment(self, msg_data_id, index=1): """ 关闭已群发文章评论 """ return self._post( - 'comment/close', + "comment/close", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def list_comment(self, msg_data_id, index=1, begin=0, count=50, type=0): """ 查看指定文章的评论数据 """ return self._post( - 'comment/list', + "comment/list", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'begin': begin, - 'count': count, - 'type': type - }) + "msg_data_id": msg_data_id, + "index": index, + "begin": begin, + "count": count, + "type": type, + }, + ) def markelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论标记精选 """ return self._post( - 'comment/markelect', + "comment/markelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def unmarkelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论取消精选 """ return self._post( - 'comment/unmarkelect', + "comment/unmarkelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def delete_comment(self, msg_data_id, index, user_comment_id): """ 删除评论 """ return self._post( - 'comment/delete', + "comment/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def add_reply_comment(self, msg_data_id, index, user_comment_id, content): """ 回复评论 """ return self._post( - 'comment/reply/add', + "comment/reply/add", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - 'content': content - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + "content": content, + }, + ) def delete_reply_comment(self, msg_data_id, index, user_comment_id): """ 删除回复 """ return self._post( - 'comment/reply/delete', + "comment/reply/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/media.py b/chapter13/booking_system/exts/wechatpy/client/api/media.py index b4338b3..3b414c6 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/media.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/media.py @@ -17,13 +17,7 @@ def upload(self, media_type, media_file): :return: 返回的 JSON 数据包 """ return self._post( - url='media/upload', - params={ - 'type': media_type - }, - files={ - 'media': media_file - } + url="media/upload", params={"type": media_type}, files={"media": media_file} ) def download(self, media_id): @@ -36,12 +30,7 @@ def download(self, media_id): :return: requests 的 Response 实例 """ - return self._get( - 'media/get', - params={ - 'media_id': media_id - } - ) + return self._get("media/get", params={"media_id": media_id}) def get_url(self, media_id): """ @@ -51,13 +40,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://api.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://api.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def upload_video(self, media_id, title, description): """ @@ -72,12 +61,8 @@ def upload_video(self, media_id, title, description): :return: 返回的 JSON 数据包 """ return self._post( - url='media/uploadvideo', - data={ - 'media_id': media_id, - 'title': title, - 'description': description - } + url="media/uploadvideo", + data={"media_id": media_id, "title": title, "description": description}, ) def upload_articles(self, articles): @@ -91,21 +76,18 @@ def upload_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'media/uploadnews', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) + return self._post("media/uploadnews", data={"articles": articles_data}) def upload_image(self, media_file): """ @@ -117,11 +99,9 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='media/uploadimg', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="media/uploadimg", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/menu.py b/chapter13/booking_system/exts/wechatpy/client/api/menu.py index f0f6ce7..d509bc6 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/menu.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/menu.py @@ -24,7 +24,7 @@ def get(self): """ try: - return self._get('menu/get') + return self._get("menu/get") except WeChatClientException as e: if e.errcode == 46003: # menu not exist @@ -81,10 +81,7 @@ def create(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/create', - data=menu_data - ) + return self._post("menu/create", data=menu_data) def update(self, menu_data): """ @@ -153,7 +150,7 @@ def delete(self): res = client.menu.delete() """ - return self._get('menu/delete') + return self._get("menu/delete") def get_menu_info(self): """ @@ -171,7 +168,7 @@ def get_menu_info(self): menu_info = client.menu.get_menu_info() """ - return self._get('get_current_selfmenu_info') + return self._get("get_current_selfmenu_info") def add_conditional(self, menu_data): """ @@ -230,10 +227,7 @@ def add_conditional(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/addconditional', - data=menu_data - ) + return self._post("menu/addconditional", data=menu_data) def del_conditional(self, menu_id): """ @@ -254,10 +248,7 @@ def del_conditional(self, menu_id): res = client.menu.del_conditional('menu_id') """ - return self._post( - 'menu/delconditional', - data={'menuid': menu_id} - ) + return self._post("menu/delconditional", data={"menuid": menu_id}) def try_match(self, user_id): """ @@ -278,7 +269,4 @@ def try_match(self, user_id): res = client.menu.try_match('openid') """ - return self._post( - 'menu/trymatch', - data={'user_id': user_id} - ) + return self._post("menu/trymatch", data={"user_id": user_id}) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/__init__.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/__init__.py index d8342ac..710b104 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/__init__.py @@ -12,7 +12,7 @@ class WeChatMerchant(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def __init__(self, *args, **kwargs): super(WeChatMerchant, self).__init__(*args, **kwargs) @@ -28,54 +28,30 @@ def __init__(self, *args, **kwargs): def create(self, product_data): """增加商品""" - return self._post( - 'merchant/create', - data=product_data - ) + return self._post("merchant/create", data=product_data) def delete(self, product_id): """删除商品""" - return self._post( - 'merchant/del', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/del", data={"product_id": product_id}) def update(self, product_id, product_data): """修改商品""" - product_data['product_id'] = product_id - return self._post( - 'merchant/update', - data=product_data - ) + product_data["product_id"] = product_id + return self._post("merchant/update", data=product_data) def get(self, product_id): """查询商品""" - return self._post( - 'merchant/get', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/get", data={"product_id": product_id}) def get_by_status(self, status): """获取指定状态的所有商品""" - return self._post( - 'merchant/getbystatus', - data={ - 'status': status - } - ) + return self._post("merchant/getbystatus", data={"status": status}) def update_product_status(self, product_id, status): """商品上下架""" return self._post( - 'merchant/modproductstatus', - data={ - 'product_id': product_id, - 'status': status - } + "merchant/modproductstatus", + data={"product_id": product_id, "status": status}, ) def get_subcategories(self, cate_id): @@ -85,12 +61,7 @@ def get_subcategories(self, cate_id): :param cate_id: 大分类ID(根节点分类id为1) :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsub', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsub", data={"cate_id": cate_id}) def get_category_sku(self, cate_id): """ @@ -99,12 +70,7 @@ def get_category_sku(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsku', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsku", data={"cate_id": cate_id}) def get_category_property(self, cate_id): """ @@ -113,12 +79,7 @@ def get_category_property(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getproperty', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getproperty", data={"cate_id": cate_id}) def add_stock(self, product_id, sku_info, quantity): """ @@ -130,12 +91,8 @@ def add_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/add', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/add", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def reduce_stock(self, product_id, sku_info, quantity): @@ -148,12 +105,8 @@ def reduce_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/reduce', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/reduce", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def add_express(self, product_data): @@ -163,10 +116,7 @@ def add_express(self, product_data): :param product_data: 邮费信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/add', - data=product_data - ) + return self._post("merchant/express/add", data=product_data) def del_express(self, template_id): """ @@ -175,12 +125,7 @@ def del_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update_express(self, template_id, delivery_template): """ @@ -190,11 +135,8 @@ def update_express(self, template_id, delivery_template): :param delivery_template: 邮费模板信息(字段说明详见增加邮费模板) :return: 返回的 JSON 数据包 """ - delivery_template['template_id'] = template_id - return self._post( - 'merchant/express/update', - data=delivery_template - ) + delivery_template["template_id"] = template_id + return self._post("merchant/express/update", data=delivery_template) def get_express(self, template_id): """ @@ -203,12 +145,7 @@ def get_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/getbyid", data={"template_id": template_id}) def get_all_express(self): """ @@ -217,9 +154,7 @@ def get_all_express(self): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/express/getall' - ) + return self._get("merchant/express/getall") def add_group(self, group_detail): """ @@ -228,10 +163,7 @@ def add_group(self, group_detail): :param group_detail: 商品分组信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/add', - data=group_detail - ) + return self._post("merchant/group/add", data=group_detail) def del_group(self, group_id): """ @@ -240,12 +172,7 @@ def del_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update_group_property(self, group_id, group_properties): """ @@ -255,11 +182,8 @@ def update_group_property(self, group_id, group_properties): :param group_properties: 商品分组属性 :return: 返回的 JSON 数据包 """ - group_properties['group_id'] = group_id - return self._post( - 'merchant/group/propertymod', - data=group_properties - ) + group_properties["group_id"] = group_id + return self._post("merchant/group/propertymod", data=group_properties) def update_group_product(self, group_id, product_data): """ @@ -269,11 +193,8 @@ def update_group_product(self, group_id, product_data): :param product_data: 分组商品信息 :return: 返回的 JSON 数据包 """ - product_data['group_id'] = group_id - return self._post( - 'merchant/group/productmod', - data=product_data - ) + product_data["group_id"] = group_id + return self._post("merchant/group/productmod", data=product_data) def get_all_groups(self): """ @@ -281,9 +202,7 @@ def get_all_groups(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/group/getall' - ) + return self._get("merchant/group/getall") def get_group(self, group_id): """ @@ -292,12 +211,7 @@ def get_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/getbyid", data={"group_id": group_id}) def add_shelf(self, shelf_data): """ @@ -306,10 +220,7 @@ def add_shelf(self, shelf_data): :param shelf_data: 货架详情信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/add', - data=shelf_data - ) + return self._post("merchant/shelf/add", data=shelf_data) def del_shelf(self, shelf_id): """ @@ -318,12 +229,7 @@ def del_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update_shelf(self, shelf_id, shelf_data): """ @@ -333,11 +239,8 @@ def update_shelf(self, shelf_id, shelf_data): :param shelf_data: 货架详情 :return: 返回的 JSON 数据包 """ - shelf_data['shelf_id'] = shelf_id - return self._post( - 'merchant/shelf/mod', - data=shelf_data - ) + shelf_data["shelf_id"] = shelf_id + return self._post("merchant/shelf/mod", data=shelf_data) def get_all_shelves(self): """ @@ -345,9 +248,7 @@ def get_all_shelves(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/shelf/getall' - ) + return self._get("merchant/shelf/getall") def get_shelf(self, shelf_id): """ @@ -356,12 +257,7 @@ def get_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) def get_order(self, order_id): """ @@ -370,12 +266,7 @@ def get_order(self, order_id): :param order_id: 订单ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/getbyid", data={"order_id": order_id}) def query_order(self, status=None, begintime=None, endtime=None): """ @@ -387,12 +278,8 @@ def query_order(self, status=None, begintime=None, endtime=None): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/order/getbyfilter', - data={ - 'status': status, - 'begintime': begintime, - 'endtime': endtime - } + "merchant/order/getbyfilter", + data={"status": status, "begintime": begintime, "endtime": endtime}, ) def set_delivery(self, order_id, delivery_data): @@ -403,11 +290,8 @@ def set_delivery(self, order_id, delivery_data): :param delivery_data: 商品物流信息 :return: 返回的 JSON 数据包 """ - delivery_data['order_id'] = order_id - return self._post( - 'merchant/shelf/setdeliverymod', - data=delivery_data - ) + delivery_data["order_id"] = order_id + return self._post("merchant/shelf/setdeliverymod", data=delivery_data) def upload_image(self, media_file): """ @@ -417,10 +301,8 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='merchant/common/upload_img', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="merchant/common/upload_img", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/category.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/category.py index 3297125..584a902 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/category.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/category.py @@ -5,28 +5,28 @@ class MerchantCategory(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get_sub_categories(self, cate_id): res = self._post( - 'merchant/category/getsub', - data={'cate_id': cate_id}, - result_processor=lambda x: x['cate_list'] + "merchant/category/getsub", + data={"cate_id": cate_id}, + result_processor=lambda x: x["cate_list"], ) return res def get_sku_list(self, cate_id): res = self._post( - 'merchant/category/getsku', - data={'cate_id': cate_id}, - result_processor=lambda x: x['sku_table'] + "merchant/category/getsku", + data={"cate_id": cate_id}, + result_processor=lambda x: x["sku_table"], ) return res def get_properties(self, cate_id): res = self._post( - 'merchant/category/getproperty', - data={'cate_id': cate_id}, - result_processor=lambda x: x['properties'] + "merchant/category/getproperty", + data={"cate_id": cate_id}, + result_processor=lambda x: x["properties"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/common.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/common.py index e1d3323..2700e77 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/common.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/common.py @@ -5,15 +5,13 @@ class MerchantCommon(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def upload_image(self, filename, image_data): res = self._post( - 'merchant/common/upload_img', - params={ - 'filename': filename - }, + "merchant/common/upload_img", + params={"filename": filename}, data=image_data, - result_processor=lambda x: x['image_url'] + result_processor=lambda x: x["image_url"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/express.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/express.py index e6e2e5c..488e05d 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/express.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/express.py @@ -5,46 +5,32 @@ class MerchantExpress(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, delivery_template): return self._post( - 'merchant/express/add', - data={ - 'delivery_template': delivery_template - } + "merchant/express/add", data={"delivery_template": delivery_template} ) def delete(self, template_id): - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update(self, template_id, delivery_template): return self._post( - 'merchant/express/update', - data={ - 'template_id': template_id, - 'delivery_template': delivery_template - } + "merchant/express/update", + data={"template_id": template_id, "delivery_template": delivery_template}, ) def get(self, template_id): res = self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - }, - result_processor=lambda x: x['template_info'] + "merchant/express/getbyid", + data={"template_id": template_id}, + result_processor=lambda x: x["template_info"], ) return res def get_all(self): res = self._get( - 'merchant/express/getall', - result_processor=lambda x: x['template_info'] + "merchant/express/getall", result_processor=lambda x: x["template_info"] ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/group.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/group.py index acaf1df..02c17d6 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/group.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/group.py @@ -5,58 +5,38 @@ class MerchantGroup(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, product_list): return self._post( - 'merchant/group/add', - data={ - 'group_detail': { - 'group_name': name, - 'product_list': product_list - } - } + "merchant/group/add", + data={"group_detail": {"group_name": name, "product_list": product_list}}, ) def delete(self, group_id): - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update(self, group_id, name): return self._post( - 'merchant/group/propertymod', - data={ - 'group_id': group_id, - 'group_name': name - } + "merchant/group/propertymod", + data={"group_id": group_id, "group_name": name}, ) def update_product(self, group_id, product): return self._post( - 'merchant/group/productmod', - data={ - 'group_id': group_id, - 'product': product - } + "merchant/group/productmod", data={"group_id": group_id, "product": product} ) def get_all(self): res = self._get( - 'merchant/group/getall', - result_processor=lambda x: x['groups_detail'] + "merchant/group/getall", result_processor=lambda x: x["groups_detail"] ) return res def get(self, group_id): res = self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - }, - result_processor=lambda x: x['group_detail'] + "merchant/group/getbyid", + data={"group_id": group_id}, + result_processor=lambda x: x["group_detail"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/order.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/order.py index 7e49412..7938633 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/order.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/order.py @@ -6,49 +6,39 @@ class MerchantOrder(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get(self, order_id): res = self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - }, - result_processor=lambda x: x['order'] + "merchant/order/getbyid", + data={"order_id": order_id}, + result_processor=lambda x: x["order"], ) return res def get_by_filter(self, status=None, begin_time=None, end_time=None): filter_dict = optionaldict( - status=status, - begintime=begin_time, - endtime=end_time + status=status, begintime=begin_time, endtime=end_time ) res = self._post( - 'merchant/order/getbyfilter', + "merchant/order/getbyfilter", data=dict(filter_dict), - result_processor=lambda x: x['order_list'] + result_processor=lambda x: x["order_list"], ) return res - def set_delivery(self, order_id, company, track_no, - need_delivery=1, is_others=0): + def set_delivery(self, order_id, company, track_no, need_delivery=1, is_others=0): return self._post( - 'merchant/order/setdelivery', + "merchant/order/setdelivery", data={ - 'order_id': order_id, - 'delivery_company': company, - 'delivery_track_no': track_no, - 'need_delivery': need_delivery, - 'is_others': is_others - } + "order_id": order_id, + "delivery_company": company, + "delivery_track_no": track_no, + "need_delivery": need_delivery, + "is_others": is_others, + }, ) def close(self, order_id): - return self._post( - 'merchant/order/close', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/close", data={"order_id": order_id}) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/shelf.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/shelf.py index afca61f..b6dc2a8 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/shelf.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/shelf.py @@ -5,48 +5,33 @@ class MerchantShelf(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', - data={ - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "merchant/shelf/add", + data={"shelf_name": name, "shelf_banner": banner, "shelf_data": shelf_data}, ) def delete(self, shelf_id): - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update(self, shelf_id, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', + "merchant/shelf/add", data={ - 'shelf_id': shelf_id, - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "shelf_id": shelf_id, + "shelf_name": name, + "shelf_banner": banner, + "shelf_data": shelf_data, + }, ) def get_all(self): res = self._get( - 'merchant/shelf/getall', - result_processor=lambda x: x['shelves'] + "merchant/shelf/getall", result_processor=lambda x: x["shelves"] ) return res def get(self, shelf_id): - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/merchant/stock.py b/chapter13/booking_system/exts/wechatpy/client/api/merchant/stock.py index b2a6b1c..295eddb 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/merchant/stock.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/merchant/stock.py @@ -5,24 +5,16 @@ class MerchantStock(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" - def add(self, product_id, quantity, sku_info=''): + def add(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/add', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/add", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) - def reduce(self, product_id, quantity, sku_info=''): + def reduce(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/reduce', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/reduce", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/message.py b/chapter13/booking_system/exts/wechatpy/client/api/message.py index 8dacb07..c418a02 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/message.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/message.py @@ -12,16 +12,13 @@ class WeChatMessage(BaseWeChatAPI): - OPENID_RE = re.compile(r'^[\w\-]{28}$', re.I) + OPENID_RE = re.compile(r"^[\w\-]{28}$", re.I) def _send_custom_message(self, data, account=None): data = data or {} if account: - data['customservice'] = {'kf_account': account} - return self._post( - 'message/custom/send', - data=data - ) + data["customservice"] = {"kf_account": account} + return self._post("message/custom/send", data=data) def send_text(self, user_id, content, account=None): """ @@ -43,11 +40,7 @@ def send_text(self, user_id, content, account=None): res = client.message.send_text('openid', 'text') """ - data = { - 'touser': user_id, - 'msgtype': 'text', - 'text': {'content': content} - } + data = {"touser": user_id, "msgtype": "text", "text": {"content": content}} return self._send_custom_message(data, account=account) def send_image(self, user_id, media_id, account=None): @@ -70,13 +63,7 @@ def send_image(self, user_id, media_id, account=None): res = client.message.send_image('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'image', - 'image': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "image", "image": {"media_id": media_id}} return self._send_custom_message(data, account=account) def send_voice(self, user_id, media_id, account=None): @@ -99,17 +86,10 @@ def send_voice(self, user_id, media_id, account=None): res = client.message.send_voice('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "voice", "voice": {"media_id": media_id}} return self._send_custom_message(data, account=account) - def send_video(self, user_id, media_id, title=None, - description=None, account=None): + def send_video(self, user_id, media_id, title=None, description=None, account=None): """ 发送视频消息 @@ -131,22 +111,26 @@ def send_video(self, user_id, media_id, title=None, res = client.message.send_video('openid', 'media_id', 'title', 'description') """ video_data = { - 'media_id': media_id, + "media_id": media_id, } if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'video', - 'video': video_data - } + data = {"touser": user_id, "msgtype": "video", "video": video_data} return self._send_custom_message(data, account=account) - def send_music(self, user_id, url, hq_url, thumb_media_id, - title=None, description=None, account=None): + def send_music( + self, + user_id, + url, + hq_url, + thumb_media_id, + title=None, + description=None, + account=None, + ): """ 发送音乐消息 @@ -163,20 +147,16 @@ def send_music(self, user_id, url, hq_url, thumb_media_id, :return: 返回的 JSON 数据包 """ music_data = { - 'musicurl': url, - 'hqmusicurl': hq_url, - 'thumb_media_id': thumb_media_id + "musicurl": url, + "hqmusicurl": hq_url, + "thumb_media_id": thumb_media_id, } if title: - music_data['title'] = title + music_data["title"] = title if description: - music_data['description'] = description + music_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'music', - 'music': music_data - } + data = {"touser": user_id, "msgtype": "music", "music": music_data} return self._send_custom_message(data, account=account) def send_articles(self, user_id, articles, account=None): @@ -194,26 +174,26 @@ def send_articles(self, user_id, articles, account=None): if isinstance(articles, (tuple, list)): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article.get('image', article.get('picurl')), - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article.get("image", article.get("picurl")), + } + ) data = { - 'touser': user_id, - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } + "touser": user_id, + "msgtype": "news", + "news": {"articles": articles_data}, } else: data = { - 'touser': user_id, - 'msgtype': 'mpnews', - 'mpnews': { - 'media_id': articles, - } + "touser": user_id, + "msgtype": "mpnews", + "mpnews": { + "media_id": articles, + }, } return self._send_custom_message(data, account=account) @@ -231,14 +211,14 @@ def send_card(self, user_id, card_id, card_ext=None, account=None): :return: 返回的 JSON 数据包 """ wxcard = { - 'card_id': card_id, + "card_id": card_id, } if card_ext: - wxcard['card_ext'] = card_ext + wxcard["card_ext"] = card_ext data = { - 'touser': user_id, - 'msgtype': 'wxcard', - 'wxcard': wxcard, + "touser": user_id, + "msgtype": "wxcard", + "wxcard": wxcard, } return self._send_custom_message(data, account=account) @@ -254,9 +234,9 @@ def send_mini_program_page(self, user_id, miniprogrampage, account=None): :return: 返回的 JSON 数据包 """ data = { - 'touser': user_id, - 'msgtype': 'miniprogrampage', - 'miniprogrampage': miniprogrampage + "touser": user_id, + "msgtype": "miniprogrampage", + "miniprogrampage": miniprogrampage, } return self._send_custom_message(data, account=account) @@ -278,55 +258,60 @@ def delete_mass(self, msg_id): res = client.message.delete_mass('message id') """ - return self._post( - 'message/mass/delete', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/delete", data={"msg_id": msg_id}) - def _send_mass_message(self, group_or_users, msg_type, msg, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def _send_mass_message( + self, + group_or_users, + msg_type, + msg, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): data = { - 'msgtype': msg_type, - 'send_ignore_reprint': send_ignore_reprint, + "msgtype": msg_type, + "send_ignore_reprint": send_ignore_reprint, } if client_msg_id is not None: - data['clientmsgid'] = client_msg_id + data["clientmsgid"] = client_msg_id if not preview: if isinstance(group_or_users, (tuple, list)): # send by order ids - data['touser'] = group_or_users - endpoint = 'message/mass/send' + data["touser"] = group_or_users + endpoint = "message/mass/send" else: # send by group id - data['filter'] = { - 'group_id': group_or_users, - 'is_to_all': is_to_all, + data["filter"] = { + "group_id": group_or_users, + "is_to_all": is_to_all, } - endpoint = 'message/mass/sendall' + endpoint = "message/mass/sendall" else: if not isinstance(group_or_users, six.string_types): - raise ValueError('group_or_users should be string types') + raise ValueError("group_or_users should be string types") # 预览接口 if self.OPENID_RE.match(group_or_users): # 按照 openid 预览群发 - data['touser'] = group_or_users + data["touser"] = group_or_users else: # 按照微信号预览群发 - data['towxname'] = group_or_users - endpoint = 'message/mass/preview' + data["towxname"] = group_or_users + endpoint = "message/mass/preview" data.update(msg) - return self._post( - endpoint, - data=data - ) - - def send_mass_text(self, group_or_users, content, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + return self._post(endpoint, data=data) + + def send_mass_text( + self, + group_or_users, + content, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发文本消息 @@ -353,21 +338,23 @@ def send_mass_text(self, group_or_users, content, """ return self._send_mass_message( group_or_users, - 'text', - { - 'text': { - 'content': content - } - }, + "text", + {"text": {"content": content}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_image(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_image( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图片消息 @@ -394,21 +381,23 @@ def send_mass_image(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'image', - { - 'image': { - 'media_id': media_id - } - }, + "image", + {"image": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_voice(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_voice( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发语音消息 @@ -435,21 +424,25 @@ def send_mass_voice(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'voice', - { - 'voice': { - 'media_id': media_id - } - }, + "voice", + {"voice": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_video(self, group_or_users, media_id, title=None, - description=None, is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_video( + self, + group_or_users, + media_id, + title=None, + description=None, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发视频消息 @@ -476,28 +469,30 @@ def send_mass_video(self, group_or_users, media_id, title=None, :return: 返回的 JSON 数据包 """ - video_data = { - 'media_id': media_id - } + video_data = {"media_id": media_id} if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description return self._send_mass_message( group_or_users, - 'mpvideo', - { - 'mpvideo': video_data - }, + "mpvideo", + {"mpvideo": video_data}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_article(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_article( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图文消息 @@ -524,12 +519,8 @@ def send_mass_article(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'mpnews', - { - 'mpnews': { - 'media_id': media_id - } - }, + "mpnews", + {"mpnews": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, @@ -554,14 +545,11 @@ def get_mass(self, msg_id): res = client.message.get_mass('mass message id') """ - return self._post( - 'message/mass/get', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/get", data={"msg_id": msg_id}) - def send_template(self, to_user_openid, template_id, data, url=None, mini_program=None): + def send_template( + self, to_user_openid, template_id, data, url=None, mini_program=None + ): """ 发送模板消息 @@ -582,10 +570,7 @@ def send_template(self, to_user_openid, template_id, data, url=None, mini_progra miniprogram=mini_program, data=data, ) - return self._post( - 'message/template/send', - data=tpl_data - ) + return self._post("message/template/send", data=tpl_data) def get_autoreply_info(self): """ @@ -604,11 +589,17 @@ def get_autoreply_info(self): info = client.message.get_autoreply_info() """ - return self._get('get_current_autoreply_info') + return self._get("get_current_autoreply_info") - def send_mass_card(self, group_or_users, card_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_card( + self, + group_or_users, + card_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发卡券消息 @@ -635,19 +626,17 @@ def send_mass_card(self, group_or_users, card_id, """ return self._send_mass_message( group_or_users, - 'wxcard', - { - 'wxcard': { - 'card_id': card_id - } - }, + "wxcard", + {"wxcard": {"card_id": card_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved=None): + def get_subscribe_authorize_url( + self, scene, template_id, redirect_url, reserved=None + ): """ 构造请求用户授权的url 详情请参阅: @@ -661,20 +650,24 @@ def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved """ if reserved is None: reserved = random_string() - base_url = 'https://mp.weixin.qq.com/mp/subscribemsg' + base_url = "https://mp.weixin.qq.com/mp/subscribemsg" params = [ - ('action', 'get_confirm'), - ('appid', self.appid), - ('scene', scene), - ('template_id', template_id), - ('redirect_url', redirect_url), - ('reserved', reserved), + ("action", "get_confirm"), + ("appid", self.appid), + ("scene", scene), + ("template_id", template_id), + ("redirect_url", redirect_url), + ("reserved", reserved), ] encoded_params = six.moves.urllib.parse.urlencode(params) - url = '{base}?{params}#wechat_redirect'.format(base=base_url, params=encoded_params) + url = "{base}?{params}#wechat_redirect".format( + base=base_url, params=encoded_params + ) return url - def send_subscribe_template(self, openid, template_id, scene, title, data, url=None): + def send_subscribe_template( + self, openid, template_id, scene, title, data, url=None + ): """ 一次性订阅消息,通过API推送订阅模板消息给到授权微信用户。 详情请参阅: @@ -690,16 +683,16 @@ def send_subscribe_template(self, openid, template_id, scene, title, data, url=N :param url: 点击消息跳转的链接,需要有ICP备案 """ post_data = { - 'touser': openid, - 'template_id': template_id, - 'url': url, - 'scene': scene, - 'title': title, - 'data': data, + "touser": openid, + "template_id": template_id, + "url": url, + "scene": scene, + "title": title, + "data": data, } if url is not None: - post_data['url'] = url + post_data["url"] = url return self._post( - 'message/template/subscribe', + "message/template/subscribe", data=post_data, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/misc.py b/chapter13/booking_system/exts/wechatpy/client/api/misc.py index 8a8f996..a6eacb6 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/misc.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/misc.py @@ -23,11 +23,7 @@ def short_url(self, long_url): """ return self._post( - 'shorturl', - data={ - 'action': 'long2short', - 'long_url': long_url - } + "shorturl", data={"action": "long2short", "long_url": long_url} ) def get_wechat_ips(self): @@ -44,8 +40,5 @@ def get_wechat_ips(self): ips = client.misc.get_wechat_ips() """ - res = self._get( - 'getcallbackip', - result_processor=lambda x: x['ip_list'] - ) + res = self._get("getcallbackip", result_processor=lambda x: x["ip_list"]) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/poi.py b/chapter13/booking_system/exts/wechatpy/client/api/poi.py index 0acfb7d..6bceefd 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/poi.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/poi.py @@ -15,7 +15,7 @@ def add(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/addpoi', data=poi_data) + return self._post("poi/addpoi", data=poi_data) def get(self, poi_id): """ @@ -27,7 +27,7 @@ def get(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/getpoi', data={'poi_id': poi_id}) + return self._post("poi/getpoi", data={"poi_id": poi_id}) def list(self, begin=0, limit=20): """ @@ -41,11 +41,11 @@ def list(self, begin=0, limit=20): :return: 返回的 JSON 数据包 """ return self._post( - 'poi/getpoilist', + "poi/getpoilist", data={ - 'begin': begin, - 'limit': limit, - } + "begin": begin, + "limit": limit, + }, ) def update(self, poi_data): @@ -58,7 +58,7 @@ def update(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/updatepoi', data=poi_data) + return self._post("poi/updatepoi", data=poi_data) def delete(self, poi_id): """ @@ -70,7 +70,7 @@ def delete(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/delpoi', data={'poi_id': poi_id}) + return self._post("poi/delpoi", data={"poi_id": poi_id}) def get_categories(self): """ @@ -82,7 +82,6 @@ def get_categories(self): :return: 门店类目表 """ res = self._get( - 'api_getwxcategory', - result_processor=lambda x: x['category_list'] + "api_getwxcategory", result_processor=lambda x: x["category_list"] ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/qrcode.py b/chapter13/booking_system/exts/wechatpy/client/api/qrcode.py index 51b7af1..07dcc9b 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/qrcode.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/qrcode.py @@ -38,10 +38,7 @@ def create(self, qrcode_data): }) """ - return self._post( - 'qrcode/create', - data=qrcode_data - ) + return self._post("qrcode/create", data=qrcode_data) def show(self, ticket): """ @@ -61,12 +58,9 @@ def show(self, ticket): """ if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] return requests.get( - url='https://mp.weixin.qq.com/cgi-bin/showqrcode', - params={ - 'ticket': ticket - } + url="https://mp.weixin.qq.com/cgi-bin/showqrcode", params={"ticket": ticket} ) @classmethod @@ -87,8 +81,8 @@ def get_url(cls, ticket): url = client.qrcode.get_url('ticket data') """ - url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}' + url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}" if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] ticket = six.moves.urllib.parse.quote(ticket) return url.format(ticket=ticket) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/scan.py b/chapter13/booking_system/exts/wechatpy/client/api/scan.py index c7a1589..1fb2d4a 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/scan.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/scan.py @@ -6,7 +6,7 @@ class WeChatScan(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/scan/' + API_BASE_URL = "https://api.weixin.qq.com/scan/" def get_merchant_info(self): """ @@ -24,7 +24,7 @@ def get_merchant_info(self): client = WeChatClient('appid', 'secret') info = client.scan.get_merchant_info() """ - return self._get('merchantinfo/get') + return self._get("merchantinfo/get") def create_product(self, product_data): """ @@ -35,7 +35,7 @@ def create_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/create', data=product_data) + return self._post("product/create", data=product_data) def modify_product_status(self, standard, key, status): """ @@ -50,11 +50,11 @@ def modify_product_status(self, standard, key, status): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, - 'status': status, + "keystandard": standard, + "keystr": key, + "status": status, } - return self._post('product/modstatus', data=data) + return self._post("product/modstatus", data=data) def publish_product(self, standard, key): """ @@ -62,7 +62,7 @@ def publish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'on')`` """ - return self.modify_product_status(standard, key, 'on') + return self.modify_product_status(standard, key, "on") def unpublish_product(self, standard, key): """ @@ -70,7 +70,7 @@ def unpublish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'off')`` """ - return self.modify_product_status(standard, key, 'off') + return self.modify_product_status(standard, key, "off") def set_test_whitelist(self, userids=None, usernames=None): """ @@ -85,11 +85,8 @@ def set_test_whitelist(self, userids=None, usernames=None): :param usernames: 可选,测试人员的微信号列表 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=userids, - username=usernames - ) - return self._post('testwhitelist/set', data=data) + data = optionaldict(openid=userids, username=usernames) + return self._post("testwhitelist/set", data=data) def get_product(self, standard, key): """ @@ -103,10 +100,10 @@ def get_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/get', data=data) + return self._post("product/get", data=data) def list_product(self, offset=0, limit=10, status=None, key=None): """ @@ -128,7 +125,7 @@ def list_product(self, offset=0, limit=10, status=None, key=None): status=status, keystr=key, ) - return self._post('product/getlist', data=data) + return self._post("product/getlist", data=data) def update_product(self, product_data): """ @@ -139,7 +136,7 @@ def update_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/update', data=product_data) + return self._post("product/update", data=product_data) def clear_product(self, standard, key): """ @@ -153,10 +150,10 @@ def clear_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/clear', data=data) + return self._post("product/clear", data=data) def check_ticket(self, ticket): """ @@ -168,4 +165,4 @@ def check_ticket(self, ticket): :param ticket: 请求 URL 中带上的 wxticket 参数 :return: 返回的 JSON 数据包 """ - return self._post('scanticket/check', data={'ticket': ticket}) + return self._post("scanticket/check", data={"ticket": ticket}) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/semantic.py b/chapter13/booking_system/exts/wechatpy/client/api/semantic.py index 73325ed..4a234eb 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/semantic.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/semantic.py @@ -7,14 +7,16 @@ class WeChatSemantic(BaseWeChatAPI): - def search(self, - query, - category, - uid=None, - latitude=None, - longitude=None, - city=None, - region=None): + def search( + self, + query, + category, + uid=None, + latitude=None, + longitude=None, + city=None, + region=None, + ): """ 发送语义理解请求 详情请参考 @@ -42,18 +44,17 @@ def search(self, """ if isinstance(category, (tuple, list)): - category = ','.join(category) + category = ",".join(category) data = optionaldict() - data['query'] = query - data['category'] = category - data['uid'] = uid - data['latitude'] = latitude - data['longitude'] = longitude - data['city'] = city - data['region'] = region - data['appid'] = self._client.appid + data["query"] = query + data["category"] = category + data["uid"] = uid + data["latitude"] = latitude + data["longitude"] = longitude + data["city"] = city + data["region"] = region + data["appid"] = self._client.appid return self._post( - url='https://api.weixin.qq.com/semantic/semproxy/search', - data=data + url="https://api.weixin.qq.com/semantic/semproxy/search", data=data ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/shakearound.py b/chapter13/booking_system/exts/wechatpy/client/api/shakearound.py index cca5ba7..52fdb37 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/shakearound.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/shakearound.py @@ -11,12 +11,12 @@ class WeChatShakeAround(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" @classmethod def _to_timestamp(cls, date): if isinstance(date, six.string_types): - date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S') + date = datetime.strptime(date, "%Y-%m-%d %H:%M:%S") if isinstance(date, datetime): timestamp = int(time.mktime(date.timetuple())) return timestamp @@ -35,19 +35,20 @@ def apply_device_id(self, quantity, reason, poi_id=None, comment=None): :return: 申请的设备信息 """ data = optionaldict() - data['quantity'] = quantity - data['apply_reason'] = reason - data['poi_id'] = poi_id - data['comment'] = comment + data["quantity"] = quantity + data["apply_reason"] = reason + data["poi_id"] = poi_id + data["comment"] = comment res = self._post( - 'shakearound/device/applyid', + "shakearound/device/applyid", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res - def update_device(self, device_id=None, uuid=None, major=None, - minor=None, comment=None): + def update_device( + self, device_id=None, uuid=None, major=None, minor=None, comment=None + ): """ 更新设备信息 详情请参考 @@ -61,20 +62,18 @@ def update_device(self, device_id=None, uuid=None, major=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['comment'] = comment - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["comment"] = comment + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/update', - data=data - ) + return self._post("shakearound/device/update", data=data) - def bind_device_location(self, poi_id, device_id=None, uuid=None, - major=None, minor=None): + def bind_device_location( + self, poi_id, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与门店的关联关系 详情请参考 @@ -88,20 +87,16 @@ def bind_device_location(self, poi_id, device_id=None, uuid=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['poi_id'] = poi_id - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["poi_id"] = poi_id + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/bindlocation', - data=data - ) + return self._post("shakearound/device/bindlocation", data=data) - def search_device(self, identifiers=None, apply_id=None, - begin=0, count=10): + def search_device(self, identifiers=None, apply_id=None, begin=0, count=10): """ 查询设备列表 详情请参考 @@ -114,15 +109,13 @@ def search_device(self, identifiers=None, apply_id=None, :return: 设备列表 """ data = optionaldict() - data['begin'] = begin - data['count'] = count - data['apply_id'] = apply_id + data["begin"] = begin + data["count"] = count + data["apply_id"] = apply_id if identifiers: - data['device_identifiers'] = identifiers + data["device_identifiers"] = identifiers res = self._post( - 'shakearound/device/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/device/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -141,20 +134,19 @@ def add_page(self, title, description, icon_url, page_url, comment=None): :return: 页面信息 """ data = optionaldict() - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/add', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/add", data=data, result_processor=lambda x: x["data"] ) return res - def update_page(self, page_id, title, description, - icon_url, page_url, comment=None): + def update_page( + self, page_id, title, description, icon_url, page_url, comment=None + ): """ 编辑页面信息 详情请参考 @@ -170,16 +162,14 @@ def update_page(self, page_id, title, description, :return: 页面信息 """ data = optionaldict() - data['page_id'] = page_id - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["page_id"] = page_id + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/update', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/update", data=data, result_processor=lambda x: x["data"] ) return res @@ -195,23 +185,14 @@ def search_pages(self, page_ids=None, begin=0, count=10): :return: 页面查询结果信息 """ if not page_ids: - data = { - 'type': 2, - 'begin': begin, - 'count': count - } + data = {"type": 2, "begin": begin, "count": count} else: if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] - data = { - 'type': 1, - 'page_ids': page_ids - } + data = {"type": 1, "page_ids": page_ids} res = self._post( - 'shakearound/page/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -224,14 +205,9 @@ def delete_page(self, page_id): :param page_id: 指定页面的id列表 :return: 返回的 JSON 数据包 """ - return self._post( - 'shakearound/page/delete', - data={ - 'page_id': page_id - } - ) + return self._post("shakearound/page/delete", data={"page_id": page_id}) - def add_material(self, media_file, media_type='icon'): + def add_material(self, media_file, media_type="icon"): """ 上传图片素材 详情请参考 @@ -242,19 +218,16 @@ def add_material(self, media_file, media_type='icon'): :return: 上传的素材信息 """ res = self._post( - 'shakearound/material/add', - files={ - 'media': media_file - }, - params={ - 'type': media_type - }, - result_processor=lambda x: x['data'] + "shakearound/material/add", + files={"media": media_file}, + params={"type": media_type}, + result_processor=lambda x: x["data"], ) return res - def bind_device_pages(self, page_ids, bind, append, device_id=None, - uuid=None, major=None, minor=None): + def bind_device_pages( + self, page_ids, bind, append, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与页面的关联关系 详情请参考 @@ -272,20 +245,17 @@ def bind_device_pages(self, page_ids, bind, append, device_id=None, if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] data = { - 'page_ids': page_ids, - 'bind': int(bind), - 'append': int(append), - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor - } + "page_ids": page_ids, + "bind": int(bind), + "append": int(append), + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, + }, } - return self._post( - 'shakearound/device/bindpage', - data=data - ) + return self._post("shakearound/device/bindpage", data=data) def get_shake_info(self, ticket): """ @@ -297,16 +267,15 @@ def get_shake_info(self, ticket): :return: 设备及用户信息 """ res = self._post( - 'shakearound/order/getshakeinfo', - data={ - 'ticket': ticket - }, - result_processor=lambda x: x['data'] + "shakearound/order/getshakeinfo", + data={"ticket": ticket}, + result_processor=lambda x: x["data"], ) return res - def get_device_statistics(self, begin_date, end_date, device_id=None, - uuid=None, major=None, minor=None): + def get_device_statistics( + self, begin_date, end_date, device_id=None, uuid=None, major=None, minor=None + ): """ 以设备为维度的数据统计接口 http://mp.weixin.qq.com/wiki/0/8a24bcacad40fe7ee98d1573cb8a6764.html @@ -319,19 +288,19 @@ def get_device_statistics(self, begin_date, end_date, device_id=None, :param minor: minor """ data = { - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, }, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date) + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), } res = self._post( - 'shakearound/statistics/device', + "shakearound/statistics/device", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -347,13 +316,13 @@ def get_page_statistics(self, page_id, begin_date, end_date): :return: 统计数据 """ res = self._post( - 'shakearound/statistics/page', + "shakearound/statistics/page", data={ - 'page_id': page_id, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date), + "page_id": page_id, + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -367,10 +336,10 @@ def get_apply_status(self, apply_id): :return: 批次状态信息 """ res = self._post( - 'shakearound/device/applystatus', + "shakearound/device/applystatus", data={ - 'apply_id': apply_id, + "apply_id": apply_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/tag.py b/chapter13/booking_system/exts/wechatpy/client/api/tag.py index 6c2a9aa..daf553d 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/tag.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/tag.py @@ -17,9 +17,9 @@ def create(self, name): """ name = to_text(name) return self._post( - 'tags/create', - data={'tag': {'name': name}}, - result_processor=lambda x: x['tag'] + "tags/create", + data={"tag": {"name": name}}, + result_processor=lambda x: x["tag"], ) def get(self): @@ -30,10 +30,7 @@ def get(self): """ - res = self._get( - 'tags/get', - result_processor=lambda x: x['tags'] - ) + res = self._get("tags/get", result_processor=lambda x: x["tags"]) return res @@ -48,13 +45,7 @@ def update(self, tag_id, name): """ name = to_text(name) return self._post( - 'tags/update', - data={ - 'tag': { - 'id': int(tag_id), - 'name': name - } - } + "tags/update", data={"tag": {"id": int(tag_id), "name": name}} ) def delete(self, tag_id): @@ -65,14 +56,7 @@ def delete(self, tag_id): :return: 返回的 JSON 数据包 """ - return self._post( - 'tags/delete', - data={ - 'tag': { - 'id': tag_id - } - } - ) + return self._post("tags/delete", data={"tag": {"id": tag_id}}) def tag_user(self, tag_id, user_id): """ @@ -84,12 +68,14 @@ def tag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchtagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchtagging", data=data) def untag_user(self, tag_id, user_id): """ @@ -101,12 +87,14 @@ def untag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchuntagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchuntagging", data=data) def get_user_tag(self, user_id): """ @@ -116,11 +104,9 @@ def get_user_tag(self, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'tags/getidlist', - data={ - 'openid': user_id - }, - result_processor=lambda x: x['tagid_list'] + "tags/getidlist", + data={"openid": user_id}, + result_processor=lambda x: x["tagid_list"], ) def get_tag_users(self, tag_id, first_user_id=None): @@ -132,14 +118,11 @@ def get_tag_users(self, tag_id, first_user_id=None): :return: 返回的 JSON 数据包 """ data = { - 'tagid': tag_id, + "tagid": tag_id, } if first_user_id: - data['next_openid'] = first_user_id - return self._post( - 'order/tag/get', - data=data - ) + data["next_openid"] = first_user_id + return self._post("order/tag/get", data=data) def iter_tag_users(self, tag_id, first_user_id=None): """ @@ -158,11 +141,11 @@ def iter_tag_users(self, tag_id, first_user_id=None): """ while True: follower_data = self.get_tag_users(tag_id, first_user_id) - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid - first_user_id = follower_data.get('next_openid') + first_user_id = follower_data.get("next_openid") if not first_user_id: return @@ -178,9 +161,9 @@ def get_black_list(self, begin_openid=None): """ data = {} if begin_openid: - data['begin_openid'] = begin_openid + data["begin_openid"] = begin_openid return self._post( - 'tags/members/getblacklist', + "tags/members/getblacklist", data=data, ) @@ -194,9 +177,9 @@ def batch_black_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchblacklist', + "tags/members/batchblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) @@ -210,8 +193,8 @@ def batch_unblack_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchunblacklist', + "tags/members/batchunblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/template.py b/chapter13/booking_system/exts/wechatpy/client/api/template.py index 5d202da..01f9bbd 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/template.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/template.py @@ -17,11 +17,8 @@ def set_industry(self, industry_id1, industry_id2): :return: 返回的 JSON 数据包 """ return self._post( - 'template/api_set_industry', - data={ - 'industry_id1': industry_id1, - 'industry_id2': industry_id2 - } + "template/api_set_industry", + data={"industry_id1": industry_id1, "industry_id2": industry_id2}, ) def get_industry(self): @@ -32,9 +29,7 @@ def get_industry(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_industry' - ) + return self._get("template/get_industry") def get(self, template_id_short): """ @@ -46,11 +41,9 @@ def get(self, template_id_short): :return: 模板 ID """ res = self._post( - 'template/api_add_template', - data={ - 'template_id_short': template_id_short - }, - result_processor=lambda x: x['template_id'] + "template/api_add_template", + data={"template_id_short": template_id_short}, + result_processor=lambda x: x["template_id"], ) return res @@ -64,9 +57,7 @@ def get_all_private_template(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_all_private_template' - ) + return self._get("template/get_all_private_template") def del_private_template(self, template_id): """ @@ -78,8 +69,5 @@ def del_private_template(self, template_id): :return: 返回的 JSON 数据包 """ return self._post( - 'template/del_private_template', - data={ - 'template_id': template_id - } + "template/del_private_template", data={"template_id": template_id} ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/user.py b/chapter13/booking_system/exts/wechatpy/client/api/user.py index 6e2a428..977310d 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/user.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/user.py @@ -8,7 +8,7 @@ class WeChatUser(BaseWeChatAPI): - def get(self, user_id, lang='zh_CN'): + def get(self, user_id, lang="zh_CN"): """ 获取用户基本信息(包括UnionID机制) 详情请参考 @@ -26,15 +26,13 @@ def get(self, user_id, lang='zh_CN'): order = client.order.get('openid') """ - assert lang in ('zh_CN', 'zh_TW', 'en'), 'lang can only be one of \ - zh_CN, zh_TW, en language codes' - return self._get( - 'order/info', - params={ - 'openid': user_id, - 'lang': lang - } - ) + assert lang in ( + "zh_CN", + "zh_TW", + "en", + ), "lang can only be one of \ + zh_CN, zh_TW, en language codes" + return self._get("order/info", params={"openid": user_id, "lang": lang}) def get_followers(self, first_user_id=None): """ @@ -56,11 +54,8 @@ def get_followers(self, first_user_id=None): """ params = {} if first_user_id: - params['next_openid'] = first_user_id - return self._get( - 'order/get', - params=params - ) + params["next_openid"] = first_user_id + return self._get("order/get", params=params) def iter_followers(self, first_user_id=None): """ @@ -86,9 +81,9 @@ def iter_followers(self, first_user_id=None): # 微信有个bug(或者叫feature),没有下一页,也返回next_openid这个字段 # 所以要通过total_count和data的长度比较判断(比较麻烦,并且不稳定) # 或者获得结果前先判断data是否存在 - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid if not first_user_id: return @@ -113,11 +108,7 @@ def update_remark(self, user_id, remark): """ return self._post( - 'order/info/updateremark', - data={ - 'openid': user_id, - 'remark': remark - } + "order/info/updateremark", data={"openid": user_id, "remark": remark} ) def get_group_id(self, user_id): @@ -139,9 +130,9 @@ def get_group_id(self, user_id): """ res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -169,16 +160,16 @@ def get_batch(self, user_list): """ if all((isinstance(x, six.string_types) for x in user_list)): - user_list = [{'openid': oid} for oid in user_list] + user_list = [{"openid": oid} for oid in user_list] res = self._post( - 'order/info/batchget', - data={'user_list': user_list}, - result_processor=lambda x: x['user_info_list'] + "order/info/batchget", + data={"user_list": user_list}, + result_processor=lambda x: x["user_info_list"], ) return res def change_openid(self, from_appid, openid_list): - '''微信公众号主体变更迁移用户 openid + """微信公众号主体变更迁移用户 openid 详情请参考 http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html @@ -186,9 +177,9 @@ def change_openid(self, from_appid, openid_list): :param from_appid: 原公众号的 appid :param openid_list: 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 :return: 转换后的 openid 信息列表 - ''' + """ return self._post( - 'changeopenid', - data={'from_appid': from_appid, 'openid_list': openid_list}, - result_processor=lambda x: x['result_list'] + "changeopenid", + data={"from_appid": from_appid, "openid_list": openid_list}, + result_processor=lambda x: x["result_list"], ) diff --git a/chapter13/booking_system/exts/wechatpy/client/api/wifi.py b/chapter13/booking_system/exts/wechatpy/client/api/wifi.py index 0852103..a513764 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/wifi.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/wifi.py @@ -8,7 +8,7 @@ class WeChatWiFi(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/bizwifi/' + API_BASE_URL = "https://api.weixin.qq.com/bizwifi/" def list_shops(self, page_index=1, page_size=20): """ @@ -22,12 +22,12 @@ def list_shops(self, page_index=1, page_size=20): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/list', + "shop/list", data={ - 'pageindex': page_index, - 'pagesize': page_size, + "pageindex": page_index, + "pagesize": page_size, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -40,11 +40,11 @@ def get_shop(self, shop_id=0): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/get', + "shop/get", data={ - 'shop_id': shop_id, + "shop_id": shop_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -63,13 +63,13 @@ def add_device(self, shop_id, ssid, password, bssid): :return: 返回的 JSON 数据包 """ return self._post( - 'device/add', + "device/add", data={ - 'shop_id': shop_id, - 'ssid': ssid, - 'password': password, - 'bssid': bssid, - } + "shop_id": shop_id, + "ssid": ssid, + "password": password, + "bssid": bssid, + }, ) def list_devices(self, shop_id=None, page_index=1, page_size=20): @@ -84,16 +84,8 @@ def list_devices(self, shop_id=None, page_index=1, page_size=20): :param page_size: 可选,每页的个数,默认20个,最大20个 :return: 返回的 JSON 数据包 """ - data = optionaldict( - shop_id=shop_id, - pageindex=page_index, - pagesize=page_size - ) - res = self._post( - 'device/list', - data=data, - result_processor=lambda x: x['data'] - ) + data = optionaldict(shop_id=shop_id, pageindex=page_index, pagesize=page_size) + res = self._post("device/list", data=data, result_processor=lambda x: x["data"]) return res def delete_device(self, bssid): @@ -106,7 +98,7 @@ def delete_device(self, bssid): :param bssid: 无线网络设备无线mac地址,格式冒号分隔,字符长度17个,并且字母小写 :return: 返回的 JSON 数据包 """ - return self._post('device/delete', data={'bssid': bssid}) + return self._post("device/delete", data={"bssid": bssid}) def get_qrcode_url(self, shop_id, img_id): """ @@ -121,12 +113,12 @@ def get_qrcode_url(self, shop_id, img_id): :return: 二维码图片网址 """ res = self._post( - 'qrcode/get', + "qrcode/get", data={ - 'shop_id': shop_id, - 'img_id': img_id, + "shop_id": shop_id, + "img_id": img_id, }, - result_processor=lambda x: x['data']['qrcode_url'] + result_processor=lambda x: x["data"]["qrcode_url"], ) return res @@ -143,12 +135,12 @@ def set_homepage(self, shop_id, template_id, url=None): :return: 返回的 JSON 数据包 """ data = { - 'shop_id': shop_id, - 'template_id': template_id, + "shop_id": shop_id, + "template_id": template_id, } if url: - data['struct'] = {'url': url} - return self._post('homepage/set', data=data) + data["struct"] = {"url": url} + return self._post("homepage/set", data=data) def get_homepage(self, shop_id): """ @@ -161,9 +153,9 @@ def get_homepage(self, shop_id): :return: 返回的 JSON 数据包 """ res = self._post( - 'homepage/get', - data={'shop_id': shop_id}, - result_processor=lambda x: x['data'] + "homepage/get", + data={"shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res @@ -180,16 +172,12 @@ def list_statistics(self, begin_date, end_date, shop_id=-1): :return: 返回的 JSON 数据包 """ if isinstance(begin_date, (datetime, date)): - begin_date = begin_date.strftime('%Y-%m-%d') + begin_date = begin_date.strftime("%Y-%m-%d") if isinstance(end_date, (datetime, date)): - end_date = end_date.strftime('%Y-%m-%d') + end_date = end_date.strftime("%Y-%m-%d") res = self._post( - 'statistics/list', - data={ - 'begin_date': begin_date, - 'end_date': end_date, - 'shop_id': shop_id - }, - result_processor=lambda x: x['data'] + "statistics/list", + data={"begin_date": begin_date, "end_date": end_date, "shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res diff --git a/chapter13/booking_system/exts/wechatpy/client/api/wxa.py b/chapter13/booking_system/exts/wechatpy/client/api/wxa.py index 1c44460..91077d3 100644 --- a/chapter13/booking_system/exts/wechatpy/client/api/wxa.py +++ b/chapter13/booking_system/exts/wechatpy/client/api/wxa.py @@ -7,7 +7,7 @@ class WeChatWxa(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create_qrcode(self, path, width=430): """ @@ -16,49 +16,49 @@ def create_qrcode(self, path, width=430): https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'cgi-bin/wxaapp/createwxaqrcode', - data={ - 'path': path, - 'width': width - } + "cgi-bin/wxaapp/createwxaqrcode", data={"path": path, "width": width} ) - def get_wxa_code(self, - path, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - is_hyaline=False): + def get_wxa_code( + self, + path, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + is_hyaline=False, + ): """ 创建小程序码(接口A: 适用于需要的码数量较少的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacode', + "wxa/getwxacode", data={ - 'path': path, - 'width': width, - 'auto_color': auto_color, - 'line_color': line_color, - 'is_hyaline': is_hyaline, - } + "path": path, + "width": width, + "auto_color": auto_color, + "line_color": line_color, + "is_hyaline": is_hyaline, + }, ) - def get_wxa_code_unlimited(self, - scene, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - page=None, - is_hyaline=False): + def get_wxa_code_unlimited( + self, + scene, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + page=None, + is_hyaline=False, + ): """ 创建小程序码(接口B:适用于需要的码数量极多,或仅临时使用的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacodeunlimit', + "wxa/getwxacodeunlimit", data=optionaldict( scene=scene, page=page, @@ -66,10 +66,19 @@ def get_wxa_code_unlimited(self, auto_color=auto_color, line_color=line_color, is_hyaline=is_hyaline, - ) + ), ) - def send_template_message(self, user_id, template_id, data, form_id, page=None, color=None, emphasis_keyword=None): + def send_template_message( + self, + user_id, + template_id, + data, + form_id, + page=None, + color=None, + emphasis_keyword=None, + ): """ 发送模板消息 详情请参考 @@ -84,12 +93,16 @@ def send_template_message(self, user_id, template_id, data, form_id, page=None, color=color, emphasis_keyword=emphasis_keyword, ) - return self._post( - 'cgi-bin/message/wxopen/template/send', - data=tpl_data - ) + return self._post("cgi-bin/message/wxopen/template/send", data=tpl_data) - def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_domain=(), download_domain=()): + def modify_domain( + self, + action, + request_domain=(), + wsrequest_domain=(), + upload_domain=(), + download_domain=(), + ): """ 修改小程序服务器授权域名 详情请参考 @@ -102,14 +115,14 @@ def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_d :param download_domain: download file 合法域名 """ return self._post( - 'wxa/modify_domain', + "wxa/modify_domain", data={ - 'action': action, - 'requestdomain': request_domain, - 'wsrequestdomain': wsrequest_domain, - 'uploaddomain': upload_domain, - 'downloaddomain': download_domain, - } + "action": action, + "requestdomain": request_domain, + "wsrequestdomain": wsrequest_domain, + "uploaddomain": upload_domain, + "downloaddomain": download_domain, + }, ) def bind_tester(self, wechat_id): @@ -121,10 +134,10 @@ def bind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/bind_tester', + "wxa/bind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def unbind_tester(self, wechat_id): @@ -136,10 +149,10 @@ def unbind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/unbind_tester', + "wxa/unbind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def commit(self, template_id, ext_json, version, description): @@ -154,12 +167,12 @@ def commit(self, template_id, ext_json, version, description): :param description: 代码描述,开发者可自定义 """ return self._post( - 'wxa/commit', + "wxa/commit", data={ - 'template_id': template_id, - 'ext_json': ext_json, - 'user_version': version, - 'user_desc': description, + "template_id": template_id, + "ext_json": ext_json, + "user_version": version, + "user_desc": description, }, ) @@ -172,7 +185,7 @@ def get_qrcode(self): :rtype: requests.Response """ - return self._get('wxa/get_qrcode') + return self._get("wxa/get_qrcode") def get_category(self): """ @@ -183,8 +196,8 @@ def get_category(self): :rtype: list[dict] """ return self._get( - 'wxa/get_category', - result_processor=lambda x: x['category_list'], + "wxa/get_category", + result_processor=lambda x: x["category_list"], ) def get_page(self): @@ -196,8 +209,8 @@ def get_page(self): :rtype: list """ return self._get( - 'wxa/get_page', - result_processor=lambda x: x['page_list'], + "wxa/get_page", + result_processor=lambda x: x["page_list"], ) def submit_audit(self, item_list): @@ -212,11 +225,11 @@ def submit_audit(self, item_list): :rtype: int """ return self._post( - 'wxa/submit_audit', + "wxa/submit_audit", data={ - 'item_list': item_list, + "item_list": item_list, }, - result_processor=lambda x: x['auditid'], + result_processor=lambda x: x["auditid"], ) def get_audit_status(self, auditid): @@ -230,9 +243,9 @@ def get_audit_status(self, auditid): :return: 一个包含 status, reason 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ return self._post( - 'wxa/get_auditstatus', + "wxa/get_auditstatus", data={ - 'auditid': auditid, + "auditid": auditid, }, ) @@ -244,9 +257,7 @@ def get_latest_audit_status(self): :return: 一个包含 status, reason, auditid 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ - return self._get( - 'wxa/get_latest_auditstatus' - ) + return self._get("wxa/get_latest_auditstatus") def release(self): """ @@ -255,7 +266,7 @@ def release(self): https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&id=open1489140610_Uavc4 """ return self._post( - 'wxa/release', + "wxa/release", data={}, ) @@ -269,9 +280,9 @@ def change_visit_status(self, close=False): :type close: bool """ return self._post( - 'wxa/change_visitstatus', + "wxa/change_visitstatus", data={ - 'action': 'close' if close else 'open', + "action": "close" if close else "open", }, ) @@ -289,10 +300,10 @@ def list_library_templates(self, offset=0, count=20): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/list', + "cgi-bin/wxopen/template/library/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, ) @@ -306,9 +317,9 @@ def get_library_template(self, template_short_id): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/get', + "cgi-bin/wxopen/template/library/get", data={ - 'id': template_short_id, + "id": template_short_id, }, ) @@ -326,12 +337,12 @@ def list_templates(self, offset=0, count=20): :rtype: list[dict] """ return self._post( - 'cgi-bin/wxopen/template/list', + "cgi-bin/wxopen/template/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, - result_processor=lambda x: x['list'], + result_processor=lambda x: x["list"], ) def add_template(self, template_short_id, keyword_id_list): @@ -346,12 +357,12 @@ def add_template(self, template_short_id, keyword_id_list): :return: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/add', + "cgi-bin/wxopen/template/add", data={ - 'id': template_short_id, - 'keyword_id_list': keyword_id_list, + "id": template_short_id, + "keyword_id_list": keyword_id_list, }, - result_processor=lambda x: x['template_id'], + result_processor=lambda x: x["template_id"], ) def del_template(self, template_id): @@ -363,9 +374,9 @@ def del_template(self, template_id): :param template_id: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/del', + "cgi-bin/wxopen/template/del", data={ - 'template_id': template_id, + "template_id": template_id, }, ) @@ -379,11 +390,11 @@ def create_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/create', + "cgi-bin/open/create", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def get_open(self, appid): @@ -396,11 +407,11 @@ def get_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/get', + "cgi-bin/open/get", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def bind_open(self, appid, open_appid): @@ -413,11 +424,11 @@ def bind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/bind', + "cgi-bin/open/bind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def unbind_open(self, appid, open_appid): @@ -430,11 +441,11 @@ def unbind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/unbind', + "cgi-bin/open/unbind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def code_to_session(self, js_code): @@ -447,11 +458,11 @@ def code_to_session(self, js_code): :return: """ return self._get( - 'sns/jscode2session', + "sns/jscode2session", params={ - 'appid': self.appid, - 'secret': self.secret, - 'js_code': js_code, - 'grant_type': 'authorization_code' - } + "appid": self.appid, + "secret": self.secret, + "js_code": js_code, + "grant_type": "authorization_code", + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/client/base.py b/chapter13/booking_system/exts/wechatpy/client/base.py index 88c7b85..1ac1b91 100644 --- a/chapter13/booking_system/exts/wechatpy/client/base.py +++ b/chapter13/booking_system/exts/wechatpy/client/base.py @@ -23,7 +23,7 @@ def _is_api_endpoint(obj): class BaseWeChatClient(object): - API_BASE_URL = '' + API_BASE_URL = "" def __new__(cls, *args, **kwargs): self = super(BaseWeChatClient, cls).__new__(cls) @@ -34,7 +34,9 @@ def __new__(cls, *args, **kwargs): setattr(self, name, api) return self - def __init__(self, appid, access_token=None, session=None, timeout=None, auto_retry=True): + def __init__( + self, appid, access_token=None, session=None, timeout=None, auto_retry=True + ): self._http = requests.Session() self.appid = appid self.expires_at = None @@ -47,7 +49,7 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -58,35 +60,30 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'access_token' not in kwargs['params']: - kwargs['params']['access_token'] = self.access_token - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - result_processor = kwargs.pop('result_processor', None) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "access_token" not in kwargs["params"] + ): + kwargs["params"]["access_token"] = self.access_token + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + result_processor = kwargs.pop("result_processor", None) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -95,24 +92,23 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - return self._handle_result( - res, method, url, result_processor, **kwargs - ) + return self._handle_result(res, method, url, result_processor, **kwargs) def _decode_result(self, res): try: - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) except (TypeError, ValueError): # Return origin response object if we can not decode it as JSON - logger.debug('Can not decode response as JSON', exc_info=True) + logger.debug("Can not decode response as JSON", exc_info=True) return res return result - def _handle_result(self, res, method=None, url=None, - result_processor=None, **kwargs): + def _handle_result( + self, res, method=None, url=None, result_processor=None, **kwargs + ): if not isinstance(res, dict): # Dirty hack around asyncio based AsyncWeChatClient result = self._decode_result(res) @@ -122,23 +118,24 @@ def _handle_result(self, res, method=None, url=None, if not isinstance(result, dict): return result - if 'base_resp' in result: + if "base_resp" in result: # Different response in device APIs. Fuck tencent! - result.update(result.pop('base_resp')) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result.update(result.pop("base_resp")) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Access token expired, fetch a new one and retry request') + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info("Access token expired, fetch a new one and retry request") self.fetch_access_token() access_token = self.session.get(self.access_token_key) - kwargs['params']['access_token'] = access_token + kwargs["params"]["access_token"] = access_token return self._request( method=method, url_or_endpoint=url, @@ -148,56 +145,43 @@ def _handle_result(self, res, method=None, url=None, elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result if not result_processor else result_processor(result) def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def _get(self, url, **kwargs): - warnings.warn('`_get` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `get` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_get` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `get` instead", + DeprecationWarning, + stacklevel=2, + ) return self.get(url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def _post(self, url, **kwargs): - warnings.warn('`_post` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `post` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_post` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `post` instead", + DeprecationWarning, + stacklevel=2, + ) return self.post(url, **kwargs) def _fetch_access_token(self, url, params): - """ The real fetch access token """ - logger.info('Fetching access token') - res = self._http.get( - url=url, - params=params - ) + """The real fetch access token""" + logger.info("Fetching access token") + res = self._http.get(url=url, params=params) try: res.raise_for_status() except requests.RequestException as reqe: @@ -206,26 +190,22 @@ def _fetch_access_token(self, url, params): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] - self.session.set( - self.access_token_key, - result['access_token'], - expires_in - ) + if "expires_in" in result: + expires_in = result["expires_in"] + self.session.set(self.access_token_key, result["access_token"], expires_in) self.expires_at = int(time.time()) + expires_in return result @@ -234,7 +214,7 @@ def fetch_access_token(self): @property def access_token(self): - """ WeChat access token """ + """WeChat access token""" access_token = self.session.get(self.access_token_key) if access_token: if not self.expires_at: diff --git a/chapter13/booking_system/exts/wechatpy/component.py b/chapter13/booking_system/exts/wechatpy/component.py index 980daa4..e663e23 100644 --- a/chapter13/booking_system/exts/wechatpy/component.py +++ b/chapter13/booking_system/exts/wechatpy/component.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.component - ~~~~~~~~~~~~~~~ +wechatpy.component +~~~~~~~~~~~~~~~ - This module provides client library for WeChat Open Platform +This module provides client library for WeChat Open Platform - :copyright: (c) 2015 by hunter007. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2015 by hunter007. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -22,8 +22,12 @@ from exts.wechatpy.client import WeChatComponentClient from exts.wechatpy.constants import WeChatErrorCode from exts.wechatpy.crypto import WeChatCrypto -from exts.wechatpy.exceptions import APILimitedException, WeChatClientException, WeChatOAuthException, \ - WeChatComponentOAuthException +from exts.wechatpy.exceptions import ( + APILimitedException, + WeChatClientException, + WeChatOAuthException, + WeChatComponentOAuthException, +) from exts.wechatpy.fields import DateTimeField, StringField from exts.wechatpy.messages import MessageMetaClass from exts.wechatpy.session.memorystorage import MemoryStorage @@ -38,22 +42,23 @@ def register_component_message(msg_type): def register(cls): COMPONENT_MESSAGE_TYPES[msg_type] = cls return cls + return register class BaseComponentMessage(six.with_metaclass(MessageMetaClass)): """Base class for all component messages and events""" - type = 'unknown' - appid = StringField('AppId') - create_time = DateTimeField('CreateTime') + + type = "unknown" + appid = StringField("AppId") + create_time = DateTimeField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -61,60 +66,67 @@ def __repr__(self): return to_text(_repr) -@register_component_message('component_verify_ticket') +@register_component_message("component_verify_ticket") class ComponentVerifyTicketMessage(BaseComponentMessage): """ component_verify_ticket协议 """ - type = 'component_verify_ticket' - verify_ticket = StringField('ComponentVerifyTicket') + + type = "component_verify_ticket" + verify_ticket = StringField("ComponentVerifyTicket") -@register_component_message('unauthorized') +@register_component_message("unauthorized") class ComponentUnauthorizedMessage(BaseComponentMessage): """ 取消授权通知 """ - type = 'unauthorized' - authorizer_appid = StringField('AuthorizerAppid') + type = "unauthorized" + authorizer_appid = StringField("AuthorizerAppid") -@register_component_message('authorized') + +@register_component_message("authorized") class ComponentAuthorizedMessage(ComponentUnauthorizedMessage): """ 新增授权通知 """ - type = 'authorized' - authorization_code = StringField('AuthorizationCode') - authorization_code_expired_time = StringField('AuthorizationCodeExpiredTime') - pre_auth_code = StringField('PreAuthCode') + + type = "authorized" + authorization_code = StringField("AuthorizationCode") + authorization_code_expired_time = StringField("AuthorizationCodeExpiredTime") + pre_auth_code = StringField("PreAuthCode") -@register_component_message('updateauthorized') +@register_component_message("updateauthorized") class ComponentUpdateauthorizedMessage(ComponentAuthorizedMessage): """ 更新授权通知 """ - type = 'updateauthorized' + + type = "updateauthorized" class ComponentUnknownMessage(BaseComponentMessage): """ 未知通知 """ - type = 'unknown' + type = "unknown" -class BaseWeChatComponent(object): - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin' - def __init__(self, - component_appid, - component_appsecret, - component_token, - encoding_aes_key, - session=None, - auto_retry=True): +class BaseWeChatComponent(object): + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin" + + def __init__( + self, + component_appid, + component_appsecret, + component_token, + encoding_aes_key, + session=None, + auto_retry=True, + ): """ :param component_appid: 第三方平台appid :param component_appsecret: 第三方平台appsecret @@ -125,8 +137,7 @@ def __init__(self, self.component_appid = component_appid self.component_appsecret = component_appsecret self.expires_at = None - self.crypto = WeChatCrypto( - component_token, encoding_aes_key, component_appid) + self.crypto = WeChatCrypto(component_token, encoding_aes_key, component_appid) self.session = session or MemoryStorage() self.auto_retry = auto_retry @@ -135,7 +146,7 @@ def __init__(self, from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -143,32 +154,26 @@ def __init__(self, @property def component_verify_ticket(self): - return self.session.get('component_verify_ticket') + return self.session.get("component_verify_ticket") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'component_access_token' not in kwargs['params']: - kwargs['params'][ - 'component_access_token'] = self.access_token - if isinstance(kwargs['data'], dict): - kwargs['data'] = json.dumps(kwargs['data']) - - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "component_access_token" not in kwargs["params"] + ): + kwargs["params"]["component_access_token"] = self.access_token + if isinstance(kwargs["data"], dict): + kwargs["data"] = json.dumps(kwargs["data"]) + + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -177,49 +182,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method, url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.fetch_access_token() - kwargs['params']['component_access_token'] = self.session.get( - 'component_access_token' + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + self.fetch_access_token() + kwargs["params"]["component_access_token"] = self.session.get( + "component_access_token" ) + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result @@ -231,26 +227,22 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ - url = '{0}{1}'.format( - self.API_BASE_URL, - '/component/api_component_token' - ) + url = "{0}{1}".format(self.API_BASE_URL, "/component/api_component_token") return self._fetch_access_token( url=url, - data=json.dumps({ - 'component_appid': self.component_appid, - 'component_appsecret': self.component_appsecret, - 'component_verify_ticket': self.component_verify_ticket - }) + data=json.dumps( + { + "component_appid": self.component_appid, + "component_appsecret": self.component_appsecret, + "component_verify_ticket": self.component_verify_ticket, + } + ), ) def _fetch_access_token(self, url, data): - """ The real fetch access token """ - logger.info('Fetching component access token') - res = self._http.post( - url=url, - data=data - ) + """The real fetch access token""" + logger.info("Fetching component access token") + res = self._http.post(url=url, data=data) try: res.raise_for_status() except requests.RequestException as reqe: @@ -259,33 +251,31 @@ def _fetch_access_token(self, url, data): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - 'component_access_token', - result['component_access_token'], - expires_in + "component_access_token", result["component_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result @property def access_token(self): - """ WeChat component access token """ - access_token = self.session.get('component_access_token') + """WeChat component access token""" + access_token = self.session.get("component_access_token") if access_token: if not self.expires_at: # order provided access_token, just return it @@ -296,41 +286,39 @@ def access_token(self): return access_token self.fetch_access_token() - return self.session.get('component_access_token') + return self.session.get("component_access_token") def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) class WeChatComponent(BaseWeChatComponent): - PRE_AUTH_URL = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage' + PRE_AUTH_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage" def get_pre_auth_url(self, redirect_uri): - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") return "{0}?component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - self.PRE_AUTH_URL, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri - ) + self.PRE_AUTH_URL, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, + ) def get_pre_auth_url_m(self, redirect_uri): """ 快速获取pre auth url,可以直接微信中发送该链接,直接授权 """ url = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=3&no_scan=1&" - redirect_uri = quote(redirect_uri, safe='') + redirect_uri = quote(redirect_uri, safe="") return "{0}component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - url, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri + url, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, ) def create_preauthcode(self): @@ -338,10 +326,8 @@ def create_preauthcode(self): 获取预授权码 """ return self.post( - '/component/api_create_preauthcode', - data={ - 'component_appid': self.component_appid - } + "/component/api_create_preauthcode", + data={"component_appid": self.component_appid}, ) def _query_auth(self, authorization_code): @@ -351,11 +337,11 @@ def _query_auth(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ return self.post( - '/component/api_query_auth', + "/component/api_query_auth", data={ - 'component_appid': self.component_appid, - 'authorization_code': authorization_code - } + "component_appid": self.component_appid, + "authorization_code": authorization_code, + }, ) def query_auth(self, authorization_code): @@ -366,28 +352,35 @@ def query_auth(self, authorization_code): """ result = self._query_auth(authorization_code) - assert result is not None \ - and 'authorization_info' in result \ - and 'authorizer_appid' in result['authorization_info'] + assert ( + result is not None + and "authorization_info" in result + and "authorizer_appid" in result["authorization_info"] + ) - authorizer_appid = result['authorization_info']['authorizer_appid'] - if 'authorizer_access_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_access_token']: - access_token = result['authorization_info']['authorizer_access_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + authorizer_appid = result["authorization_info"]["authorizer_appid"] + if ( + "authorizer_access_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_access_token"] + ): + access_token = result["authorization_info"]["authorizer_access_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in result['authorization_info']: - expires_in = result['authorization_info']['expires_in'] + if "expires_in" in result["authorization_info"]: + expires_in = result["authorization_info"]["expires_in"] self.session.set(access_token_key, access_token, expires_in) - if 'authorizer_refresh_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_refresh_token']: - refresh_token = result['authorization_info']['authorizer_refresh_token'] - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) - self.session.set(refresh_token_key, refresh_token) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 + if ( + "authorizer_refresh_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_refresh_token"] + ): + refresh_token = result["authorization_info"]["authorizer_refresh_token"] + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) + self.session.set( + refresh_token_key, refresh_token + ) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 return result - def refresh_authorizer_token( - self, authorizer_appid, authorizer_refresh_token): + def refresh_authorizer_token(self, authorizer_appid, authorizer_refresh_token): """ 获取(刷新)授权公众号的令牌 @@ -395,12 +388,12 @@ def refresh_authorizer_token( :params authorizer_refresh_token: 授权方的刷新令牌 """ return self.post( - '/component/api_authorizer_token', + "/component/api_authorizer_token", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'authorizer_refresh_token': authorizer_refresh_token - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "authorizer_refresh_token": authorizer_refresh_token, + }, ) def get_authorizer_info(self, authorizer_appid): @@ -410,11 +403,11 @@ def get_authorizer_info(self, authorizer_appid): :params authorizer_appid: 授权方appid """ return self.post( - '/component/api_get_authorizer_info', + "/component/api_get_authorizer_info", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + }, ) def get_authorizer_option(self, authorizer_appid, option_name): @@ -425,16 +418,15 @@ def get_authorizer_option(self, authorizer_appid, option_name): :params option_name: 选项名称 """ return self.post( - '/component/api_get_authorizer_option', + "/component/api_get_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + }, ) - def set_authorizer_option( - self, authorizer_appid, option_name, option_value): + def set_authorizer_option(self, authorizer_appid, option_name, option_value): """ 设置授权方的选项信息 @@ -443,13 +435,13 @@ def set_authorizer_option( :params option_value: 设置的选项值 """ return self.post( - '/component/api_set_authorizer_option', + "/component/api_set_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name, - 'option_value': option_value - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + "option_value": option_value, + }, ) def get_client_by_authorization_code(self, authorization_code): @@ -458,17 +450,19 @@ def get_client_by_authorization_code(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ - warnings.warn('`get_client_by_authorization_code` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` parse message and ' - 'Use `get_client_by_appid` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_client_by_authorization_code` method of `WeChatComponent` is deprecated," + "Use `parse_message` parse message and " + "Use `get_client_by_appid` instead", + DeprecationWarning, + stacklevel=2, + ) result = self.query_auth(authorization_code) - access_token = result['authorization_info']['authorizer_access_token'] - refresh_token = result['authorization_info']['authorizer_refresh_token'] # NOQA - authorizer_appid = result['authorization_info']['authorizer_appid'] # noqa + access_token = result["authorization_info"]["authorizer_access_token"] + refresh_token = result["authorization_info"]["authorizer_refresh_token"] # NOQA + authorizer_appid = result["authorization_info"]["authorizer_appid"] # noqa return WeChatComponentClient( - authorizer_appid, self, access_token, refresh_token, - session=self.session + authorizer_appid, self, access_token, refresh_token, session=self.session ) def get_client_by_appid(self, authorizer_appid): @@ -477,30 +471,23 @@ def get_client_by_appid(self, authorizer_appid): :params authorizer_appid: 授权公众号appid """ - access_token_key = '{0}_access_token'.format(authorizer_appid) - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) + access_token_key = "{0}_access_token".format(authorizer_appid) + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) access_token = self.session.get(access_token_key) refresh_token = self.session.get(refresh_token_key) assert refresh_token if not access_token: - ret = self.refresh_authorizer_token( - authorizer_appid, - refresh_token - ) - access_token = ret['authorizer_access_token'] - refresh_token = ret['authorizer_refresh_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + ret = self.refresh_authorizer_token(authorizer_appid, refresh_token) + access_token = ret["authorizer_access_token"] + refresh_token = ret["authorizer_refresh_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in ret: - expires_in = ret['expires_in'] + if "expires_in" in ret: + expires_in = ret["expires_in"] self.session.set(access_token_key, access_token, expires_in) - return WeChatComponentClient( - authorizer_appid, - self, - session=self.session - ) + return WeChatComponentClient(authorizer_appid, self, session=self.session) def parse_message(self, msg, msg_signature, timestamp, nonce): """ @@ -512,13 +499,15 @@ def parse_message(self, msg, msg_signature, timestamp, nonce): :params nonce: 随机数 """ content = self.crypto.decrypt_message(msg, msg_signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] - message_type = message['InfoType'].lower() - message_class = COMPONENT_MESSAGE_TYPES.get(message_type, ComponentUnknownMessage) + message = xmltodict.parse(to_text(content))["xml"] + message_type = message["InfoType"].lower() + message_class = COMPONENT_MESSAGE_TYPES.get( + message_type, ComponentUnknownMessage + ) msg = message_class(message) - if msg.type == 'component_verify_ticket': + if msg.type == "component_verify_ticket": self.session.set(msg.type, msg.verify_ticket) - elif msg.type in ('authorized', 'updateauthorized'): + elif msg.type in ("authorized", "updateauthorized"): msg.query_auth_result = self.query_auth(msg.authorization_code) return msg @@ -531,11 +520,14 @@ def cache_component_verify_ticket(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`cache_component_verify_ticket` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`cache_component_verify_ticket` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] o = ComponentVerifyTicketMessage(message) self.session.set(o.type, o.verify_ticket) @@ -548,11 +540,14 @@ def get_unauthorized(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`get_unauthorized` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_unauthorized` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] return ComponentUnauthorizedMessage(message) def get_component_oauth(self, authorizer_appid): @@ -565,16 +560,25 @@ def get_component_oauth(self, authorizer_appid): class ComponentOAuth(object): - """ 微信开放平台 代公众号 OAuth 网页授权 + """微信开放平台 代公众号 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' - def __init__(self, app_id, component_appid=None, component_access_token=None, - redirect_uri=None, scope='snsapi_base', state='', component=None): + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" + + def __init__( + self, + app_id, + component_appid=None, + component_access_token=None, + redirect_uri=None, + scope="snsapi_base", + state="", + component=None, + ): """ :param app_id: 微信公众号 app_id @@ -584,42 +588,55 @@ def __init__(self, app_id, component_appid=None, component_access_token=None, self.app_id = app_id self.component = component if self.component is None: - warnings.warn('cannot found `component` param of `ComponentOAuth` `__init__` method,' - 'Use `WeChatComponent.get_component_oauth` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "cannot found `component` param of `ComponentOAuth` `__init__` method," + "Use `WeChatComponent.get_component_oauth` instead", + DeprecationWarning, + stacklevel=2, + ) - self.component = ObjectDict({'component_appid': component_appid, 'access_token': component_access_token}) + self.component = ObjectDict( + { + "component_appid": component_appid, + "access_token": component_access_token, + } + ) if redirect_uri is not None: - warnings.warn('found `redirect_uri` param of `ComponentOAuth` `__init__` method,' - 'Use `ComponentOAuth.get_authorize_url` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "found `redirect_uri` param of `ComponentOAuth` `__init__` method," + "Use `ComponentOAuth.get_authorize_url` instead", + DeprecationWarning, + stacklevel=2, + ) self.authorize_url = self.get_authorize_url(redirect_uri, scope, state) - def get_authorize_url(self, redirect_uri, scope='snsapi_base', state=''): + def get_authorize_url(self, redirect_uri, scope="snsapi_base", state=""): """ :param redirect_uri: 重定向地址,需要urlencode,这里填写的应是服务开发方的回调地址 :param scope: 可选,微信公众号 OAuth2 scope,默认为 ``snsapi_base`` :param state: 可选,重定向后会带上state参数,开发者可以填写任意参数值,最多128字节 """ - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', + "&response_type=code&scope=", scope, ] if state: - url_list.extend(['&state=', state]) - url_list.extend([ - '&component_appid=', - self.component.component_appid, - ]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.extend( + [ + "&component_appid=", + self.component.component_appid, + ] + ) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -628,20 +645,20 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/access_token', + "sns/oauth2/component/access_token", params={ - 'appid': self.app_id, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - 'code': code, - 'grant_type': 'authorization_code', - } + "appid": self.app_id, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res def refresh_access_token(self, refresh_token): @@ -651,24 +668,24 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/refresh_token', + "sns/oauth2/component/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): - """ 获取用户基本信息(需授权作用域为snsapi_userinfo) + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): + """获取用户基本信息(需授权作用域为snsapi_userinfo) 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。 @@ -680,33 +697,24 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -715,53 +723,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method=method, url=url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.component.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.component.fetch_access_token() - kwargs['params']['component_access_token'] = self.component.access_token - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) + self.component.fetch_access_token() + kwargs["params"]["component_access_token"] = self.component.access_token + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatComponentOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) diff --git a/chapter13/booking_system/exts/wechatpy/constants.py b/chapter13/booking_system/exts/wechatpy/constants.py index 628476a..967736e 100644 --- a/chapter13/booking_system/exts/wechatpy/constants.py +++ b/chapter13/booking_system/exts/wechatpy/constants.py @@ -6,26 +6,28 @@ @unique class UserFormInfoFlag(Enum): - """ 微信卡券会员卡格式化的选项类型 """ - MOBILE = 'USER_FORM_INFO_FLAG_MOBILE' # 手机号 - SEX = 'USER_FORM_INFO_FLAG_SEX' # 性别 - NAME = 'USER_FORM_INFO_FLAG_NAME' # 姓名 - BIRTHDAY = 'USER_FORM_INFO_FLAG_BIRTHDAY' # 生日 - IDCARD = 'USER_FORM_INFO_FLAG_IDCARD' # 身份证 - EMAIL = 'USER_FORM_INFO_FLAG_EMAIL' # 邮箱 - LOCATION = 'USER_FORM_INFO_FLAG_LOCATION' # 详细地址 - EDUCATION_BACKGRO = 'USER_FORM_INFO_FLAG_EDUCATION_BACKGRO' # 教育背景 - INDUSTRY = 'USER_FORM_INFO_FLAG_INDUSTRY' # 行业 - INCOME = 'USER_FORM_INFO_FLAG_INCOME' # 收入 - HABIT = 'USER_FORM_INFO_FLAG_HABIT' # 兴趣爱好 + """微信卡券会员卡格式化的选项类型""" + + MOBILE = "USER_FORM_INFO_FLAG_MOBILE" # 手机号 + SEX = "USER_FORM_INFO_FLAG_SEX" # 性别 + NAME = "USER_FORM_INFO_FLAG_NAME" # 姓名 + BIRTHDAY = "USER_FORM_INFO_FLAG_BIRTHDAY" # 生日 + IDCARD = "USER_FORM_INFO_FLAG_IDCARD" # 身份证 + EMAIL = "USER_FORM_INFO_FLAG_EMAIL" # 邮箱 + LOCATION = "USER_FORM_INFO_FLAG_LOCATION" # 详细地址 + EDUCATION_BACKGRO = "USER_FORM_INFO_FLAG_EDUCATION_BACKGRO" # 教育背景 + INDUSTRY = "USER_FORM_INFO_FLAG_INDUSTRY" # 行业 + INCOME = "USER_FORM_INFO_FLAG_INCOME" # 收入 + HABIT = "USER_FORM_INFO_FLAG_HABIT" # 兴趣爱好 @unique class ReimburseStatus(Enum): - """ 发票报销状态 """ - INIT = 'INVOICE_REIMBURSE_INIT' # 初始状态,未锁定,可提交报销 - LOCK = 'INVOICE_REIMBURSE_LOCK' # 已锁定,无法重复提交报销 - CLOSURE = 'INVOICE_REIMBURSE_CLOSURE' # 已核销,从用户卡包中移除 + """发票报销状态""" + + INIT = "INVOICE_REIMBURSE_INIT" # 初始状态,未锁定,可提交报销 + LOCK = "INVOICE_REIMBURSE_LOCK" # 已锁定,无法重复提交报销 + CLOSURE = "INVOICE_REIMBURSE_CLOSURE" # 已核销,从用户卡包中移除 @unique @@ -33,6 +35,7 @@ class WeChatErrorCode(IntEnum): """ 微信接口返回码,全局返回码请参考 https://mp.weixin.qq.com/wiki?id=mp1433747234 """ + # 系统错误 SYSTEM_ERROR = -1000 diff --git a/chapter13/booking_system/exts/wechatpy/crypto/__init__.py b/chapter13/booking_system/exts/wechatpy/crypto/__init__.py index 4c93dbd..0df8905 100644 --- a/chapter13/booking_system/exts/wechatpy/crypto/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/crypto/__init__.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.crypto - ~~~~~~~~~~~~~~~~ +wechatpy.crypto +~~~~~~~~~~~~~~~~ - This module provides some crypto tools for WeChat and WeChat enterprise +This module provides some crypto tools for WeChat and WeChat enterprise - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import json @@ -14,10 +14,7 @@ import base64 from exts.wechatpy.utils import to_text, to_binary, WeChatSigner -from exts.wechatpy.exceptions import ( - InvalidAppIdException, - InvalidSignatureException -) +from exts.wechatpy.exceptions import InvalidAppIdException, InvalidSignatureException from exts.wechatpy.crypto.base import BasePrpCrypto, WeChatCipher from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder @@ -40,29 +37,22 @@ def decrypt(self, text, app_id): class BaseWeChatCrypto(object): def __init__(self, token, encoding_aes_key, _id): - encoding_aes_key = to_binary(encoding_aes_key + '=') + encoding_aes_key = to_binary(encoding_aes_key + "=") self.key = base64.b64decode(encoding_aes_key) assert len(self.key) == 32 self.token = token self._id = _id - def _check_signature(self, - signature, - timestamp, - nonce, - echo_str, - crypto_class=None): + def _check_signature( + self, signature, timestamp, nonce, echo_str, crypto_class=None + ): _signature = _get_signature(self.token, timestamp, nonce, echo_str) if _signature != signature: raise InvalidSignatureException() pc = crypto_class(self.key) return pc.decrypt(echo_str, self._id) - def _encrypt_message(self, - msg, - nonce, - timestamp=None, - crypto_class=None): + def _encrypt_message(self, msg, nonce, timestamp=None, crypto_class=None): from exts.wechatpy.replies import BaseReply xml = """ @@ -77,25 +67,19 @@ def _encrypt_message(self, pc = crypto_class(self.key) encrypt = to_text(pc.encrypt(msg, self._id)) signature = _get_signature(self.token, timestamp, nonce, encrypt) - return to_text(xml.format( - encrypt=encrypt, - signature=signature, - timestamp=timestamp, - nonce=nonce - )) - - def _decrypt_message(self, - msg, - signature, - timestamp, - nonce, - crypto_class=None): + return to_text( + xml.format( + encrypt=encrypt, signature=signature, timestamp=timestamp, nonce=nonce + ) + ) + + def _decrypt_message(self, msg, signature, timestamp, nonce, crypto_class=None): if not isinstance(msg, dict): import xmltodict - msg = xmltodict.parse(to_text(msg))['xml'] + msg = xmltodict.parse(to_text(msg))["xml"] - encrypt = msg['Encrypt'] + encrypt = msg["Encrypt"] _signature = _get_signature(self.token, timestamp, nonce, encrypt) if _signature != signature: raise InvalidSignatureException() @@ -113,13 +97,7 @@ def encrypt_message(self, msg, nonce, timestamp=None): return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) class WeChatWxaCrypto(object): @@ -132,6 +110,6 @@ def decrypt_message(self, msg): decrypted = self.cipher.decrypt(raw_data) plaintext = PKCS7Encoder.decode(decrypted) decrypted_msg = json.loads(to_text(plaintext)) - if decrypted_msg['watermark']['appid'] != self.app_id: + if decrypted_msg["watermark"]["appid"] != self.app_id: raise InvalidAppIdException() return decrypted_msg diff --git a/chapter13/booking_system/exts/wechatpy/crypto/base.py b/chapter13/booking_system/exts/wechatpy/crypto/base.py index e12300e..a6f60d3 100644 --- a/chapter13/booking_system/exts/wechatpy/crypto/base.py +++ b/chapter13/booking_system/exts/wechatpy/crypto/base.py @@ -6,13 +6,14 @@ from exts.wechatpy.utils import to_text, to_binary, random_string, byte2int from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder + try: from exts.wechatpy.crypto.cryptography import WeChatCipher except ImportError: try: from exts.wechatpy.crypto.pycrypto import WeChatCipher except ImportError: - raise Exception('You must install either cryptography or pycryptodome!') + raise Exception("You must install either cryptography or pycryptodome!") class BasePrpCrypto(object): @@ -27,12 +28,12 @@ def _encrypt(self, text, _id): text = to_binary(text) tmp_list = [] tmp_list.append(to_binary(self.get_random_string())) - length = struct.pack(b'I', socket.htonl(len(text))) + length = struct.pack(b"I", socket.htonl(len(text))) tmp_list.append(length) tmp_list.append(text) tmp_list.append(to_binary(_id)) - text = b''.join(tmp_list) + text = b"".join(tmp_list) text = PKCS7Encoder.encode(text) ciphertext = to_binary(self.cipher.encrypt(text)) @@ -43,9 +44,9 @@ def _decrypt(self, text, _id, exception=None): plain_text = self.cipher.decrypt(base64.b64decode(text)) padding = byte2int(plain_text[-1]) content = plain_text[16:-padding] - xml_length = socket.ntohl(struct.unpack(b'I', content[:4])[0]) - xml_content = to_text(content[4:xml_length + 4]) - from_id = to_text(content[xml_length + 4:]) + xml_length = socket.ntohl(struct.unpack(b"I", content[:4])[0]) + xml_content = to_text(content[4 : xml_length + 4]) + from_id = to_text(content[xml_length + 4 :]) if from_id != _id: exception = exception or Exception raise exception() diff --git a/chapter13/booking_system/exts/wechatpy/crypto/cryptography.py b/chapter13/booking_system/exts/wechatpy/crypto/cryptography.py index e63917f..944923e 100644 --- a/chapter13/booking_system/exts/wechatpy/crypto/cryptography.py +++ b/chapter13/booking_system/exts/wechatpy/crypto/cryptography.py @@ -9,11 +9,7 @@ class WeChatCipher(object): def __init__(self, key, iv=None): iv = iv or key[:16] backend = default_backend() - self.cipher = Cipher( - algorithms.AES(key), - modes.CBC(iv), - backend=backend - ) + self.cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) def encrypt(self, plaintext): encryptor = self.cipher.encryptor() diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/__init__.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/__init__.py index 89b19c6..94d6b23 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/__init__.py @@ -6,7 +6,7 @@ class WeChatClient(BaseWeChatClient): - API_BASE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin/" agent = api.WeChatAgent() appchat = api.WeChatAppChat() @@ -25,8 +25,15 @@ class WeChatClient(BaseWeChatClient): tag = api.WeChatTag() user = api.WeChatUser() - def __init__(self, corp_id, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + corp_id, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( corp_id, access_token, session, timeout, auto_retry ) @@ -35,14 +42,11 @@ def __init__(self, corp_id, secret, access_token=None, @property def access_token_key(self): - return '{0}_{1}_access_token'.format(self.corp_id, self.secret[:10]) + return "{0}_{1}_access_token".format(self.corp_id, self.secret[:10]) def fetch_access_token(self): - """ Fetch access token""" + """Fetch access token""" return self._fetch_access_token( - url='https://qyapi.weixin.qq.com/cgi-bin/gettoken', - params={ - 'corpid': self.corp_id, - 'corpsecret': self.secret - } + url="https://qyapi.weixin.qq.com/cgi-bin/gettoken", + params={"corpid": self.corp_id, "corpsecret": self.secret}, ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/agent.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/agent.py index 2ba1d4c..d969d72 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/agent.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/agent.py @@ -19,12 +19,7 @@ def get(self, agent_id): :param agent_id: 应用id :return: 返回的 JSON 数据包 """ - return self._get( - 'agent/get', - params={ - 'agentid': agent_id - } - ) + return self._get("agent/get", params={"agentid": agent_id}) def list(self): """ @@ -33,18 +28,20 @@ def list(self): :return: 应用概况列表 """ - res = self._get('agent/list') - return res['agentlist'] + res = self._get("agent/list") + return res["agentlist"] - def set(self, - agent_id, - name=None, - description=None, - redirect_domain=None, - logo_media_id=None, - report_location_flag=0, - is_report_user=True, - is_report_enter=True): + def set( + self, + agent_id, + name=None, + description=None, + redirect_domain=None, + logo_media_id=None, + report_location_flag=0, + is_report_user=True, + is_report_enter=True, + ): """ 设置应用 https://work.weixin.qq.com/api/doc#90000/90135/90228 @@ -60,15 +57,12 @@ def set(self, :return: 返回的 JSON 数据包 """ agent_data = optionaldict() - agent_data['agentid'] = agent_id - agent_data['name'] = name - agent_data['description'] = description - agent_data['redirect_domain'] = redirect_domain - agent_data['logo_mediaid'] = logo_media_id - agent_data['report_location_flag'] = report_location_flag - agent_data['isreportenter'] = 1 if is_report_enter else 0 - agent_data['isreportuser'] = 1 if is_report_user else 0 - return self._post( - 'agent/set', - data=agent_data - ) + agent_data["agentid"] = agent_id + agent_data["name"] = name + agent_data["description"] = description + agent_data["redirect_domain"] = redirect_domain + agent_data["logo_mediaid"] = logo_media_id + agent_data["report_location_flag"] = report_location_flag + agent_data["isreportenter"] = 1 if is_report_enter else 0 + agent_data["isreportuser"] = 1 if is_report_user else 0 + return self._post("agent/set", data=agent_data) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/appchat.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/appchat.py index e6a5b46..1feb9e6 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/appchat.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/appchat.py @@ -35,7 +35,7 @@ def create(self, chat_id=None, name=None, owner=None, user_list=None): owner=owner, userlist=user_list, ) - return self._post('appchat/create', data=data) + return self._post("appchat/create", data=data) def get(self, chat_id): """ @@ -47,11 +47,12 @@ def get(self, chat_id): :param chat_id: 群聊id :return: 会话信息 """ - res = self._get('appchat/get', params={'chatid': chat_id}) - return res['chat_info'] + res = self._get("appchat/get", params={"chatid": chat_id}) + return res["chat_info"] - def update(self, chat_id, name=None, owner=None, - add_user_list=None, del_user_list=None): + def update( + self, chat_id, name=None, owner=None, add_user_list=None, del_user_list=None + ): """ 修改群聊会话 @@ -72,7 +73,7 @@ def update(self, chat_id, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('appchat/update', data=data) + return self._post("appchat/update", data=data) def send(self, chat_id, msg_type, **kwargs): """ @@ -84,16 +85,13 @@ def send(self, chat_id, msg_type, **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = { - 'chatid': chat_id, - 'safe': kwargs.get('safe') or 0 - } + data = {"chatid": chat_id, "safe": kwargs.get("safe") or 0} data.update(self._build_msg_content(msg_type, **kwargs)) - return self._post('appchat/send', data=data) + return self._post("appchat/send", data=data) def send_msg(self, chat_id, msg_type, **kwargs): - """ deprecated, use `send` instead """ + """deprecated, use `send` instead""" return self.send(chat_id, msg_type, **kwargs) def send_text(self, chat_id, content, safe=0): @@ -107,9 +105,9 @@ def send_text(self, chat_id, content, safe=0): :param safe: 表示是否是保密消息,0表示否,1表示是,默认0 :return: """ - return self.send(chat_id, 'text', safe=safe, content=content) + return self.send(chat_id, "text", safe=safe, content=content) - def _build_msg_content(self, msgtype='text', **kwargs): + def _build_msg_content(self, msgtype="text", **kwargs): """ 构造消息内容 @@ -118,25 +116,25 @@ def _build_msg_content(self, msgtype='text', **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = {'msgtype': msgtype} - if msgtype == 'text': - data[msgtype] = {'content': kwargs.get('content')} - elif msgtype == 'image' or msgtype == 'voice' or msgtype == 'file': - data[msgtype] = {'media_id': kwargs.get('media_id')} - elif msgtype == 'video': + data = {"msgtype": msgtype} + if msgtype == "text": + data[msgtype] = {"content": kwargs.get("content")} + elif msgtype == "image" or msgtype == "voice" or msgtype == "file": + data[msgtype] = {"media_id": kwargs.get("media_id")} + elif msgtype == "video": data[msgtype] = { - 'media_id': kwargs.get('media_id'), - 'title': kwargs.get('title'), - 'description': kwargs.get('description') + "media_id": kwargs.get("media_id"), + "title": kwargs.get("title"), + "description": kwargs.get("description"), } - elif msgtype == 'textcard': + elif msgtype == "textcard": data[msgtype] = { - 'title': kwargs.get('title'), - 'description': kwargs.get('description'), - 'url': kwargs.get('url'), - 'btntxt': kwargs.get('btntxt'), + "title": kwargs.get("title"), + "description": kwargs.get("description"), + "url": kwargs.get("url"), + "btntxt": kwargs.get("btntxt"), } - elif msgtype == 'news': + elif msgtype == "news": # { # "articles" : # [ @@ -149,7 +147,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'mpnews': + elif msgtype == "mpnews": # { # "articles":[ # { @@ -163,7 +161,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'markdown': + elif msgtype == "markdown": # { # "content": "您的会议室已经预定,稍后会同步到`邮箱` # >**事项详情** @@ -181,5 +179,5 @@ def _build_msg_content(self, msgtype='text', **kwargs): # } data[msgtype] = kwargs else: - raise TypeError('不能识别的msgtype: %s' % msgtype) + raise TypeError("不能识别的msgtype: %s" % msgtype) return data diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/batch.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/batch.py index 8ed88d5..268ebf3 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/batch.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/batch.py @@ -30,16 +30,16 @@ def sync_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/syncuser', + "batch/syncuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): @@ -56,16 +56,16 @@ def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceuser', + "batch/replaceuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_party(self, url, token, encoding_aes_key, media_id): @@ -81,15 +81,15 @@ def replace_party(self, url, token, encoding_aes_key, media_id): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceparty', + "batch/replaceparty", data={ - 'media_id': media_id, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def get_result(self, job_id): @@ -101,7 +101,7 @@ def get_result(self, job_id): :param job_id: 异步任务id,最大长度为64字符 :return: 返回的 JSON 数据包 """ - return self._get('batch/getresult', params={'jobid': job_id}) + return self._get("batch/getresult", params={"jobid": job_id}) def invite(self, user=None, party=None, tag=None): """ @@ -117,10 +117,18 @@ def invite(self, user=None, party=None, tag=None): :return: 返回的 JSON 数据包 """ data = optionaldict(user=user, party=party, tag=tag) - return self._post('batch/invite', data=data) - - def invite_user(self, url, token, encoding_aes_key, user_ids=None, - party_ids=None, tag_ids=None, invite_tips=None): + return self._post("batch/invite", data=data) + + def invite_user( + self, + url, + token, + encoding_aes_key, + user_ids=None, + party_ids=None, + tag_ids=None, + invite_tips=None, + ): """ 邀请成员关注(deprecated) https://qydev.weixin.qq.com/wiki/index.php?title=异步任务接口 @@ -135,19 +143,19 @@ def invite_user(self, url, token, encoding_aes_key, user_ids=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['callback'] = { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key + data["callback"] = { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, } if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(map(to_text, user_ids)) + user_ids = "|".join(map(to_text, user_ids)) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(map(to_text, party_ids)) + party_ids = "|".join(map(to_text, party_ids)) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(map(to_text, tag_ids)) - data['touser'] = user_ids - data['toparty'] = party_ids - data['totag'] = tag_ids - data['invite_tips'] = invite_tips - return self._post('batch/inviteuser', data=data) + tag_ids = "|".join(map(to_text, tag_ids)) + data["touser"] = user_ids + data["toparty"] = party_ids + data["totag"] = tag_ids + data["invite_tips"] = invite_tips + return self._post("batch/inviteuser", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/chat.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/chat.py index da16e5c..a71f53c 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/chat.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/chat.py @@ -27,13 +27,13 @@ def create(self, chat_id, name, owner, user_list): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/create', + "chat/create", data={ - 'chatid': chat_id, - 'name': name, - 'owner': owner, - 'userlist': user_list, - } + "chatid": chat_id, + "name": name, + "owner": owner, + "userlist": user_list, + }, ) def get(self, chat_id): @@ -46,11 +46,18 @@ def get(self, chat_id): :param chat_id: 会话 ID :return: 会话信息 """ - res = self._get('chat/get', params={'chatid': chat_id}) - return res['chat_info'] - - def update(self, chat_id, op_user, name=None, owner=None, - add_user_list=None, del_user_list=None): + res = self._get("chat/get", params={"chatid": chat_id}) + return res["chat_info"] + + def update( + self, + chat_id, + op_user, + name=None, + owner=None, + add_user_list=None, + del_user_list=None, + ): """ 修改会话 @@ -73,7 +80,7 @@ def update(self, chat_id, op_user, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('chat/update', data=data) + return self._post("chat/update", data=data) def quit(self, chat_id, op_user): """ @@ -87,11 +94,11 @@ def quit(self, chat_id, op_user): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/quit', + "chat/quit", data={ - 'chatid': chat_id, - 'op_user': op_user, - } + "chatid": chat_id, + "op_user": op_user, + }, ) def clear_notify(self, op_user, type, id): @@ -107,14 +114,14 @@ def clear_notify(self, op_user, type, id): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/clearnotify', + "chat/clearnotify", data={ - 'op_user': op_user, - 'chat': { - 'type': type, - 'id': id, - } - } + "op_user": op_user, + "chat": { + "type": type, + "id": id, + }, + }, ) def set_mute(self, user_mute_list): @@ -127,10 +134,7 @@ def set_mute(self, user_mute_list): :param user_mute_list: 成员新消息免打扰参数,数组,最大支持10000个成员 :return: 返回的 JSON 数据包 """ - return self._post( - 'chat/setmute', - data={'user_mute_list': user_mute_list} - ) + return self._post("chat/setmute", data={"user_mute_list": user_mute_list}) def send_text(self, sender, receiver_type, receiver_id, content): """ @@ -146,17 +150,17 @@ def send_text(self, sender, receiver_type, receiver_id, content): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "text", + "text": { + "content": content, }, - 'sender': sender, - 'msgtype': 'text', - 'text': { - 'content': content, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_text(self, sender, receiver, content): """ @@ -167,7 +171,7 @@ def send_single_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'single', receiver, content) + return self.send_text(sender, "single", receiver, content) def send_group_text(self, sender, receiver, content): """ @@ -178,7 +182,7 @@ def send_group_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'group', receiver, content) + return self.send_text(sender, "group", receiver, content) def send_image(self, sender, receiver_type, receiver_id, media_id): """ @@ -194,17 +198,17 @@ def send_image(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "image", + "image": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'image', - 'image': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_image(self, sender, receiver, media_id): """ @@ -215,7 +219,7 @@ def send_single_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'single', receiver, media_id) + return self.send_image(sender, "single", receiver, media_id) def send_group_image(self, sender, receiver, media_id): """ @@ -226,7 +230,7 @@ def send_group_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'group', receiver, media_id) + return self.send_image(sender, "group", receiver, media_id) def send_file(self, sender, receiver_type, receiver_id, media_id): """ @@ -242,17 +246,17 @@ def send_file(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "file", + "file": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'file', - 'file': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_file(self, sender, receiver, media_id): """ @@ -263,7 +267,7 @@ def send_single_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'single', receiver, media_id) + return self.send_file(sender, "single", receiver, media_id) def send_group_file(self, sender, receiver, media_id): """ @@ -274,4 +278,4 @@ def send_group_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'group', receiver, media_id) + return self.send_file(sender, "group", receiver, media_id) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/department.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/department.py index d36893c..603c2ae 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/department.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/department.py @@ -23,13 +23,8 @@ def create(self, name, parent_id=1, order=None, id=None): :param id: 部门id,32位整型,指定时必须大于1。若不填该参数,将自动生成id :return: 返回的 JSON 数据包 """ - data = optionaldict( - name=name, - parentid=parent_id, - order=order, - id=id - ) - return self._post('department/create', data=data) + data = optionaldict(name=name, parentid=parent_id, order=order, id=id) + return self._post("department/create", data=data) def update(self, id, name=None, parent_id=None, order=None): """ @@ -43,13 +38,8 @@ def update(self, id, name=None, parent_id=None, order=None): :param order: 在父部门中的次序值。order值大的排序靠前。有效的值范围是[0, 2^32) :return: 返回的 JSON 数据包 """ - data = optionaldict( - id=id, - name=name, - parentid=parent_id, - order=order - ) - return self._post('department/update', data=data) + data = optionaldict(id=id, name=name, parentid=parent_id, order=order) + return self._post("department/update", data=data) def delete(self, id): """ @@ -60,7 +50,7 @@ def delete(self, id): :param id: 部门id。(注:不能删除根部门;不能删除含有子部门、成员的部门) :return: 返回的 JSON 数据包 """ - return self._get('department/delete', params={'id': id}) + return self._get("department/delete", params={"id": id}) def get(self, id=None): """ @@ -75,10 +65,10 @@ def get(self, id=None): :return: 部门列表 """ if id is None: - res = self._get('department/list') + res = self._get("department/list") else: - res = self._get('department/list', params={'id': id}) - return res['department'] + res = self._get("department/list", params={"id": id}) + return res["department"] def get_users(self, id, status=0, fetch_child=0, simple=True): """ @@ -92,13 +82,13 @@ def get_users(self, id, status=0, fetch_child=0, simple=True): :param simple: True 获取部门成员,False 获取部门成员详情 :return: 部门成员列表 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': id, - 'status': status, - 'fetch_child': 1 if fetch_child else 0 - } + "department_id": id, + "status": status, + "fetch_child": 1 if fetch_child else 0, + }, ) - return res['userlist'] + return res["userlist"] diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py index 59571df..d0b7be6 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py @@ -20,7 +20,7 @@ def get_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('get_jsapi_ticket') + return self._get("get_jsapi_ticket") def get_jsapi_signature(self, noncestr, ticket, timestamp, url): """ @@ -35,12 +35,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -52,7 +52,7 @@ def get_agent_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('ticket/get', params={'type': 'agent_config'}) + return self._get("ticket/get", params={"type": "agent_config"}) def get_jsapi_ticket(self): """ @@ -62,14 +62,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -82,14 +82,14 @@ def get_agent_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_agent_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_agent_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_agent_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_agent_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_agent_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/material.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/material.py index 9de5fef..2c23f37 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/material.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/material.py @@ -19,22 +19,19 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'material/add_mpnews', - data={ - "mpnews": { - "articles": articles_data + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } - } + ) + return self._post( + "material/add_mpnews", data={"mpnews": {"articles": articles_data}} ) def add(self, agent_id, media_type, media_file): @@ -49,15 +46,11 @@ def add(self, agent_id, media_type, media_file): :return: 返回的 JSON 数据包 """ params = { - 'agentid': agent_id, - 'type': media_type, + "agentid": agent_id, + "type": media_type, } return self._post( - url='material/add_material', - params=params, - files={ - 'media': media_file - } + url="material/add_material", params=params, files={"media": media_file} ) def get_url(self, agent_id, media_id): @@ -71,15 +64,15 @@ def get_url(self, agent_id, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/material/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/material/get", + "?access_token=", self.access_token, - '&media_id=', + "&media_id=", media_id, - '&agentid=', + "&agentid=", agent_id, ) - return ''.join(parts) + return "".join(parts) def get(self, agent_id, media_id): """ @@ -104,11 +97,11 @@ def get_articles(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get', + "material/get", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def delete(self, agent_id, media_id): @@ -122,11 +115,11 @@ def delete(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/del', + "material/del", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def update_articles(self, agent_id, media_id, articles): @@ -142,22 +135,20 @@ def update_articles(self, agent_id, media_id, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) return self._post( - 'material/update_news', - data={ - 'agentid': agent_id, - 'media_id': media_id, - 'articles': articles_data - } + "material/update_news", + data={"agentid": agent_id, "media_id": media_id, "articles": articles_data}, ) def get_count(self, agent_id): @@ -170,10 +161,10 @@ def get_count(self, agent_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get_count', + "material/get_count", params={ - 'agent_id': agent_id, - } + "agent_id": agent_id, + }, ) def batchget(self, agent_id, media_type, offset=0, count=20): @@ -190,11 +181,11 @@ def batchget(self, agent_id, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget', + "material/batchget", data={ - 'agent_id': agent_id, - 'type': media_type, - 'offset': offset, - 'count': count - } + "agent_id": agent_id, + "type": media_type, + "offset": offset, + "count": count, + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/media.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/media.py index 15762f3..4705bbf 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/media.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/media.py @@ -23,7 +23,9 @@ def upload(self, media_type, media_file): :param media_file: 要上传的文件,一个 File-object :return: 返回的 JSON 数据包 """ - return self._post('media/upload', params={'type': media_type}, files={'media': media_file}) + return self._post( + "media/upload", params={"type": media_type}, files={"media": media_file} + ) def upload_img(self, image_file): """ @@ -38,7 +40,7 @@ def upload_img(self, image_file): :return: 返回的 JSON 数据包 """ - return self._post('media/uploadimg', files={'media': image_file}) + return self._post("media/uploadimg", files={"media": image_file}) def get_url(self, media_id): """ @@ -50,13 +52,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def get_jssdk_url(self, media_id): """ @@ -68,13 +70,13 @@ def get_jssdk_url(self, media_id): :return: 高清语音素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def download(self, media_id): """ diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/menu.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/menu.py index 612fb25..41aabd2 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/menu.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/menu.py @@ -19,13 +19,7 @@ def create(self, agent_id, menu_data): :param agent_id: 应用id """ - return self._post( - 'menu/create', - params={ - 'agentid': agent_id - }, - data=menu_data - ) + return self._post("menu/create", params={"agentid": agent_id}, data=menu_data) def get(self, agent_id): """ @@ -35,12 +29,7 @@ def get(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/get', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/get", params={"agentid": agent_id}) def delete(self, agent_id): """ @@ -50,12 +39,7 @@ def delete(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/delete', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/delete", params={"agentid": agent_id}) def update(self, agent_id, menu_data): self.delete(agent_id) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/message.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/message.py index 21b2988..9952ebc 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/message.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/message.py @@ -25,8 +25,7 @@ class WeChatMessage(BaseWeChatAPI): * 小程序通知消息 """ - def send(self, agent_id, user_ids, party_ids='', - tag_ids='', msg=None): + def send(self, agent_id, user_ids, party_ids="", tag_ids="", msg=None): """ 通用的消息发送接口。msg 内需要指定 msgtype 和对应类型消息必须的字段。 如果部分接收人无权限或不存在,发送仍然执行,但会返回无效的部分(即invaliduser或invalidparty或invalidtag),常见的原因是接收人不在应用的可见范围内。 @@ -42,38 +41,42 @@ def send(self, agent_id, user_ids, party_ids='', """ msg = msg or {} if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(user_ids) + user_ids = "|".join(user_ids) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(party_ids) + party_ids = "|".join(party_ids) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(tag_ids) + tag_ids = "|".join(tag_ids) data = { - 'touser': user_ids, - 'toparty': party_ids, - 'totag': tag_ids, - 'agentid': agent_id + "touser": user_ids, + "toparty": party_ids, + "totag": tag_ids, + "agentid": agent_id, } data.update(msg) - return self._post('message/send', data=data) + return self._post("message/send", data=data) - def send_text(self, agent_id, user_ids, content, - party_ids='', tag_ids='', safe=0): + def send_text(self, agent_id, user_ids, content, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'text', - 'text': {'content': content}, - 'safe': safe - } + msg={"msgtype": "text", "text": {"content": content}, "safe": safe}, ) - def send_text_card(self, agent_id, user_ids, title, description, url, btntxt='详情', - party_ids='', tag_ids=''): - """ 文本卡片消息 + def send_text_card( + self, + agent_id, + user_ids, + title, + description, + url, + btntxt="详情", + party_ids="", + tag_ids="", + ): + """文本卡片消息 https://work.weixin.qq.com/api/doc#90000/90135/90236/文本卡片消息 @@ -113,129 +116,114 @@ def send_text_card(self, agent_id, user_ids, title, description, url, btntxt=' party_ids, tag_ids, msg={ - 'msgtype': 'textcard', - 'textcard': { - 'title': title, - 'description': description, - 'url': url, - 'btntxt': btntxt, + "msgtype": "textcard", + "textcard": { + "title": title, + "description": description, + "url": url, + "btntxt": btntxt, }, - } + }, ) - def send_image(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_image( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'image', - 'image': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "image", "image": {"media_id": media_id}, "safe": safe}, ) - def send_voice(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_voice( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "voice", "voice": {"media_id": media_id}, "safe": safe}, ) - def send_video(self, agent_id, user_ids, media_id, title=None, - description=None, party_ids='', tag_ids='', safe=0): + def send_video( + self, + agent_id, + user_ids, + media_id, + title=None, + description=None, + party_ids="", + tag_ids="", + safe=0, + ): video_data = optionaldict() - video_data['media_id'] = media_id - video_data['title'] = title - video_data['description'] = description + video_data["media_id"] = media_id + video_data["title"] = title + video_data["description"] = description return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'video', - 'video': dict(video_data), - 'safe': safe - } + msg={"msgtype": "video", "video": dict(video_data), "safe": safe}, ) - def send_file(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_file(self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'file', - 'file': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "file", "file": {"media_id": media_id}, "safe": safe}, ) - def send_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids=''): + def send_articles(self, agent_id, user_ids, articles, party_ids="", tag_ids=""): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article['image'] - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article["image"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } - } + msg={"msgtype": "news", "news": {"articles": articles_data}}, ) - def send_mp_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids='', safe=0): + def send_mp_articles( + self, agent_id, user_ids, articles, party_ids="", tag_ids="", safe=0 + ): articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'author': article['author'], - 'title': article['title'], - 'content': article['content'], - 'content_source_url': article['content_source_url'], - 'digest': article['digest'], - 'show_cover_pic': article['show_cover_pic'] - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "author": article["author"], + "title": article["title"], + "content": article["content"], + "content_source_url": article["content_source_url"], + "digest": article["digest"], + "show_cover_pic": article["show_cover_pic"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, msg={ - 'msgtype': 'mpnews', - 'mpnews': { - 'articles': articles_data - }, - 'safe': safe - } + "msgtype": "mpnews", + "mpnews": {"articles": articles_data}, + "safe": safe, + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/misc.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/misc.py index 54c356c..34c9e2f 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/misc.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/misc.py @@ -14,5 +14,5 @@ def get_wechat_ips(self): :return: 企业微信回调的IP段 """ - res = self._get('getcallbackip') - return res['ip_list'] + res = self._get("getcallbackip") + return res["ip_list"] diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/oauth.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/oauth.py index cffe7ca..9bb913a 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/oauth.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/oauth.py @@ -7,7 +7,7 @@ class WeChatOAuth(BaseWeChatAPI): - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize' + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" def authorize_url(self, redirect_uri, state=None): """ @@ -19,19 +19,19 @@ def authorize_url(self, redirect_uri, state=None): :param state: 重定向后会带上 state 参数 :return: 返回的 JSON 数据包 """ - redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b'') + redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - '?appid=', + "?appid=", self._client.corp_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=snsapi_base', + "&response_type=code&scope=snsapi_base", ] if state: - url_list.extend(['&state=', state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def get_user_info(self, code): """ @@ -44,8 +44,8 @@ def get_user_info(self, code): """ return self._get( - 'order/getuserinfo', + "order/getuserinfo", params={ - 'code': code, - } + "code": code, + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/service.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/service.py index 75ba8ee..2b4d083 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/service.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/service.py @@ -23,11 +23,11 @@ def get_provider_token(self, provider_secret): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_provider_token', + "service/get_provider_token", data={ - 'corpid': self._client.corp_id, - 'provider_secret': provider_secret, - } + "corpid": self._client.corp_id, + "provider_secret": provider_secret, + }, ) def get_suite_token(self, suite_id, suite_secret, suite_ticket): @@ -42,12 +42,12 @@ def get_suite_token(self, suite_id, suite_secret, suite_ticket): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_suite_token', + "service/get_suite_token", data={ - 'suite_id': suite_id, - 'suite_secret': suite_secret, - 'suite_ticket': suite_ticket - } + "suite_id": suite_id, + "suite_secret": suite_secret, + "suite_ticket": suite_ticket, + }, ) def get_login_info(self, auth_code, provider_access_token=None): @@ -62,16 +62,18 @@ def get_login_info(self, auth_code, provider_access_token=None): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_info', + "service/get_login_info", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'auth_code': auth_code, - } + "auth_code": auth_code, + }, ) - def get_login_url(self, login_ticket, target, agentid=None, provider_access_token=None): + def get_login_url( + self, login_ticket, target, agentid=None, provider_access_token=None + ): """ 获取登录企业号官网的url @@ -85,13 +87,13 @@ def get_login_url(self, login_ticket, target, agentid=None, provider_access_toke :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_url', + "service/get_login_url", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'login_ticket': login_ticket, - 'target': target, - 'agentid': agentid, - } + "login_ticket": login_ticket, + "target": target, + "agentid": agentid, + }, ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py index 0155576..047ebbc 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py @@ -15,10 +15,5 @@ def get_shake_info(self, ticket): :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 :return: 设备及用户信息 """ - res = self._post( - 'shakearound/getshakeinfo', - data={ - 'ticket': ticket - } - ) - return res['data'] + res = self._post("shakearound/getshakeinfo", data={"ticket": ticket}) + return res["data"] diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/tag.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/tag.py index dce5dd5..8db6f66 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/tag.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/tag.py @@ -12,56 +12,27 @@ class WeChatTag(BaseWeChatAPI): """ def create(self, name): - return self._post( - 'tag/create', - data={ - 'tagname': name - } - ) + return self._post("tag/create", data={"tagname": name}) def update(self, tag_id, name): - return self._post( - 'tag/update', - data={ - 'tagid': tag_id, - 'tagname': name - } - ) + return self._post("tag/update", data={"tagid": tag_id, "tagname": name}) def delete(self, tag_id): - return self._get( - 'tag/delete', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/delete", params={"tagid": tag_id}) def get_users(self, tag_id): - return self._get( - 'tag/get', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/get", params={"tagid": tag_id}) def add_users(self, tag_id, user_ids): return self._post( - 'tag/addtagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/addtagusers", data={"tagid": tag_id, "userlist": user_ids} ) def delete_users(self, tag_id, user_ids): return self._post( - 'tag/deltagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/deltagusers", data={"tagid": tag_id, "userlist": user_ids} ) def list(self): - res = self._get('tag/list') - return res['taglist'] + res = self._get("tag/list") + return res["taglist"] diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/user.py b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/user.py index bd5e367..e94404c 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/client/api/user.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/client/api/user.py @@ -15,30 +15,37 @@ class WeChatUser(BaseWeChatAPI): 邀请成员接口位于 `WeChatBatch.invite` """ - def create(self, user_id, name, department=None, position=None, - mobile=None, gender=0, tel=None, email=None, - weixin_id=None, extattr=None): + def create( + self, + user_id, + name, + department=None, + position=None, + mobile=None, + gender=0, + tel=None, + email=None, + weixin_id=None, + extattr=None, + ): """ 创建成员 https://work.weixin.qq.com/api/doc#90000/90135/90195 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - - return self._post( - 'order/create', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + + return self._post("order/create", data=user_data) def get(self, user_id): """ @@ -46,38 +53,41 @@ def get(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90196 """ - return self._get( - 'order/get', - params={ - 'userid': user_id - } - ) - - def update(self, user_id, name=None, department=None, position=None, - mobile=None, gender=None, tel=None, email=None, - weixin_id=None, enable=None, extattr=None): + return self._get("order/get", params={"userid": user_id}) + + def update( + self, + user_id, + name=None, + department=None, + position=None, + mobile=None, + gender=None, + tel=None, + email=None, + weixin_id=None, + enable=None, + extattr=None, + ): """ 更新成员 https://work.weixin.qq.com/api/doc#90000/90135/90197 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - user_data['enable'] = enable - - return self._post( - 'order/update', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + user_data["enable"] = enable + + return self._post("order/update", data=user_data) def delete(self, user_id): """ @@ -85,12 +95,7 @@ def delete(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90198 """ - return self._get( - 'order/delete', - params={ - 'userid': user_id - } - ) + return self._get("order/delete", params={"userid": user_id}) def batch_delete(self, user_ids): """ @@ -98,12 +103,7 @@ def batch_delete(self, user_ids): https://work.weixin.qq.com/api/doc#90000/90135/90199 """ - return self._post( - 'order/batchdelete', - data={ - 'useridlist': user_ids - } - ) + return self._post("order/batchdelete", data={"useridlist": user_ids}) def list(self, department_id, fetch_child=False, status=0, simple=False): """ @@ -114,16 +114,16 @@ def list(self, department_id, fetch_child=False, status=0, simple=False): 此接口和 `WeChatDepartment.get_users` 是同一个接口,区别为 simple 的默认值不同。 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': department_id, - 'fetch_child': 1 if fetch_child else 0, - 'status': status - } + "department_id": department_id, + "fetch_child": 1 if fetch_child else 0, + "status": status, + }, ) - return res['userlist'] + return res["userlist"] def convert_to_openid(self, user_id, agent_id=None): """ @@ -135,11 +135,8 @@ def convert_to_openid(self, user_id, agent_id=None): :param agent_id: 可选,需要发送红包的应用ID,若只是使用微信支付和企业转账,则无需该参数 :return: 返回的 JSON 数据包 """ - data = optionaldict( - userid=user_id, - agentid=agent_id - ) - return self._post('order/convert_to_openid', data=data) + data = optionaldict(userid=user_id, agentid=agent_id) + return self._post("order/convert_to_openid", data=data) def convert_to_user_id(self, openid): """ @@ -150,8 +147,8 @@ def convert_to_user_id(self, openid): :param openid: 在使用微信支付、微信红包和企业转账之后,返回结果的openid :return: 该 openid 在企业微信中对应的成员 user_id """ - res = self._post('order/convert_to_userid', data={'openid': openid}) - return res['userid'] + res = self._post("order/convert_to_userid", data={"openid": openid}) + return res["userid"] def verify(self, user_id): """ @@ -161,18 +158,9 @@ def verify(self, user_id): :param user_id: 成员UserID。对应管理端的帐号 """ - return self._get( - 'order/authsucc', - params={ - 'userid': user_id - } - ) + return self._get("order/authsucc", params={"userid": user_id}) def get_info(self, agent_id, code): return self._get( - 'order/getuserinfo', - params={ - 'agentid': agent_id, - 'code': code - } + "order/getuserinfo", params={"agentid": agent_id, "code": code} ) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/crypto.py b/chapter13/booking_system/exts/wechatpy/enterprise/crypto.py index 9b14bd6..90e6f4a 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/crypto.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/crypto.py @@ -20,27 +20,10 @@ def __init__(self, token, encoding_aes_key, corp_id): self.corp_id = corp_id def check_signature(self, signature, timestamp, nonce, echo_str): - return self._check_signature( - signature, - timestamp, - nonce, - echo_str, - PrpCrypto - ) + return self._check_signature(signature, timestamp, nonce, echo_str, PrpCrypto) def encrypt_message(self, msg, nonce, timestamp=None): - return self._encrypt_message( - msg, - nonce, - timestamp, - PrpCrypto - ) + return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/exceptions.py b/chapter13/booking_system/exts/wechatpy/enterprise/exceptions.py index a4ac5ee..13cd7f5 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/exceptions.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/exceptions.py @@ -6,5 +6,5 @@ class InvalidCorpIdException(WeChatException): - def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): + def __init__(self, errcode=-40005, errmsg="Invalid corp_id"): super(InvalidCorpIdException, self).__init__(errcode, errmsg) diff --git a/chapter13/booking_system/exts/wechatpy/enterprise/parser.py b/chapter13/booking_system/exts/wechatpy/enterprise/parser.py index 31fa199..7d1040d 100644 --- a/chapter13/booking_system/exts/wechatpy/enterprise/parser.py +++ b/chapter13/booking_system/exts/wechatpy/enterprise/parser.py @@ -12,10 +12,10 @@ def parse_message(xml): if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() - if message_type == 'event': - event_type = message['Event'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() + if message_type == "event": + event_type = message["Event"].lower() message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter13/booking_system/exts/wechatpy/events.py b/chapter13/booking_system/exts/wechatpy/events.py index eeb03db..a1ba320 100644 --- a/chapter13/booking_system/exts/wechatpy/events.py +++ b/chapter13/booking_system/exts/wechatpy/events.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.events - ~~~~~~~~~~~~~~~~ +wechatpy.events +~~~~~~~~~~~~~~~~ - This module contains all the events WeChat callback uses. +This module contains all the events WeChat callback uses. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -16,7 +16,7 @@ IntegerField, BaseField, Base64DecodeField, - DateTimeField + DateTimeField, ) from exts.wechatpy.messages import BaseMessage @@ -30,19 +30,22 @@ def register_event(event_type): :param event_type: Event type """ + def register(cls): EVENT_TYPES[event_type] = cls return cls + return register class BaseEvent(BaseMessage): """Base class for all events""" - type = 'event' - event = '' + + type = "event" + event = "" -@register_event('subscribe') +@register_event("subscribe") class SubscribeEvent(BaseEvent): """ 用户关注事件 @@ -50,11 +53,12 @@ class SubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe' - key = StringField('EventKey', '') + event = "subscribe" + key = StringField("EventKey", "") -@register_event('unsubscribe') + +@register_event("unsubscribe") class UnsubscribeEvent(BaseEvent): """ 用户取消关注事件 @@ -62,10 +66,11 @@ class UnsubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'unsubscribe' + + event = "unsubscribe" -@register_event('subscribe_scan') +@register_event("subscribe_scan") class SubscribeScanEvent(BaseEvent): """ 用户扫描二维码关注事件 @@ -73,12 +78,13 @@ class SubscribeScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe_scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + event = "subscribe_scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('scan') + +@register_event("scan") class ScanEvent(BaseEvent): """ 用户扫描二维码事件 @@ -86,12 +92,13 @@ class ScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + + event = "scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('location') +@register_event("location") class LocationEvent(BaseEvent): """ 上报地理位置事件 @@ -99,13 +106,14 @@ class LocationEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'location' - latitude = FloatField('Latitude', 0.0) - longitude = FloatField('Longitude', 0.0) - precision = FloatField('Precision', 0.0) + + event = "location" + latitude = FloatField("Latitude", 0.0) + longitude = FloatField("Longitude", 0.0) + precision = FloatField("Precision", 0.0) -@register_event('click') +@register_event("click") class ClickEvent(BaseEvent): """ 点击菜单拉取消息事件 @@ -113,11 +121,12 @@ class ClickEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'click' - key = StringField('EventKey') + event = "click" + key = StringField("EventKey") -@register_event('view') + +@register_event("view") class ViewEvent(BaseEvent): """ 点击菜单跳转链接事件 @@ -125,11 +134,12 @@ class ViewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'view' - url = StringField('EventKey') + + event = "view" + url = StringField("EventKey") -@register_event('masssendjobfinish') +@register_event("masssendjobfinish") class MassSendJobFinishEvent(BaseEvent): """ 群发消息任务完成事件 @@ -137,16 +147,17 @@ class MassSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1481187827_i0l21 """ - id = IntegerField('MsgID', 0) - event = 'masssendjobfinish' - status = StringField('Status') - total_count = IntegerField('TotalCount', 0) - filter_count = IntegerField('FilterCount', 0) - sent_count = IntegerField('SentCount', 0) - error_count = IntegerField('ErrorCount', 0) + id = IntegerField("MsgID", 0) + event = "masssendjobfinish" + status = StringField("Status") + total_count = IntegerField("TotalCount", 0) + filter_count = IntegerField("FilterCount", 0) + sent_count = IntegerField("SentCount", 0) + error_count = IntegerField("ErrorCount", 0) -@register_event('templatesendjobfinish') + +@register_event("templatesendjobfinish") class TemplateSendJobFinishEvent(BaseEvent): """ 模板消息任务完成事件 @@ -154,25 +165,26 @@ class TemplateSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1433751277 """ - id = IntegerField('MsgID') - event = 'templatesendjobfinish' - status = StringField('Status') + + id = IntegerField("MsgID") + event = "templatesendjobfinish" + status = StringField("Status") class BaseScanCodeEvent(BaseEvent): - key = StringField('EventKey') - scan_code_info = BaseField('ScanCodeInfo', {}) + key = StringField("EventKey") + scan_code_info = BaseField("ScanCodeInfo", {}) @property def scan_type(self): - return self.scan_code_info['ScanType'] + return self.scan_code_info["ScanType"] @property def scan_result(self): - return self.scan_code_info['ScanResult'] + return self.scan_code_info["ScanResult"] -@register_event('scancode_push') +@register_event("scancode_push") class ScanCodePushEvent(BaseScanCodeEvent): """ 扫码推事件 @@ -180,10 +192,11 @@ class ScanCodePushEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_push' + + event = "scancode_push" -@register_event('scancode_waitmsg') +@register_event("scancode_waitmsg") class ScanCodeWaitMsgEvent(BaseScanCodeEvent): """ 扫码推事件且弹出“消息接收中”提示框的事件 @@ -191,28 +204,29 @@ class ScanCodeWaitMsgEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_waitmsg' + + event = "scancode_waitmsg" class BasePictureEvent(BaseEvent): - key = StringField('EventKey') - pictures_info = BaseField('SendPicsInfo', {}) + key = StringField("EventKey") + pictures_info = BaseField("SendPicsInfo", {}) @property def count(self): - return int(self.pictures_info['Count']) + return int(self.pictures_info["Count"]) @property def pictures(self): - if self.pictures_info['PicList']: - items = self.pictures_info['PicList']['item'] + if self.pictures_info["PicList"]: + items = self.pictures_info["PicList"]["item"] if self.count > 1: return items return [items] return [] -@register_event('pic_sysphoto') +@register_event("pic_sysphoto") class PicSysPhotoEvent(BasePictureEvent): """ 弹出系统拍照发图的事件 @@ -220,10 +234,11 @@ class PicSysPhotoEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_sysphoto' + + event = "pic_sysphoto" -@register_event('pic_photo_or_album') +@register_event("pic_photo_or_album") class PicPhotoOrAlbumEvent(BasePictureEvent): """ 弹出拍照或者相册发图的事件 @@ -231,10 +246,11 @@ class PicPhotoOrAlbumEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_photo_or_album' + event = "pic_photo_or_album" -@register_event('pic_weixin') + +@register_event("pic_weixin") class PicWeChatEvent(BasePictureEvent): """ 弹出微信相册发图器的事件 @@ -242,10 +258,11 @@ class PicWeChatEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_weixin' + + event = "pic_weixin" -@register_event('location_select') +@register_event("location_select") class LocationSelectEvent(BaseEvent): """ 弹出地理位置选择器的事件 @@ -253,17 +270,18 @@ class LocationSelectEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'location_select' - key = StringField('EventKey') - location_info = BaseField('SendLocationInfo', {}) + + event = "location_select" + key = StringField("EventKey") + location_info = BaseField("SendLocationInfo", {}) @property def location_x(self): - return self.location_info['Location_X'] + return self.location_info["Location_X"] @property def location_y(self): - return self.location_info['Location_Y'] + return self.location_info["Location_Y"] @property def location(self): @@ -271,30 +289,30 @@ def location(self): @property def scale(self): - return self.location_info['Scale'] + return self.location_info["Scale"] @property def label(self): - return self.location_info['Label'] + return self.location_info["Label"] @property def poiname(self): - return self.location_info['Poiname'] + return self.location_info["Poiname"] -@register_event('card_pass_check') +@register_event("card_pass_check") class CardPassCheckEvent(BaseEvent): - event = 'card_pass_check' - card_id = StringField('CardId') + event = "card_pass_check" + card_id = StringField("CardId") -@register_event('card_not_pass_check') +@register_event("card_not_pass_check") class CardNotPassCheckEvent(BaseEvent): - event = 'card_not_pass_check' - card_id = StringField('CardId') + event = "card_not_pass_check" + card_id = StringField("CardId") -@register_event('user_get_card') +@register_event("user_get_card") class UserGetCardEvent(BaseEvent): """ 领取事件推送 @@ -302,16 +320,17 @@ class UserGetCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_get_card' - card_id = StringField('CardId') - is_given_by_friend = IntegerField('IsGiveByFriend') - friend = StringField('FriendUserName') - code = StringField('UserCardCode') - old_code = StringField('OldUserCardCode') - outer_id = StringField('OuterId') + + event = "user_get_card" + card_id = StringField("CardId") + is_given_by_friend = IntegerField("IsGiveByFriend") + friend = StringField("FriendUserName") + code = StringField("UserCardCode") + old_code = StringField("OldUserCardCode") + outer_id = StringField("OuterId") -@register_event('user_del_card') +@register_event("user_del_card") class UserDeleteCardEvent(BaseEvent): """ 卡券删除事件推送 @@ -319,12 +338,13 @@ class UserDeleteCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_del_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') + event = "user_del_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") -@register_event('user_consume_card') + +@register_event("user_consume_card") class UserConsumeCardEvent(BaseEvent): """ 卡券核销事件推送 @@ -332,95 +352,96 @@ class UserConsumeCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_consume_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') - consume_source = StringField('ConsumeSource') - location_id = StringField('LocationId') - staff = StringField('StaffOpenId') + + event = "user_consume_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") + consume_source = StringField("ConsumeSource") + location_id = StringField("LocationId") + staff = StringField("StaffOpenId") -@register_event('merchant_order') +@register_event("merchant_order") class MerchantOrderEvent(BaseEvent): - event = 'merchant_order' - order_id = StringField('OrderId') - order_status = IntegerField('OrderStatus') - product_id = StringField('ProductId') - sku_info = StringField('SkuInfo') + event = "merchant_order" + order_id = StringField("OrderId") + order_status = IntegerField("OrderStatus") + product_id = StringField("ProductId") + sku_info = StringField("SkuInfo") -@register_event('kf_create_session') +@register_event("kf_create_session") class KfCreateSessionEvent(BaseEvent): - event = 'kf_create_session' - account = StringField('KfAccount') + event = "kf_create_session" + account = StringField("KfAccount") -@register_event('kf_close_session') +@register_event("kf_close_session") class KfCloseSessionEvent(BaseEvent): - event = 'kf_close_session' - account = StringField('KfAccount') + event = "kf_close_session" + account = StringField("KfAccount") -@register_event('kf_switch_session') +@register_event("kf_switch_session") class KfSwitchSessionEvent(BaseEvent): - event = 'kf_switch_session' - from_account = StringField('FromKfAccount') - to_account = StringField('ToKfAccount') + event = "kf_switch_session" + from_account = StringField("FromKfAccount") + to_account = StringField("ToKfAccount") -@register_event('device_text') +@register_event("device_text") class DeviceTextEvent(BaseEvent): - event = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_bind') +@register_event("device_bind") class DeviceBindEvent(BaseEvent): - event = 'device_bind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_bind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_unbind') +@register_event("device_unbind") class DeviceUnbindEvent(BaseEvent): - event = 'device_unbind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_unbind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_subscribe_status') +@register_event("device_subscribe_status") class DeviceSubscribeStatusEvent(BaseEvent): - event = 'device_subscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_subscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('device_unsubscribe_status') +@register_event("device_unsubscribe_status") class DeviceUnsubscribeStatusEvent(BaseEvent): - event = 'device_unsubscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_unsubscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('shakearoundusershake') +@register_event("shakearoundusershake") class ShakearoundUserShakeEvent(BaseEvent): - event = 'shakearound_user_shake' - _chosen_beacon = BaseField('ChosenBeacon', {}) - _around_beacons = BaseField('AroundBeacons', {}) + event = "shakearound_user_shake" + _chosen_beacon = BaseField("ChosenBeacon", {}) + _around_beacons = BaseField("AroundBeacons", {}) @property def chosen_beacon(self): @@ -428,10 +449,10 @@ def chosen_beacon(self): if not beacon: return {} return { - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), } @property @@ -441,39 +462,41 @@ def around_beacons(self): return [] ret = [] - for beacon in beacons['AroundBeacon']: - ret.append({ - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), - }) + for beacon in beacons["AroundBeacon"]: + ret.append( + { + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), + } + ) return ret -@register_event('poi_check_notify') +@register_event("poi_check_notify") class PoiCheckNotifyEvent(BaseEvent): - event = 'poi_check_notify' - poi_id = StringField('PoiId') - uniq_id = StringField('UniqId') - result = StringField('Result') - message = StringField('Msg') + event = "poi_check_notify" + poi_id = StringField("PoiId") + uniq_id = StringField("UniqId") + result = StringField("Result") + message = StringField("Msg") -@register_event('wificonnected') +@register_event("wificonnected") class WiFiConnectedEvent(BaseEvent): - event = 'wificconnected' - connect_time = IntegerField('ConnectTime') - expire_time = IntegerField('ExpireTime') - vendor_id = StringField('VendorId') - shop_id = StringField('PlaceId') - bssid = StringField('DeviceNo') + event = "wificconnected" + connect_time = IntegerField("ConnectTime") + expire_time = IntegerField("ExpireTime") + vendor_id = StringField("VendorId") + shop_id = StringField("PlaceId") + bssid = StringField("DeviceNo") # ============================================================================ # 微信认证事件推送 # ============================================================================ -@register_event('qualification_verify_success') +@register_event("qualification_verify_success") class QualificationVerifySuccessEvent(BaseEvent): """ 资质认证成功事件 @@ -481,11 +504,12 @@ class QualificationVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "qualification_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('qualification_verify_fail') +@register_event("qualification_verify_fail") class QualificationVerifyFailEvent(BaseEvent): """ 资质认证失败事件 @@ -493,12 +517,13 @@ class QualificationVerifyFailEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "qualification_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('naming_verify_success') + +@register_event("naming_verify_success") class NamingVerifySuccessEvent(BaseEvent): """ 名称认证成功事件 @@ -506,11 +531,12 @@ class NamingVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "naming_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('naming_verify_fail') +@register_event("naming_verify_fail") class NamingVerifyFailEvent(BaseEvent): """ 名称认证失败事件 @@ -518,12 +544,13 @@ class NamingVerifyFailEvent(BaseEvent): 客户端不打勾,但仍有接口权限。详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "naming_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('annual_renew') + +@register_event("annual_renew") class AnnualRenewEvent(BaseEvent): """ 年审通知事件 @@ -531,11 +558,12 @@ class AnnualRenewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'annual_renew' - expired_time = DateTimeField('ExpiredTime') + + event = "annual_renew" + expired_time = DateTimeField("ExpiredTime") -@register_event('verify_expired') +@register_event("verify_expired") class VerifyExpiredEvent(BaseEvent): """ 认证过期失效通知 @@ -543,11 +571,12 @@ class VerifyExpiredEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'verify_expired' - expired_time = DateTimeField('ExpiredTime') + event = "verify_expired" + expired_time = DateTimeField("ExpiredTime") -@register_event('user_scan_product') + +@register_event("user_scan_product") class UserScanProductEvent(BaseEvent): """ 打开商品主页事件 @@ -555,17 +584,18 @@ class UserScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - country = StringField('Country') - province = StringField('Province') - city = StringField('City') - sex = IntegerField('Sex') - scene = IntegerField('Scene') + + event = "user_scan_product" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + country = StringField("Country") + province = StringField("Province") + city = StringField("City") + sex = IntegerField("Sex") + scene = IntegerField("Scene") -@register_event('user_scan_product_enter_session') +@register_event("user_scan_product_enter_session") class UserScanProductEnterSessionEvent(BaseEvent): """ 进入公众号事件 @@ -573,12 +603,13 @@ class UserScanProductEnterSessionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_enter_session' - standard = StringField('KeyStandard') - key = StringField('KeyStr') + event = "user_scan_product_enter_session" + standard = StringField("KeyStandard") + key = StringField("KeyStr") -@register_event('user_scan_product_async') + +@register_event("user_scan_product_async") class UserScanProductAsyncEvent(BaseEvent): """ 地理位置信息异步推送事件 @@ -586,13 +617,14 @@ class UserScanProductAsyncEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_async' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - region_code = StringField('RegionCode') + + event = "user_scan_product_async" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + region_code = StringField("RegionCode") -@register_event('user_scan_product_verify_action') +@register_event("user_scan_product_verify_action") class UserScanProductVerifyActionEvent(BaseEvent): """ 商品审核结果事件 @@ -600,14 +632,15 @@ class UserScanProductVerifyActionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_verify_action' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - result = StringField('Result') - reason = StringField('ReasonMsg') + + event = "user_scan_product_verify_action" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + result = StringField("Result") + reason = StringField("ReasonMsg") -@register_event('subscribe_scan_product') +@register_event("subscribe_scan_product") class SubscribeScanProductEvent(BaseEvent): """ 用户在商品主页中关注公众号事件 @@ -615,23 +648,24 @@ class SubscribeScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'subscribe_scan_product' - event_key = StringField('EventKey') + + event = "subscribe_scan_product" + event_key = StringField("EventKey") @property def scene(self): - return self.event_key.split('|', 1)[0] + return self.event_key.split("|", 1)[0] @property def standard(self): - return self.event_key.split('|')[1] + return self.event_key.split("|")[1] @property def key(self): - return self.event_key.split('|')[2] + return self.event_key.split("|")[2] -@register_event('user_authorize_invoice') +@register_event("user_authorize_invoice") class UserAuthorizeInvoiceEvent(BaseEvent): """ 用户授权发票事件 @@ -640,14 +674,15 @@ class UserAuthorizeInvoiceEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'user_authorize_invoice' - success_order_id = StringField('SuccOrderId') # 授权成功的订单号 - fail_order_id = StringField('FailOrderId') # 授权失败的订单号 - app_id = StringField('AppId') # 用于接收事件推送的公众号的AppId - auth_source = StringField('Source') # 授权来源,web表示来自微信内H5,app标识来自app + + event = "user_authorize_invoice" + success_order_id = StringField("SuccOrderId") # 授权成功的订单号 + fail_order_id = StringField("FailOrderId") # 授权失败的订单号 + app_id = StringField("AppId") # 用于接收事件推送的公众号的AppId + auth_source = StringField("Source") # 授权来源,web表示来自微信内H5,app标识来自app -@register_event('update_invoice_status') +@register_event("update_invoice_status") class UpdateInvoiceStatusEvent(BaseEvent): """ 发票状态更新事件 @@ -655,13 +690,14 @@ class UpdateInvoiceStatusEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'update_invoice_status' - status = StringField('Status') # 发票报销状态 - card_id = StringField('CardId') # 发票 Card ID - code = StringField('Code') # 发票 Code + event = "update_invoice_status" + status = StringField("Status") # 发票报销状态 + card_id = StringField("CardId") # 发票 Card ID + code = StringField("Code") # 发票 Code -@register_event('submit_invoice_title') + +@register_event("submit_invoice_title") class SubmitInvoiceTitleEvent(BaseEvent): """ 用户提交发票抬头事件 @@ -669,33 +705,38 @@ class SubmitInvoiceTitleEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0 """ - event = 'submit_invoice_title' - title = StringField('title') # 抬头 - phone = StringField('phone') # 联系方式 - tax_no = StringField('tax_no') # 税号 - addr = StringField('addr') # 地址 - bank_type = StringField('bank_type') # 银行类型 - bank_no = StringField('bank_no') # 银行号码 - attach = StringField('attach') # 附加字段 - title_type = StringField('title_type') # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType + + event = "submit_invoice_title" + title = StringField("title") # 抬头 + phone = StringField("phone") # 联系方式 + tax_no = StringField("tax_no") # 税号 + addr = StringField("addr") # 地址 + bank_type = StringField("bank_type") # 银行类型 + bank_no = StringField("bank_no") # 银行号码 + attach = StringField("attach") # 附加字段 + title_type = StringField( + "title_type" + ) # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType -@register_event('user_enter_tempsession') +@register_event("user_enter_tempsession") class UserEnterTempSessionEvent(BaseEvent): """ 小程序用户进入客服消息 详情请参阅 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/receive.html """ - event = 'user_enter_tempsession' - session_from = StringField('SessionFrom') + event = "user_enter_tempsession" + session_from = StringField("SessionFrom") -@register_event('view_miniprogram') + +@register_event("view_miniprogram") class ViewMiniProgramEvent(BaseEvent): """ 从菜单进入小程序事件 """ - event = 'view_miniprogram' - page_path = StringField('EventKey') # 小程序路径 - menu_id = StringField('MenuId') # 菜单ID + + event = "view_miniprogram" + page_path = StringField("EventKey") # 小程序路径 + menu_id = StringField("MenuId") # 菜单ID diff --git a/chapter13/booking_system/exts/wechatpy/exceptions.py b/chapter13/booking_system/exts/wechatpy/exceptions.py index 683da28..f347485 100644 --- a/chapter13/booking_system/exts/wechatpy/exceptions.py +++ b/chapter13/booking_system/exts/wechatpy/exceptions.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.exceptions - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.exceptions +~~~~~~~~~~~~~~~~~~~~ - Basic exceptions definition. +Basic exceptions definition. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -27,9 +27,8 @@ def __init__(self, errcode, errmsg): self.errmsg = errmsg def __str__(self): - _repr = 'Error code: {code}, message: {msg}'.format( - code=self.errcode, - msg=self.errmsg + _repr = "Error code: {code}, message: {msg}".format( + code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -37,10 +36,8 @@ def __str__(self): return to_text(_repr) def __repr__(self): - _repr = '{klass}({code}, {msg})'.format( - klass=self.__class__.__name__, - code=self.errcode, - msg=self.errmsg + _repr = "{klass}({code}, {msg})".format( + klass=self.__class__.__name__, code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -51,8 +48,7 @@ def __repr__(self): class WeChatClientException(WeChatException): """WeChat API client exception class""" - def __init__(self, errcode, errmsg, client=None, - request=None, response=None): + def __init__(self, errcode, errmsg, client=None, request=None, response=None): super(WeChatClientException, self).__init__(errcode, errmsg) self.client = client self.request = request @@ -62,38 +58,49 @@ def __init__(self, errcode, errmsg, client=None, class InvalidSignatureException(WeChatException): """Invalid signature exception class""" - def __init__(self, errcode=-40001, errmsg='Invalid signature'): + def __init__(self, errcode=-40001, errmsg="Invalid signature"): super(InvalidSignatureException, self).__init__(errcode, errmsg) class APILimitedException(WeChatClientException): """WeChat API call limited exception class""" + pass class InvalidAppIdException(WeChatException): """Invalid app_id exception class""" - def __init__(self, errcode=-40005, errmsg='Invalid AppId'): + def __init__(self, errcode=-40005, errmsg="Invalid AppId"): super(InvalidAppIdException, self).__init__(errcode, errmsg) class WeChatOAuthException(WeChatClientException): """WeChat OAuth API exception class""" + pass class WeChatComponentOAuthException(WeChatClientException): """WeChat Component OAuth API exception class""" + pass class WeChatPayException(WeChatClientException): """WeChat Pay API exception class""" - def __init__(self, return_code, result_code=None, return_msg=None, - errcode=None, errmsg=None, client=None, - request=None, response=None): + def __init__( + self, + return_code, + result_code=None, + return_msg=None, + errcode=None, + errmsg=None, + client=None, + request=None, + response=None, + ): """ :param return_code: 返回状态码 :param result_code: 业务结果 @@ -102,11 +109,7 @@ def __init__(self, return_code, result_code=None, return_msg=None, :param errmsg: 错误代码描述 """ super(WeChatPayException, self).__init__( - errcode, - errmsg, - client, - request, - response + errcode, errmsg, client, request, response ) self.return_code = return_code self.result_code = result_code @@ -114,27 +117,31 @@ def __init__(self, return_code, result_code=None, return_msg=None, def __str__(self): if six.PY2: - return to_binary('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_binary( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) else: - return to_text('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_text( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) def __repr__(self): - _repr = '{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})'.format( + _repr = "{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})".format( klass=self.__class__.__name__, code=self.return_code, msg=self.return_msg, pay_code=self.errcode, - pay_msg=self.errmsg + pay_msg=self.errmsg, ) if six.PY2: return to_binary(_repr) diff --git a/chapter13/booking_system/exts/wechatpy/fields.py b/chapter13/booking_system/exts/wechatpy/fields.py index 8db6847..9a4bdf9 100644 --- a/chapter13/booking_system/exts/wechatpy/fields.py +++ b/chapter13/booking_system/exts/wechatpy/fields.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.fields - ~~~~~~~~~~~~~~~~ +wechatpy.fields +~~~~~~~~~~~~~~~~ - This module defines some useful field types for parse WeChat messages +This module defines some useful field types for parse WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -19,7 +19,7 @@ from exts.wechatpy.utils import to_text, to_binary, ObjectDict, timezone -default_timezone = timezone('Asia/Shanghai') +default_timezone = timezone("Asia/Shanghai") class FieldDescriptor(object): @@ -36,8 +36,11 @@ def __get__(self, instance, instance_type=None): instance._data[self.attr_name] = value if isinstance(value, dict): value = ObjectDict(value) - if value and not isinstance(value, (dict, list, tuple)) and \ - six.callable(self.field.converter): + if ( + value + and not isinstance(value, (dict, list, tuple)) + and six.callable(self.field.converter) + ): value = self.field.converter(value) return value return self.field @@ -61,9 +64,8 @@ def from_xml(cls, value): raise NotImplementedError() def __repr__(self): - _repr = '{klass}({name})'.format( - klass=self.__class__.__name__, - name=repr(self.name) + _repr = "{klass}({name})".format( + klass=self.__class__.__name__, name=repr(self.name) ) if six.PY2: return to_binary(_repr) @@ -85,7 +87,7 @@ def __to_text(self, value): def to_xml(self, value): value = self.converter(value) - tpl = '<{name}>' + tpl = "<{name}>" return tpl.format(name=self.name, value=value) @classmethod @@ -98,7 +100,7 @@ class IntegerField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -110,12 +112,13 @@ class DateTimeField(BaseField): def __converter(self, value): v = int(value) return datetime.fromtimestamp(v, tz=default_timezone) + converter = __converter def to_xml(self, value): value = time.mktime(datetime.timetuple(value)) value = int(value) - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -128,7 +131,7 @@ class FloatField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -167,62 +170,66 @@ def from_xml(cls, value): class VideoField(StringField): def to_xml(self, value): - kwargs = dict(media_id=self.converter(value['media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' + kwargs = dict(media_id=self.converter(value["media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" tpl = """""".format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(media_id=value['MediaId']) - if 'Title' in value: - rv["title"] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] + rv = dict(media_id=value["MediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] return rv class MusicField(StringField): def to_xml(self, value): - kwargs = dict(thumb_media_id=self.converter(value['thumb_media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' - if 'music_url' in value: - kwargs['music_url'] = self.converter(value['music_url']) - content += '' - if 'hq_music_url' in value: - kwargs['hq_music_url'] = self.converter(value['hq_music_url']) - content += '' + kwargs = dict(thumb_media_id=self.converter(value["thumb_media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" + if "music_url" in value: + kwargs["music_url"] = self.converter(value["music_url"]) + content += "" + if "hq_music_url" in value: + kwargs["hq_music_url"] = self.converter(value["hq_music_url"]) + content += "" tpl = """ {content} - """.format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(thumb_media_id=value['ThumbMediaId']) - if 'Title' in value: - rv['title'] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] - if 'MusicUrl' in value: - rv['music_url'] = value['MusicUrl'] - if 'HQMusicUrl' in value: - rv['hq_music_url'] = value['HQMusicUrl'] + rv = dict(thumb_media_id=value["ThumbMediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] + if "MusicUrl" in value: + rv["music_url"] = value["MusicUrl"] + if "HQMusicUrl" in value: + rv["hq_music_url"] = value["HQMusicUrl"] return rv @@ -232,10 +239,10 @@ def to_xml(self, articles): article_count = len(articles) items = [] for article in articles: - title = self.converter(article.get('title', '')) - description = self.converter(article.get('description', '')) - image = self.converter(article.get('image', '')) - url = self.converter(article.get('url', '')) + title = self.converter(article.get("title", "")) + description = self.converter(article.get("description", "")) + image = self.converter(article.get("image", "")) + url = self.converter(article.get("url", "")) item_tpl = """ <![CDATA[{title}]]> @@ -243,28 +250,25 @@ def to_xml(self, articles): """ item = item_tpl.format( - title=title, - description=description, - image=image, - url=url + title=title, description=description, image=image, url=url ) items.append(item) - items_str = '\n'.join(items) + items_str = "\n".join(items) tpl = """{article_count} {items}""" - return tpl.format( - article_count=article_count, - items=items_str - ) + return tpl.format(article_count=article_count, items=items_str) @classmethod def from_xml(cls, value): - return [dict( - title=item["Title"], - description=item["Description"], - image=item["PicUrl"], - url=item["Url"] - ) for item in value["item"]] + return [ + dict( + title=item["Title"], + description=item["Description"], + image=item["PicUrl"], + url=item["Url"], + ) + for item in value["item"] + ] class Base64EncodeField(StringField): @@ -286,13 +290,11 @@ def __base64_decode(self, text): class HardwareField(StringField): def to_xml(self, value=None): - value = value or {'view': 'myrank', 'action': 'ranklist'} + value = value or {"view": "myrank", "action": "ranklist"} tpl = """<{name}> """ return tpl.format( - name=self.name, - view=value.get('view'), - action=value.get('action') + name=self.name, view=value.get("view"), action=value.get("action") ) diff --git a/chapter13/booking_system/exts/wechatpy/messages.py b/chapter13/booking_system/exts/wechatpy/messages.py index 04f4d0c..9e33666 100644 --- a/chapter13/booking_system/exts/wechatpy/messages.py +++ b/chapter13/booking_system/exts/wechatpy/messages.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.messages - ~~~~~~~~~~~~~~~~~~ +wechatpy.messages +~~~~~~~~~~~~~~~~~~ - This module defines all the messages you can get from WeChat server +This module defines all the messages you can get from WeChat server - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import copy @@ -17,7 +17,7 @@ StringField, IntegerField, DateTimeField, - FieldDescriptor + FieldDescriptor, ) from exts.wechatpy.utils import to_text, to_binary @@ -29,14 +29,16 @@ def register_message(msg_type): def register(cls): MESSAGE_TYPES[msg_type] = cls return cls + return register class MessageMetaClass(type): """Metaclass for all messages""" + def __new__(cls, name, bases, attrs): for b in bases: - if not hasattr(b, '_fields'): + if not hasattr(b, "_fields"): continue for k, v in b.__dict__.items(): @@ -56,20 +58,20 @@ def __new__(cls, name, bases, attrs): class BaseMessage(six.with_metaclass(MessageMetaClass)): """Base class for all messages and events""" - type = 'unknown' - id = IntegerField('MsgId', 0) - source = StringField('FromUserName') - target = StringField('ToUserName') - create_time = DateTimeField('CreateTime') - time = IntegerField('CreateTime') + + type = "unknown" + id = IntegerField("MsgId", 0) + source = StringField("FromUserName") + target = StringField("ToUserName") + create_time = DateTimeField("CreateTime") + time = IntegerField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -77,97 +79,105 @@ def __repr__(self): return to_text(_repr) -@register_message('text') +@register_message("text") class TextMessage(BaseMessage): """ 文本消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_message('image') + +@register_message("image") class ImageMessage(BaseMessage): """ 图片消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'image' - media_id = StringField('MediaId') - image = StringField('PicUrl') + + type = "image" + media_id = StringField("MediaId") + image = StringField("PicUrl") -@register_message('voice') +@register_message("voice") class VoiceMessage(BaseMessage): """ 语音消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'voice' - media_id = StringField('MediaId') - format = StringField('Format') - recognition = StringField('Recognition') + + type = "voice" + media_id = StringField("MediaId") + format = StringField("Format") + recognition = StringField("Recognition") -@register_message('shortvideo') +@register_message("shortvideo") class ShortVideoMessage(BaseMessage): """ 短视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'shortvideo' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + type = "shortvideo" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('video') + +@register_message("video") class VideoMessage(BaseMessage): """ 视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'video' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + + type = "video" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('location') +@register_message("location") class LocationMessage(BaseMessage): """ 地理位置消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'location' - location_x = StringField('Location_X') - location_y = StringField('Location_Y') - scale = StringField('Scale') - label = StringField('Label') + + type = "location" + location_x = StringField("Location_X") + location_y = StringField("Location_Y") + scale = StringField("Scale") + label = StringField("Label") @property def location(self): return self.location_x, self.location_y -@register_message('link') +@register_message("link") class LinkMessage(BaseMessage): """ 链接消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'link' - title = StringField('Title') - description = StringField('Description') - url = StringField('Url') + + type = "link" + title = StringField("Title") + description = StringField("Description") + url = StringField("Url") class UnknownMessage(BaseMessage): """未知消息类型""" + pass diff --git a/chapter13/booking_system/exts/wechatpy/oauth.py b/chapter13/booking_system/exts/wechatpy/oauth.py index db5743a..984cffa 100644 --- a/chapter13/booking_system/exts/wechatpy/oauth.py +++ b/chapter13/booking_system/exts/wechatpy/oauth.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.oauth - ~~~~~~~~~~~~~~~ +wechatpy.oauth +~~~~~~~~~~~~~~~ - This module provides OAuth2 library for WeChat +This module provides OAuth2 library for WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -18,16 +18,16 @@ class WeChatOAuth(object): - """ 微信公众平台 OAuth 网页授权 + """微信公众平台 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" - def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): + def __init__(self, app_id, secret, redirect_uri, scope="snsapi_base", state=""): """ :param app_id: 微信公众号 app_id @@ -44,24 +44,19 @@ def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): self._http = requests.Session() def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -70,29 +65,21 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result['errmsg'] + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result["errmsg"] raise WeChatOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) @property def authorize_url(self): @@ -100,20 +87,20 @@ def authorize_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - self.scope + "&response_type=code&scope=", + self.scope, ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) @property def qrconnect_url(self): @@ -121,20 +108,20 @@ def qrconnect_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'qrconnect?appid=', + "qrconnect?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - 'snsapi_login' # scope + "&response_type=code&scope=", + "snsapi_login", # scope ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -143,18 +130,18 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/access_token', + "sns/oauth2/access_token", params={ - 'appid': self.app_id, - 'secret': self.secret, - 'code': code, - 'grant_type': 'authorization_code' - } + "appid": self.app_id, + "secret": self.secret, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res def refresh_access_token(self, refresh_token): @@ -164,20 +151,20 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/refresh_token', + "sns/oauth2/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): """获取用户信息 :param openid: 可选,微信 openid,默认获取当前授权用户信息 @@ -188,12 +175,8 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def check_access_token(self, openid=None, access_token=None): @@ -206,12 +189,8 @@ def check_access_token(self, openid=None, access_token=None): openid = openid or self.open_id access_token = access_token or self.access_token res = self._get( - 'sns/auth', - params={ - 'access_token': access_token, - 'openid': openid - } + "sns/auth", params={"access_token": access_token, "openid": openid} ) - if res['errcode'] == 0: + if res["errcode"] == 0: return True return False diff --git a/chapter13/booking_system/exts/wechatpy/parser.py b/chapter13/booking_system/exts/wechatpy/parser.py index 11f3af7..0706fae 100644 --- a/chapter13/booking_system/exts/wechatpy/parser.py +++ b/chapter13/booking_system/exts/wechatpy/parser.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.parser - ~~~~~~~~~~~~~~~~ - This module provides functions for parsing WeChat messages +wechatpy.parser +~~~~~~~~~~~~~~~~ +This module provides functions for parsing WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import xmltodict @@ -24,28 +24,28 @@ def parse_message(xml): """ if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() event_type = None - if message_type == 'event' or message_type.startswith('device_'): - if 'Event' in message: - event_type = message['Event'].lower() + if message_type == "event" or message_type.startswith("device_"): + if "Event" in message: + event_type = message["Event"].lower() # special event type for device_event - if event_type is None and message_type.startswith('device_'): + if event_type is None and message_type.startswith("device_"): event_type = message_type - elif message_type.startswith('device_'): - event_type = 'device_{event}'.format(event=event_type) + elif message_type.startswith("device_"): + event_type = "device_{event}".format(event=event_type) - if event_type == 'subscribe' and message.get('EventKey'): - event_key = message['EventKey'] - if event_key.startswith(('scanbarcode|', 'scanimage|')): - event_type = 'subscribe_scan_product' - message['Event'] = event_type - elif event_key.startswith('qrscene_'): + if event_type == "subscribe" and message.get("EventKey"): + event_key = message["EventKey"] + if event_key.startswith(("scanbarcode|", "scanimage|")): + event_type = "subscribe_scan_product" + message["Event"] = event_type + elif event_key.startswith("qrscene_"): # Scan to subscribe with scene id event - event_type = 'subscribe_scan' - message['Event'] = event_type - message['EventKey'] = event_key[len('qrscene_'):] + event_type = "subscribe_scan" + message["Event"] = event_type + message["EventKey"] = event_key[len("qrscene_") :] message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter13/booking_system/exts/wechatpy/pay/__init__.py b/chapter13/booking_system/exts/wechatpy/pay/__init__.py index ff9dc96..e7ce60d 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/__init__.py +++ b/chapter13/booking_system/exts/wechatpy/pay/__init__.py @@ -11,7 +11,10 @@ from exts.wechatpy.utils import random_string from exts.wechatpy.exceptions import WeChatPayException, InvalidSignatureException from exts.wechatpy.pay.utils import ( - calculate_signature, calculate_signature_hmac, _check_signature, dict_to_xml + calculate_signature, + calculate_signature_hmac, + _check_signature, + dict_to_xml, ) from exts.wechatpy.pay.base import BaseWeChatPayAPI from exts.wechatpy.pay import api @@ -57,7 +60,7 @@ class WeChatPay(object): withhold = api.WeChatWithhold() """代扣接口""" - API_BASE_URL = 'https://api.mch.weixin.qq.com/' + API_BASE_URL = "https://api.mch.weixin.qq.com/" def __new__(cls, *args, **kwargs): self = super(WeChatPay, cls).__new__(cls) @@ -68,8 +71,18 @@ def __new__(cls, *args, **kwargs): setattr(self, name, _api) return self - def __init__(self, appid, api_key, mch_id, sub_mch_id=None, - mch_cert=None, mch_key=None, timeout=None, sandbox=False, sub_appid=None): + def __init__( + self, + appid, + api_key, + mch_id, + sub_mch_id=None, + mch_cert=None, + mch_key=None, + timeout=None, + sandbox=False, + sub_appid=None, + ): self.appid = appid self.sub_appid = sub_appid self.api_key = api_key @@ -84,56 +97,58 @@ def __init__(self, appid, api_key, mch_id, sub_mch_id=None, def _fetch_sandbox_api_key(self): nonce_str = random_string(32) - sign = calculate_signature({'mch_id': self.mch_id, 'nonce_str': nonce_str}, self.api_key) - payload = dict_to_xml({ - 'mch_id': self.mch_id, - 'nonce_str': nonce_str, - }, sign=sign) - headers = {'Content-Type': 'text/xml'} - api_url = '{base}sandboxnew/pay/getsignkey'.format(base=self.API_BASE_URL) + sign = calculate_signature( + {"mch_id": self.mch_id, "nonce_str": nonce_str}, self.api_key + ) + payload = dict_to_xml( + { + "mch_id": self.mch_id, + "nonce_str": nonce_str, + }, + sign=sign, + ) + headers = {"Content-Type": "text/xml"} + api_url = "{base}sandboxnew/pay/getsignkey".format(base=self.API_BASE_URL) response = self._http.post(api_url, data=payload, headers=headers) - return xmltodict.parse(response.text)['xml'].get('sandbox_signkey') + return xmltodict.parse(response.text)["xml"].get("sandbox_signkey") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) if self.sandbox: - api_base_url = '{url}sandboxnew/'.format(url=api_base_url) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + api_base_url = "{url}sandboxnew/".format(url=api_base_url) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - data = kwargs['data'] - if 'mchid' not in data: + if isinstance(kwargs.get("data", ""), dict): + data = kwargs["data"] + if "mchid" not in data: # Fuck Tencent - data.setdefault('mch_id', self.mch_id) - data.setdefault('sub_mch_id', self.sub_mch_id) - data.setdefault('nonce_str', random_string(32)) + data.setdefault("mch_id", self.mch_id) + data.setdefault("sub_mch_id", self.sub_mch_id) + data.setdefault("nonce_str", random_string(32)) data = optionaldict(data) - if data.get('sign_type', 'MD5') == 'HMAC-SHA256': - sign = calculate_signature_hmac(data, self.sandbox_api_key if self.sandbox else self.api_key) + if data.get("sign_type", "MD5") == "HMAC-SHA256": + sign = calculate_signature_hmac( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) else: - sign = calculate_signature(data, self.sandbox_api_key if self.sandbox else self.api_key) + sign = calculate_signature( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) body = dict_to_xml(data, sign) - body = body.encode('utf-8') - kwargs['data'] = body + body = body.encode("utf-8") + kwargs["data"] = body # 商户证书 if self.mch_cert and self.mch_key: - kwargs['cert'] = (self.mch_cert, self.mch_key) - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - logger.debug('Request to WeChat API: %s %s\n%s', method, url, kwargs) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + kwargs["cert"] = (self.mch_cert, self.mch_key) + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + logger.debug("Request to WeChat API: %s %s\n%s", method, url, kwargs) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -141,28 +156,28 @@ def _request(self, method, url_or_endpoint, **kwargs): return_code=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res) def _handle_result(self, res): - res.encoding = 'utf-8' + res.encoding = "utf-8" xml = res.text - logger.debug('Response from WeChat API \n %s', xml) + logger.debug("Response from WeChat API \n %s", xml) try: - data = xmltodict.parse(xml)['xml'] + data = xmltodict.parse(xml)["xml"] except (xmltodict.ParsingInterrupted, ExpatError): # 解析 XML 失败 - logger.debug('WeChat payment result xml parsing error', exc_info=True) + logger.debug("WeChat payment result xml parsing error", exc_info=True) return xml - return_code = data['return_code'] - return_msg = data.get('return_msg') - result_code = data.get('result_code') - errcode = data.get('err_code') - errmsg = data.get('err_code_des') - if return_code != 'SUCCESS' or result_code != 'SUCCESS': + return_code = data["return_code"] + return_msg = data.get("return_msg") + result_code = data.get("result_code") + errcode = data.get("err_code") + errmsg = data.get("err_code_des") + if return_code != "SUCCESS" or result_code != "SUCCESS": # 返回状态码不为成功 raise WeChatPayException( return_code, @@ -172,26 +187,20 @@ def _handle_result(self, res): errmsg, client=self, request=res.request, - response=res + response=res, ) return data def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def check_signature(self, params): - return _check_signature(params, self.api_key if not self.sandbox else self.sandbox_api_key) + return _check_signature( + params, self.api_key if not self.sandbox else self.sandbox_api_key + ) def parse_payment_result(self, xml): """解析微信支付结果通知""" @@ -200,22 +209,30 @@ def parse_payment_result(self, xml): except (xmltodict.ParsingInterrupted, ExpatError): raise InvalidSignatureException() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise InvalidSignatureException() - data = data['xml'] - sign = data.pop('sign', None) - if '#text' in data.keys(): + data = data["xml"] + sign = data.pop("sign", None) + if "#text" in data.keys(): pass - del data['#text'] - real_sign = calculate_signature(data, self.api_key if not self.sandbox else self.sandbox_api_key) + del data["#text"] + real_sign = calculate_signature( + data, self.api_key if not self.sandbox else self.sandbox_api_key + ) if sign != real_sign: raise InvalidSignatureException() - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) - data['sign'] = sign + data["sign"] = sign return data @property diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/coupon.py b/chapter13/booking_system/exts/wechatpy/pay/api/coupon.py index 53cd0bc..fe97cfd 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/coupon.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/coupon.py @@ -8,8 +8,9 @@ class WeChatCoupon(BaseWeChatPayAPI): - def send(self, user_id, stock_id, op_user_id=None, device_info=None, - out_trade_no=None): + def send( + self, user_id, stock_id, op_user_id=None, device_info=None, out_trade_no=None + ): """ 发放代金券 @@ -22,23 +23,21 @@ def send(self, user_id, stock_id, op_user_id=None, device_info=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'openid': user_id, - 'openid_count': 1, - 'partner_trade_no': out_trade_no, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "openid": user_id, + "openid_count": 1, + "partner_trade_no": out_trade_no, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/send_coupon', data=data) + return self._post("mmpaymkttransfers/send_coupon", data=data) def query_stock(self, stock_id, op_user_id=None, device_info=None): """ @@ -50,17 +49,16 @@ def query_stock(self, stock_id, op_user_id=None, device_info=None): :return: 返回的结果信息 """ data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/query_coupon_stock', data=data) + return self._post("mmpaymkttransfers/query_coupon_stock", data=data) - def query_coupon(self, coupon_id, user_id, - op_user_id=None, device_info=None): + def query_coupon(self, coupon_id, user_id, op_user_id=None, device_info=None): """ 查询代金券信息 @@ -71,12 +69,12 @@ def query_coupon(self, coupon_id, user_id, :return: 返回的结果信息 """ data = { - 'coupon_id': coupon_id, - 'openid': user_id, - 'appid': self.appid, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "coupon_id": coupon_id, + "openid": user_id, + "appid": self.appid, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('promotion/query_coupon', data=data) + return self._post("promotion/query_coupon", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/jsapi.py b/chapter13/booking_system/exts/wechatpy/pay/api/jsapi.py index 79ed209..a818fe8 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/jsapi.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/jsapi.py @@ -8,6 +8,7 @@ logger = logging.getLogger(__name__) + class WeChatJSAPI(BaseWeChatPayAPI): def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): @@ -20,15 +21,19 @@ def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } return calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=False): @@ -44,18 +49,22 @@ def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=Fals :return: 参数 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } sign = calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) - logger.debug('JSAPI payment parameters: data = %s, sign = %s', data, sign) - data['paySign'] = sign + logger.debug("JSAPI payment parameters: data = %s, sign = %s", data, sign) + data["paySign"] = sign if jssdk: - data['timestamp'] = data.pop('timeStamp') + data["timestamp"] = data.pop("timeStamp") return data diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/micropay.py b/chapter13/booking_system/exts/wechatpy/pay/api/micropay.py index 30e8714..439cf19 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/micropay.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/micropay.py @@ -8,8 +8,20 @@ class WeChatMicroPay(BaseWeChatPayAPI): - def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', goods_tag=None, device_info=None, limit_pay=None): + def create( + self, + body, + total_fee, + auth_code, + client_ip=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + device_info=None, + limit_pay=None, + ): """ 刷卡支付接口 :param device_info: 可选,终端设备号(商户自定义,如门店编号) @@ -27,26 +39,24 @@ def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, """ now = datetime.now() if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'total_fee': total_fee, - 'fee_type': fee_type, - 'spbill_create_ip': client_ip or get_external_ip(), - 'goods_tag': goods_tag, - 'limit_pay': limit_pay, - 'auth_code': auth_code, + "appid": self.appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "total_fee": total_fee, + "fee_type": fee_type, + "spbill_create_ip": client_ip or get_external_ip(), + "goods_tag": goods_tag, + "limit_pay": limit_pay, + "auth_code": auth_code, } - return self._post('pay/micropay', data=data) + return self._post("pay/micropay", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -57,8 +67,8 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/order.py b/chapter13/booking_system/exts/wechatpy/pay/api/order.py index ebc3549..68005fd 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/order.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/order.py @@ -13,10 +13,27 @@ class WeChatOrder(BaseWeChatPayAPI): - def create(self, trade_type, body, total_fee, notify_url, client_ip=None, - user_id=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', time_start=None, time_expire=None, goods_tag=None, - product_id=None, device_info=None, limit_pay=None, scene_info=None, sub_user_id=None): + def create( + self, + trade_type, + body, + total_fee, + notify_url, + client_ip=None, + user_id=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + time_start=None, + time_expire=None, + goods_tag=None, + product_id=None, + device_info=None, + limit_pay=None, + scene_info=None, + sub_user_id=None, + ): """ 统一下单接口 @@ -41,43 +58,41 @@ def create(self, trade_type, body, total_fee, notify_url, client_ip=None, :type scene_info: dict :return: 返回的结果数据 """ - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) hours_later = now + timedelta(hours=2) if time_start is None: time_start = now if time_expire is None: time_expire = hours_later if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) if scene_info is not None: scene_info = json.dumps(scene_info, ensure_ascii=False) data = { - 'appid': self.appid, - 'sub_appid': self.sub_appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'fee_type': fee_type, - 'total_fee': total_fee, - 'spbill_create_ip': client_ip or get_external_ip(), - 'time_start': time_start.strftime('%Y%m%d%H%M%S'), - 'time_expire': time_expire.strftime('%Y%m%d%H%M%S'), - 'goods_tag': goods_tag, - 'notify_url': notify_url, - 'trade_type': trade_type, - 'limit_pay': limit_pay, - 'product_id': product_id, - 'openid': user_id, - 'sub_openid': sub_user_id, - 'scene_info': scene_info, + "appid": self.appid, + "sub_appid": self.sub_appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "fee_type": fee_type, + "total_fee": total_fee, + "spbill_create_ip": client_ip or get_external_ip(), + "time_start": time_start.strftime("%Y%m%d%H%M%S"), + "time_expire": time_expire.strftime("%Y%m%d%H%M%S"), + "goods_tag": goods_tag, + "notify_url": notify_url, + "trade_type": trade_type, + "limit_pay": limit_pay, + "product_id": product_id, + "openid": user_id, + "sub_openid": sub_user_id, + "scene_info": scene_info, } - return self._post('pay/unifiedorder', data=data) + return self._post("pay/unifiedorder", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -88,11 +103,11 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) def close(self, out_trade_no): """ @@ -102,10 +117,10 @@ def close(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "out_trade_no": out_trade_no, } - return self._post('pay/closeorder', data=data) + return self._post("pay/closeorder", data=data) def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): """ @@ -117,15 +132,15 @@ def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appid': self.appid, - 'partnerid': self.mch_id, - 'prepayid': prepay_id, - 'package': 'Sign=WXPay', - 'timestamp': timestamp or to_text(int(time.time())), - 'noncestr': nonce_str or random_string(32) + "appid": self.appid, + "partnerid": self.mch_id, + "prepayid": prepay_id, + "package": "Sign=WXPay", + "timestamp": timestamp or to_text(int(time.time())), + "noncestr": nonce_str or random_string(32), } sign = calculate_signature(data, self._client.api_key) - data['sign'] = sign + data["sign"] = sign return data def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): @@ -138,14 +153,14 @@ def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'package': 'prepay_id='+prepay_id, - 'signType': 'MD5' + "appId": self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "package": "prepay_id=" + prepay_id, + "signType": "MD5", } sign = calculate_signature(data, self._client.api_key) - data['paySign'] = sign + data["paySign"] = sign return data def reverse(self, transaction_id=None, out_trade_no=None): @@ -159,8 +174,8 @@ def reverse(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('secapi/pay/reverse', data=data) + return self._post("secapi/pay/reverse", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/redpack.py b/chapter13/booking_system/exts/wechatpy/pay/api/redpack.py index c888b97..5a779f7 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/redpack.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/redpack.py @@ -9,9 +9,20 @@ class WeChatRedpack(BaseWeChatPayAPI): - def send(self, user_id, total_amount, send_name, act_name, - wishing, remark, total_num=1, client_ip=None, - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num=1, + client_ip=None, + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送现金红包 @@ -30,31 +41,41 @@ def send(self, user_id, total_amount, send_name, act_name, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'client_ip': client_ip or get_external_ip(), - 'total_num': total_num, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "client_ip": client_ip or get_external_ip(), + "total_num": total_num, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendredpack', data=data) + return self._post("mmpaymkttransfers/sendredpack", data=data) - def send_group(self, user_id, total_amount, send_name, act_name, wishing, - remark, total_num, client_ip=None, amt_type="ALL_RAND", - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send_group( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num, + client_ip=None, + amt_type="ALL_RAND", + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送裂变红包 @@ -75,30 +96,30 @@ def send_group(self, user_id, total_amount, send_name, act_name, wishing, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( + out_trade_no = "{0}{1}{2}".format( self._client.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now.strftime("%Y%m%d%H%M%S"), + random.randint(1000, 10000), ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'total_num': total_num, - 'client_ip': client_ip or get_external_ip(), - 'amt_type': amt_type, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "total_num": total_num, + "client_ip": client_ip or get_external_ip(), + "amt_type": amt_type, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendgroupredpack', data=data) + return self._post("mmpaymkttransfers/sendgroupredpack", data=data) - def query(self, out_trade_no, bill_type='MCHT'): + def query(self, out_trade_no, bill_type="MCHT"): """ 查询红包发放记录 @@ -107,8 +128,8 @@ def query(self, out_trade_no, bill_type='MCHT'): :return: 返回的红包发放记录信息 """ data = { - 'mch_billno': out_trade_no, - 'bill_type': bill_type, - 'appid': self.appid, + "mch_billno": out_trade_no, + "bill_type": bill_type, + "appid": self.appid, } - return self._post('mmpaymkttransfers/gethbinfo', data=data) + return self._post("mmpaymkttransfers/gethbinfo", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/refund.py b/chapter13/booking_system/exts/wechatpy/pay/api/refund.py index 8d9a5d1..9dec65b 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/refund.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/refund.py @@ -6,10 +6,19 @@ class WeChatRefund(BaseWeChatPayAPI): - def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, - out_trade_no=None, fee_type='CNY', op_user_id=None, - device_info=None, refund_account='REFUND_SOURCE_UNSETTLED_FUNDS', - notify_url=None): + def apply( + self, + total_fee, + refund_fee, + out_refund_no, + transaction_id=None, + out_trade_no=None, + fee_type="CNY", + op_user_id=None, + device_info=None, + refund_account="REFUND_SOURCE_UNSETTLED_FUNDS", + notify_url=None, + ): """ 申请退款 @@ -26,22 +35,28 @@ def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'total_fee': total_fee, - 'refund_fee': refund_fee, - 'refund_fee_type': fee_type, - 'op_user_id': op_user_id if op_user_id else self.mch_id, - 'refund_account': refund_account, - 'notify_url': notify_url, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "total_fee": total_fee, + "refund_fee": refund_fee, + "refund_fee_type": fee_type, + "op_user_id": op_user_id if op_user_id else self.mch_id, + "refund_account": refund_account, + "notify_url": notify_url, } - return self._post('secapi/pay/refund', data=data) + return self._post("secapi/pay/refund", data=data) - def query(self, refund_id=None, out_refund_no=None, transaction_id=None, - out_trade_no=None, device_info=None): + def query( + self, + refund_id=None, + out_refund_no=None, + transaction_id=None, + out_trade_no=None, + device_info=None, + ): """ 查询退款 @@ -53,11 +68,11 @@ def query(self, refund_id=None, out_refund_no=None, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'refund_id': refund_id, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "refund_id": refund_id, } - return self._post('pay/refundquery', data=data) + return self._post("pay/refundquery", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/tools.py b/chapter13/booking_system/exts/wechatpy/pay/api/tools.py index 75ffc33..1c76797 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/tools.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/tools.py @@ -15,12 +15,12 @@ def short_url(self, long_url): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'long_url': long_url, + "appid": self.appid, + "long_url": long_url, } - return self._post('tools/shorturl', data=data) + return self._post("tools/shorturl", data=data) - def download_bill(self, bill_date, bill_type='ALL', device_info=None): + def download_bill(self, bill_date, bill_type="ALL", device_info=None): """ 下载对账单 @@ -33,18 +33,17 @@ def download_bill(self, bill_date, bill_type='ALL', device_info=None): :return: 返回的结果数据 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'bill_type': bill_type, - 'device_info': device_info, + "appid": self.appid, + "bill_date": bill_date, + "bill_type": bill_type, + "device_info": device_info, } - return self._post('pay/downloadbill', data=data) + return self._post("pay/downloadbill", data=data) - def download_fundflow(self, bill_date, account_type='Basic', - tar_type=None): + def download_fundflow(self, bill_date, account_type="Basic", tar_type=None): """ 下载资金账单 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7 @@ -58,17 +57,17 @@ def download_fundflow(self, bill_date, account_type='Basic', 不传则默认为数据流形式。 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'account_type': account_type, - 'sign_type': 'HMAC-SHA256' + "appid": self.appid, + "bill_date": bill_date, + "account_type": account_type, + "sign_type": "HMAC-SHA256", } if tar_type is not None: - data['tar_type'] = tar_type - return self._post('pay/downloadfundflow', data=data) + data["tar_type"] = tar_type + return self._post("pay/downloadfundflow", data=data) def auto_code_to_openid(self, auth_code): """ @@ -78,7 +77,7 @@ def auto_code_to_openid(self, auth_code): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'auth_code': auth_code, + "appid": self.appid, + "auth_code": auth_code, } - return self._post('tools/authcodetoopenid', data=data) + return self._post("tools/authcodetoopenid", data=data) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/transfer.py b/chapter13/booking_system/exts/wechatpy/pay/api/transfer.py index 0b49951..13701fe 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/transfer.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/transfer.py @@ -9,9 +9,17 @@ class WeChatTransfer(BaseWeChatPayAPI): - def transfer(self, user_id, amount, desc, client_ip=None, - check_name='OPTION_CHECK', real_name=None, - out_trade_no=None, device_info=None): + def transfer( + self, + user_id, + amount, + desc, + client_ip=None, + check_name="OPTION_CHECK", + real_name=None, + out_trade_no=None, + device_info=None, + ): """ 企业付款接口 @@ -32,24 +40,22 @@ def transfer(self, user_id, amount, desc, client_ip=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_appid': self.appid, - 'mchid': self.mch_id, - 'device_info': device_info, - 'partner_trade_no': out_trade_no, - 'openid': user_id, - 'check_name': check_name, - 're_user_name': real_name, - 'amount': amount, - 'desc': desc, - 'spbill_create_ip': client_ip or get_external_ip(), + "mch_appid": self.appid, + "mchid": self.mch_id, + "device_info": device_info, + "partner_trade_no": out_trade_no, + "openid": user_id, + "check_name": check_name, + "re_user_name": real_name, + "amount": amount, + "desc": desc, + "spbill_create_ip": client_ip or get_external_ip(), } - return self._post('mmpaymkttransfers/promotion/transfers', data=data) + return self._post("mmpaymkttransfers/promotion/transfers", data=data) def query(self, out_trade_no): """ @@ -59,12 +65,14 @@ def query(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'partner_trade_no': out_trade_no, + "appid": self.appid, + "partner_trade_no": out_trade_no, } - return self._post('mmpaymkttransfers/gettransferinfo', data=data) + return self._post("mmpaymkttransfers/gettransferinfo", data=data) - def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None): + def transfer_bankcard( + self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None + ): """ 企业付款到银行卡接口 @@ -78,21 +86,19 @@ def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=Non """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, - 'amount': amount, - 'desc': desc, - 'enc_bank_no': self._rsa_encrypt(bank_card_no), - 'enc_true_name': self._rsa_encrypt(true_name), - 'bank_code': bank_code, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, + "amount": amount, + "desc": desc, + "enc_bank_no": self._rsa_encrypt(bank_card_no), + "enc_true_name": self._rsa_encrypt(true_name), + "bank_code": bank_code, } - return self._post('mmpaysptrans/pay_bank', data=data) + return self._post("mmpaysptrans/pay_bank", data=data) def query_bankcard(self, out_trade_no): """ @@ -102,19 +108,21 @@ def query_bankcard(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, } - return self._post('mmpaysptrans/query_bank', data=data) + return self._post("mmpaysptrans/query_bank", data=data) def get_rsa_public_key(self): data = { - 'mch_id': self.mch_id, - 'sign_type': 'MD5', + "mch_id": self.mch_id, + "sign_type": "MD5", } - return self._post('https://fraud.mch.weixin.qq.com/risk/getpublickey', data=data) + return self._post( + "https://fraud.mch.weixin.qq.com/risk/getpublickey", data=data + ) def _rsa_encrypt(self, data): - if not getattr(self, '_rsa_public_key', None): - self._rsa_public_key = self.get_rsa_public_key()['pub_key'] + if not getattr(self, "_rsa_public_key", None): + self._rsa_public_key = self.get_rsa_public_key()["pub_key"] return rsa_encrypt(data, self._rsa_public_key) diff --git a/chapter13/booking_system/exts/wechatpy/pay/api/withhold.py b/chapter13/booking_system/exts/wechatpy/pay/api/withhold.py index 3e9f2e7..e629d80 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/api/withhold.py +++ b/chapter13/booking_system/exts/wechatpy/pay/api/withhold.py @@ -13,9 +13,23 @@ class WeChatWithhold(BaseWeChatPayAPI): - def apply_signing(self, plan_id, contract_code, contract_display_account, notify_url, - version="1.0", clientip=None, deviceid=None, mobile=None, email=None, qq=None, - request_serial=None, openid=None, creid=None, outerid=None): + def apply_signing( + self, + plan_id, + contract_code, + contract_display_account, + notify_url, + version="1.0", + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + request_serial=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请签约 api @@ -65,10 +79,17 @@ def apply_signing(self, plan_id, contract_code, contract_display_account, notify data["sign"] = sign return { "base_url": "{}papay/entrustweb".format(self._client.API_BASE_URL), - "data": data + "data": data, } - def query_signing(self, contract_id=None, plan_id=None, contract_code=None, openid=None, version="1.0"): + def query_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + openid=None, + version="1.0", + ): """ 查询签约关系 api @@ -79,8 +100,14 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open :param version: 版本号 固定值1.0 :return: 返回的结果信息 """ - if not contract_id and not (plan_id and contract_code) and not (plan_id and openid): - raise ValueError("contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice.") + if ( + not contract_id + and not (plan_id and contract_code) + and not (plan_id and openid) + ): + raise ValueError( + "contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, @@ -91,11 +118,28 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open "version": version, "nonce_str": None, } - return self._post('papay/querycontract', data=data) - - def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=None, - detail=None, attach=None, fee_type='CNY', goods_tag=None, clientip=None, deviceid=None, - mobile=None, email=None, qq=None, openid=None, creid=None, outerid=None): + return self._post("papay/querycontract", data=data) + + def apply_deduct( + self, + body, + total_fee, + contract_id, + notify_url, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请扣款 api @@ -118,15 +162,13 @@ def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=No :param outerid: 可选 商户侧用户标识 用户在商户侧的标识 :return: 返回的结果信息 """ - trade_type = 'PAP' # 交易类型 交易类型PAP-微信委托代扣支付 + trade_type = "PAP" # 交易类型 交易类型PAP-微信委托代扣支付 timestamp = int(time.time()) # 10位时间戳 spbill_create_ip = get_external_ip() # 终端IP 调用微信支付API的机器IP if not out_trade_no: - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { @@ -173,8 +215,14 @@ def query_order(self, transaction_id=None, out_trade_no=None): } return self._post("pay/paporderquery", data=data) - def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=None, - contract_termination_remark=None, version="1.0"): + def apply_cancel_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + contract_termination_remark=None, + version="1.0", + ): """ 申请解约 @@ -188,7 +236,9 @@ def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=Non :return: """ if not (contract_id or (plan_id and contract_code)): - raise ValueError("contract_id and (plan_id, contract_code) must be a choice.") + raise ValueError( + "contract_id and (plan_id, contract_code) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, diff --git a/chapter13/booking_system/exts/wechatpy/pay/base.py b/chapter13/booking_system/exts/wechatpy/pay/base.py index 6184fa9..25c7830 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/base.py +++ b/chapter13/booking_system/exts/wechatpy/pay/base.py @@ -3,18 +3,19 @@ class BaseWeChatPayAPI(object): - """ WeChat Pay API base class """ + """WeChat Pay API base class""" + def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.post(url, **kwargs) @property diff --git a/chapter13/booking_system/exts/wechatpy/pay/utils.py b/chapter13/booking_system/exts/wechatpy/pay/utils.py index 4c1d05d..194be89 100644 --- a/chapter13/booking_system/exts/wechatpy/pay/utils.py +++ b/chapter13/booking_system/exts/wechatpy/pay/utils.py @@ -13,19 +13,22 @@ logger = logging.getLogger(__name__) + def format_url(params, api_key=None): # if '#text' in params: # print(params['#text']) # del params['#text'] # print( params['#text']) - data = [to_binary('{0}={1}'.format(k, params[k])) for k in sorted(params) if params[k]] + data = [ + to_binary("{0}={1}".format(k, params[k])) for k in sorted(params) if params[k] + ] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # del data[0] if api_key: - data.append(to_binary('key={0}'.format(api_key))) + data.append(to_binary("key={0}".format(api_key))) return b"&".join(data) @@ -37,42 +40,45 @@ def calculate_signature(params, api_key): def calculate_signature_hmac(params, api_key): url = format_url(params, api_key) - sign = to_text(hmac.new(api_key.encode(), msg=url, - digestmod=hashlib.sha256).hexdigest().upper()) + sign = to_text( + hmac.new(api_key.encode(), msg=url, digestmod=hashlib.sha256) + .hexdigest() + .upper() + ) return sign def _check_signature(params, api_key): _params = copy.deepcopy(params) - sign = _params.pop('sign', '') + sign = _params.pop("sign", "") return sign == calculate_signature(_params, api_key) def dict_to_xml(d, sign): - xml = ['\n'] + xml = ["\n"] for k in sorted(d): # use sorted to avoid test error on Py3k v = d[k] - if isinstance(v, six.integer_types) or (isinstance(v, six.string_types) and v.isdigit()): - xml.append('<{0}>{1}\n'.format(to_text(k), to_text(v))) + if isinstance(v, six.integer_types) or ( + isinstance(v, six.string_types) and v.isdigit() + ): + xml.append("<{0}>{1}\n".format(to_text(k), to_text(v))) else: - xml.append( - '<{0}>\n'.format(to_text(k), to_text(v)) - ) - xml.append('\n'.format(to_text(sign))) - return ''.join(xml) + xml.append("<{0}>\n".format(to_text(k), to_text(v))) + xml.append("\n".format(to_text(sign))) + return "".join(xml) def get_external_ip(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: - wechat_ip = socket.gethostbyname('api.mch.weixin.qq.com') + wechat_ip = socket.gethostbyname("api.mch.weixin.qq.com") sock.connect((wechat_ip, 80)) addr, port = sock.getsockname() sock.close() return addr except socket.error: - return '127.0.0.1' + return "127.0.0.1" def rsa_encrypt(data, pem, b64_encode=True): @@ -87,6 +93,7 @@ def rsa_encrypt(data, pem, b64_encode=True): from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding + encoded_data = to_binary(data) pem = to_binary(pem) public_key = serialization.load_pem_public_key(pem, backend=default_backend()) @@ -96,10 +103,10 @@ def rsa_encrypt(data, pem, b64_encode=True): mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) if b64_encode: - encrypted_data = base64.b64encode(encrypted_data).decode('utf-8') + encrypted_data = base64.b64encode(encrypted_data).decode("utf-8") return encrypted_data @@ -118,13 +125,15 @@ def rsa_decrypt(encrypted_data, pem, password=None): encrypted_data = to_binary(encrypted_data) pem = to_binary(pem) - private_key = serialization.load_pem_private_key(pem, password, backend=default_backend()) + private_key = serialization.load_pem_private_key( + pem, password, backend=default_backend() + ) data = private_key.decrypt( encrypted_data, padding=padding.OAEP( mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) return data diff --git a/chapter13/booking_system/exts/wechatpy/replies.py b/chapter13/booking_system/exts/wechatpy/replies.py index 9a48d71..3365edc 100644 --- a/chapter13/booking_system/exts/wechatpy/replies.py +++ b/chapter13/booking_system/exts/wechatpy/replies.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.replies - ~~~~~~~~~~~~~~~~~~ - This module defines all kinds of replies you can send to WeChat +wechatpy.replies +~~~~~~~~~~~~~~~~~~ +This module defines all kinds of replies you can send to WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -34,28 +34,30 @@ def register_reply(reply_type): def register(cls): REPLY_TYPES[reply_type] = cls return cls + return register class BaseReply(six.with_metaclass(MessageMetaClass)): """Base class for all replies""" - source = StringField('FromUserName') - target = StringField('ToUserName') - time = IntegerField('CreateTime', time.time()) - type = 'unknown' + + source = StringField("FromUserName") + target = StringField("ToUserName") + time = IntegerField("CreateTime", time.time()) + type = "unknown" def __init__(self, **kwargs): self._data = {} - message = kwargs.pop('message', None) + message = kwargs.pop("message", None) if message and isinstance(message, BaseMessage): - if 'source' not in kwargs: - kwargs['source'] = message.target - if 'target' not in kwargs: - kwargs['target'] = message.source - if hasattr(message, 'agent') and 'agent' not in kwargs: - kwargs['agent'] = message.agent - if 'time' not in kwargs: - kwargs['time'] = time.time() + if "source" not in kwargs: + kwargs["source"] = message.target + if "target" not in kwargs: + kwargs["target"] = message.source + if hasattr(message, "agent") and "agent" not in kwargs: + kwargs["agent"] = message.agent + if "time" not in kwargs: + kwargs["time"] = time.time() for name, value in kwargs.items(): field = self._fields.get(name) if field: @@ -65,9 +67,9 @@ def __init__(self, **kwargs): def render(self): """Render reply from Python object to XML string""" - tpl = '\n{data}\n' + tpl = "\n{data}\n" nodes = [] - msg_type = ''.format( + msg_type = "".format( msg_type=self.type ) nodes.append(msg_type) @@ -75,7 +77,7 @@ def render(self): value = getattr(self, name, field.default) node_xml = field.to_xml(value) nodes.append(node_xml) - data = '\n'.join(nodes) + data = "\n".join(nodes) return tpl.format(data=data) def __str__(self): @@ -85,39 +87,42 @@ def __str__(self): return to_text(self.render()) -@register_reply('empty') +@register_reply("empty") class EmptyReply(BaseReply): """ 回复空串 微信服务器不会对此作任何处理,并且不会发起重试 """ + def __init__(self): pass def render(self): - return '' + return "" -@register_reply('text') +@register_reply("text") class TextReply(BaseReply): """ 文本回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_reply('image') + +@register_reply("image") class ImageReply(BaseReply): """ 图片回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'image' - image = ImageField('Image') + + type = "image" + image = ImageField("Image") @property def media_id(self): @@ -128,15 +133,16 @@ def media_id(self, value): self.image = value -@register_reply('voice') +@register_reply("voice") class VoiceReply(BaseReply): """ 语音回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'voice' - voice = VoiceField('Voice') + + type = "voice" + voice = VoiceField("Voice") @property def media_id(self): @@ -147,169 +153,174 @@ def media_id(self, value): self.voice = value -@register_reply('video') +@register_reply("video") class VideoReply(BaseReply): """ 视频回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'video' - video = VideoField('Video', {}) + + type = "video" + video = VideoField("Video", {}) @property def media_id(self): - return self.video.get('media_id') + return self.video.get("media_id") @media_id.setter def media_id(self, value): video = self.video - video['media_id'] = value + video["media_id"] = value self.video = video @property def title(self): - return self.video.get('title') + return self.video.get("title") @title.setter def title(self, value): video = self.video - video['title'] = value + video["title"] = value self.video = video @property def description(self): - return self.video.get('description') + return self.video.get("description") @description.setter def description(self, value): video = self.video - video['description'] = value + video["description"] = value self.video = video -@register_reply('music') +@register_reply("music") class MusicReply(BaseReply): """ 音乐回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'music' - music = MusicField('Music', {}) + + type = "music" + music = MusicField("Music", {}) @property def thumb_media_id(self): - return self.music.get('thumb_media_id') + return self.music.get("thumb_media_id") @thumb_media_id.setter def thumb_media_id(self, value): music = self.music - music['thumb_media_id'] = value + music["thumb_media_id"] = value self.music = music @property def title(self): - return self.music.get('title') + return self.music.get("title") @title.setter def title(self, value): music = self.music - music['title'] = value + music["title"] = value self.music = music @property def description(self): - return self.music.get('description') + return self.music.get("description") @description.setter def description(self, value): music = self.music - music['description'] = value + music["description"] = value self.music = music @property def music_url(self): - return self.music.get('music_url') + return self.music.get("music_url") @music_url.setter def music_url(self, value): music = self.music - music['music_url'] = value + music["music_url"] = value self.music = music @property def hq_music_url(self): - return self.music.get('hq_music_url') + return self.music.get("hq_music_url") @hq_music_url.setter def hq_music_url(self, value): music = self.music - music['hq_music_url'] = value + music["hq_music_url"] = value self.music = music -@register_reply('news') +@register_reply("news") class ArticlesReply(BaseReply): """ 图文回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'news' - articles = ArticlesField('Articles', []) + + type = "news" + articles = ArticlesField("Articles", []) def add_article(self, article): if len(self.articles) == 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) articles = self.articles articles.append(article) self.articles = articles -@register_reply('transfer_customer_service') +@register_reply("transfer_customer_service") class TransferCustomerServiceReply(BaseReply): """ 将消息转发到多客服 详情请参阅 http://mp.weixin.qq.com/wiki/5/ae230189c9bd07a6b221f48619aeef35.html """ - type = 'transfer_customer_service' + type = "transfer_customer_service" -@register_reply('device_text') + +@register_reply("device_text") class DeviceTextReply(BaseReply): - type = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_event') +@register_reply("device_event") class DeviceEventReply(BaseReply): - type = 'device_event' - event = StringField('Event') - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_event" + event = StringField("Event") + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_status') +@register_reply("device_status") class DeviceStatusReply(BaseReply): - type = 'device_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - status = IntegerField('DeviceStatus') + type = "device_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + status = IntegerField("DeviceStatus") -@register_reply('hardware') +@register_reply("hardware") class HardwareReply(BaseReply): - type = 'hardware' - func_flag = IntegerField('FuncFlag', 0) - hardware = HardwareField('HardWare') + type = "hardware" + func_flag = IntegerField("FuncFlag", 0) + hardware = HardwareField("HardWare") def create_reply(reply, message=None, render=False): @@ -325,18 +336,13 @@ def create_reply(reply, message=None, render=False): r.source = message.target r.target = message.source elif isinstance(reply, six.string_types): - r = TextReply( - message=message, - content=reply - ) + r = TextReply(message=message, content=reply) elif isinstance(reply, (tuple, list)): if len(reply) > 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") - r = ArticlesReply( - message=message, - articles=reply - ) + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) + r = ArticlesReply(message=message, articles=reply) if r and render: return r.render() return r diff --git a/chapter13/booking_system/exts/wechatpy/session/memcachedstorage.py b/chapter13/booking_system/exts/wechatpy/session/memcachedstorage.py index e9d7b33..15bd06d 100644 --- a/chapter13/booking_system/exts/wechatpy/session/memcachedstorage.py +++ b/chapter13/booking_system/exts/wechatpy/session/memcachedstorage.py @@ -8,14 +8,14 @@ class MemcachedStorage(SessionStorage): - def __init__(self, mc, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, mc, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(mc, method_name) self.mc = mc self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter13/booking_system/exts/wechatpy/session/redisstorage.py b/chapter13/booking_system/exts/wechatpy/session/redisstorage.py index 7412929..c931e64 100644 --- a/chapter13/booking_system/exts/wechatpy/session/redisstorage.py +++ b/chapter13/booking_system/exts/wechatpy/session/redisstorage.py @@ -7,14 +7,14 @@ class RedisStorage(SessionStorage): - def __init__(self, redis, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, redis, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(redis, method_name) self.redis = redis self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter13/booking_system/exts/wechatpy/session/shovestorage.py b/chapter13/booking_system/exts/wechatpy/session/shovestorage.py index 2e0ffbf..1efda82 100644 --- a/chapter13/booking_system/exts/wechatpy/session/shovestorage.py +++ b/chapter13/booking_system/exts/wechatpy/session/shovestorage.py @@ -5,12 +5,12 @@ class ShoveStorage(SessionStorage): - def __init__(self, shove, prefix='wechatpy'): + def __init__(self, shove, prefix="wechatpy"): self.shove = shove self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter13/booking_system/exts/wechatpy/utils.py b/chapter13/booking_system/exts/wechatpy/utils.py index 74480ed..ee02ada 100644 --- a/chapter13/booking_system/exts/wechatpy/utils.py +++ b/chapter13/booking_system/exts/wechatpy/utils.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.utils - ~~~~~~~~~~~~~~~ +wechatpy.utils +~~~~~~~~~~~~~~~ - This module provides some useful utilities. +This module provides some useful utilities. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import string @@ -14,7 +14,7 @@ import hashlib try: - '''Use simplejson if we can, fallback to json otherwise.''' + """Use simplejson if we can, fallback to json otherwise.""" import simplejson as json except ImportError: import json # NOQA @@ -24,8 +24,7 @@ class ObjectDict(dict): - """Makes a dictionary behave like an object, with attribute-style access. - """ + """Makes a dictionary behave like an object, with attribute-style access.""" def __getattr__(self, key): if key in self: @@ -39,7 +38,7 @@ def __setattr__(self, key, value): class WeChatSigner(object): """WeChat data signer""" - def __init__(self, delimiter=b''): + def __init__(self, delimiter=b""): self._data = [] self._delimiter = to_binary(delimiter) @@ -73,14 +72,14 @@ def check_signature(token, signature, timestamp, nonce): raise InvalidSignatureException() -def to_text(value, encoding='utf-8'): +def to_text(value, encoding="utf-8"): """Convert value to unicode, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return '' + return "" if isinstance(value, six.text_type): return value if isinstance(value, six.binary_type): @@ -88,14 +87,14 @@ def to_text(value, encoding='utf-8'): return six.text_type(value) -def to_binary(value, encoding='utf-8'): +def to_binary(value, encoding="utf-8"): """Convert value to binary string, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return b'' + return b"" if isinstance(value, six.binary_type): return value if isinstance(value, six.text_type): @@ -111,11 +110,13 @@ def timezone(zone): """ try: import pytz + return pytz.timezone(zone) except ImportError: pass try: from dateutil.tz import gettz + return gettz(zone) except ImportError: return None @@ -124,7 +125,7 @@ def timezone(zone): def random_string(length=16): rule = string.ascii_letters + string.digits rand_list = random.sample(rule, length) - return ''.join(rand_list) + return "".join(rand_list) def get_querystring(uri): diff --git a/chapter13/booking_system/main.py b/chapter13/booking_system/main.py index ec3f1e1..b0c5d55 100644 --- a/chapter13/booking_system/main.py +++ b/chapter13/booking_system/main.py @@ -1,12 +1,14 @@ from app import creat_app -app =creat_app() + +app = creat_app() if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) # tree -I "node_modules|cache|test_*" -# tree -I "__pycache__" \ No newline at end of file +# tree -I "__pycache__" diff --git a/chapter13/booking_system/middlewares/loger/middleware.py b/chapter13/booking_system/middlewares/loger/middleware.py index dca0ac5..e74aaef 100644 --- a/chapter13/booking_system/middlewares/loger/middleware.py +++ b/chapter13/booking_system/middlewares/loger/middleware.py @@ -15,87 +15,107 @@ request: Request = bind_contextvar(request_var) - - def setup_ext_loguru(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(log_file_path, format=format2, rotation='00:00', encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file - + logger.add( + log_file_path, + format=format2, + rotation="00:00", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, - + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str(getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) class LogerMiddleware: def __init__( - self, - *, - app: ASGIApp, - log_pro_path: str, - is_record_useragent=False, - is_record_headers=False, - nesss_access_heads_keys=[], - ignore_url: typing.List = ['/favicon.ico', 'websocket'], + self, + *, + app: ASGIApp, + log_pro_path: str, + is_record_useragent=False, + is_record_headers=False, + nesss_access_heads_keys=[], + ignore_url: typing.List = ["/favicon.ico", "websocket"], ) -> None: self.app = app self.is_record_useragent = is_record_useragent @@ -105,11 +125,11 @@ def __init__( setup_ext_loguru(log_pro_path) def make_traceid(self, request) -> None: - ''' + """ 生成追踪链路ID :param request: :return: - ''' + """ request.state.traceid = shortuuid.uuid() # 追踪索引序号 request.state.trace_links_index = 0 @@ -119,36 +139,35 @@ def make_traceid(self, request) -> None: request.state.start_time = perf_counter() def make_token_request(self, request): - ''' + """ 生成当前请求上下文对象request :param request: :return: - ''' + """ return request_var.set(request) def reset_token_request(self, token_request): - ''' + """ 重置当前请求上下文对象request :param request: :return: - ''' + """ request_var.reset(token_request) - async def get_request_body(self, request) -> typing.AnyStr: body = None try: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass request.state.body = body @@ -189,77 +208,102 @@ async def make_request_log_msg(self, request) -> typing.Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") except: log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, - 'url': url, - 'method': method, - 'ip': ip, - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), + "url": url, + "method": method, + "ip": ip, + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - print('log_msg', log_msg) + print("log_msg", log_msg) # 对于没有的数据清除 - if 'headers' in log_msg and not log_msg['headers']: - log_msg.pop('headers') - if log_msg['params']: - if 'query_params' in log_msg['params'] and not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - print(log_msg['params']) - if 'from' in log_msg['params'] and not log_msg['params']['from']: - log_msg['params'].pop('from') - if 'body' in log_msg['params'] and not log_msg['params']['body']: - log_msg['params'].pop('body') + if "headers" in log_msg and not log_msg["headers"]: + log_msg.pop("headers") + if log_msg["params"]: + if ( + "query_params" in log_msg["params"] + and not log_msg["params"]["query_params"] + ): + log_msg["params"].pop("query_params") + print(log_msg["params"]) + if "from" in log_msg["params"] and not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if "body" in log_msg["params"] and not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] != "http": # pragma: no cover await self.app(scope, receive, send) @@ -284,9 +328,9 @@ async def receive(): # 生成日志记录 log_msg = await self.make_request_log_msg(request) # 开始写日志信息到文件中 - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) try: response = await self.app(scope, receive, send) return response finally: - self.reset_token_request(token_request) + self.reset_token_request(token_request) diff --git a/chapter13/booking_system/order_consumer.py b/chapter13/booking_system/order_consumer.py index d417a2f..88d332f 100644 --- a/chapter13/booking_system/order_consumer.py +++ b/chapter13/booking_system/order_consumer.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/10/19 ------------------------------------------------- - 修改描述-2021/10/19: + 修改描述-2021/10/19: ------------------------------------------------- """ import pika @@ -21,24 +21,33 @@ credentials = pika.PlainCredentials("guest", "guest") # 创建连接http://47.99.189.42:30100/ connection = pika.BlockingConnection( - pika.ConnectionParameters(host='localhost', port=5672, virtual_host='yuyueguahao', credentials=credentials)) + pika.ConnectionParameters( + host="localhost", port=5672, virtual_host="yuyueguahao", credentials=credentials + ) +) # 通过连接创建信道 channel = connection.channel() # 通过信道创建我们的队列 其中名称是task_queue,并且这个队列的消息是需要持久化的!PS:持久化存储存到磁盘会占空间, # 队列不能由持久化变为普通队列,反过来也是!否则会报错!所以队列类型创建的开始必须确定的! -order_dead_letter_exchange_name = 'xz-dead-letter-exchange' -order_dead_letter_exchange_type = 'fanout' -order_dead_letter_queue_name = 'xz-dead-letter-queue' -order_dead_letter_routing_key = 'xz-dead-letter-queue' +order_dead_letter_exchange_name = "xz-dead-letter-exchange" +order_dead_letter_exchange_type = "fanout" +order_dead_letter_queue_name = "xz-dead-letter-queue" +order_dead_letter_routing_key = "xz-dead-letter-queue" # 相对比只要交换机名称即可接收到消息的广播模式(fanout),direct模式在其基础上,多加了一层密码限制(routingKey) -channel.exchange_declare(exchange=order_dead_letter_exchange_name, durable=True, - exchange_type=order_dead_letter_exchange_type) +channel.exchange_declare( + exchange=order_dead_letter_exchange_name, + durable=True, + exchange_type=order_dead_letter_exchange_type, +) channel.queue_declare(queue=order_dead_letter_queue_name, durable=True) -channel.queue_bind(exchange=order_dead_letter_exchange_name, queue=order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) +channel.queue_bind( + exchange=order_dead_letter_exchange_name, + queue=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, +) -print(' [*] 死信队列里面的死信消息的消费. To exit press CTRL+C') +print(" [*] 死信队列里面的死信消息的消费. To exit press CTRL+C") # 初始化数据库的链接处理 @@ -50,11 +59,17 @@ def callback(ch, method, properties, body): # 获取当前的订单支付状态信息,如果当前处于没支付的状态的话,则需要回滚我们的库存 with sync_context_get_db() as session: - _result = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'), - DoctorSubscribeinfo.visit_uopenid == mesgg.get( - 'visit_uopenid'), - DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).one_or_none() + _result = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.visit_uopenid == mesgg.get("visit_uopenid"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ) + .one_or_none() + ) if _result: @@ -65,9 +80,12 @@ def callback(ch, method, properties, body): pass # 更新订单状态 print("更新状态!!!!!!!!!!!!!") - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'),DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).update({DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) elif _result.statue == 3: pass elif _result.statue == 5: @@ -84,7 +102,7 @@ def callback(ch, method, properties, body): channel.basic_qos(prefetch_count=1) # await channel.set_qos(prefetch_count=1) # 开始进行订阅消费 -ack = channel.basic_consume(queue='xz-dead-letter-queue', on_message_callback=callback) -print('s', ack) +ack = channel.basic_consume(queue="xz-dead-letter-queue", on_message_callback=callback) +print("s", ack) # 消费者会阻塞在这里,一直等待消息,队列中有消息了,就会执行消息的回调函数 channel.start_consuming() diff --git a/chapter13/booking_system/plugins/base.py b/chapter13/booking_system/plugins/base.py index 847db87..72827ca 100644 --- a/chapter13/booking_system/plugins/base.py +++ b/chapter13/booking_system/plugins/base.py @@ -3,12 +3,21 @@ import typing import abc + class PluginBase(abc.ABC): - def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): + def __init__( + self, app: fastapi.FastAPI = None, config: pydantic.BaseSettings = None + ): if app is not None: self.init_app(app) @abc.abstractmethod - def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: - raise NotImplementedError('需要实现初始化') + def init_app( + self, + app: fastapi.FastAPI, + config: pydantic.BaseSettings = None, + *args, + **kwargs + ) -> None: + raise NotImplementedError("需要实现初始化") diff --git a/chapter13/booking_system/plugins/request_hook.py b/chapter13/booking_system/plugins/request_hook.py index 5cc23e7..c43f5ee 100644 --- a/chapter13/booking_system/plugins/request_hook.py +++ b/chapter13/booking_system/plugins/request_hook.py @@ -1,4 +1,3 @@ - from plugins.base import PluginBase from fastapi import FastAPI from pydantic import BaseSettings @@ -10,15 +9,24 @@ class HookPluginClient(PluginBase): # 设置插件默认的参数信息 - def __init__(self, - on_before_request: typing.Sequence[typing.Callable] = None, - on_after_request: typing.Sequence[typing.Callable] = None, - on_teardown_appcontext: typing.Sequence[typing.Callable] = None, - *args, **kwargs): + def __init__( + self, + on_before_request: typing.Sequence[typing.Callable] = None, + on_after_request: typing.Sequence[typing.Callable] = None, + on_teardown_appcontext: typing.Sequence[typing.Callable] = None, + *args, + **kwargs + ): super().__init__(*args, **kwargs) - self.on_before_request = [] if on_before_request is None else list(on_before_request) - self.on_after_request = [] if on_after_request is None else list(on_after_request) - self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + self.on_before_request = ( + [] if on_before_request is None else list(on_before_request) + ) + self.on_after_request = ( + [] if on_after_request is None else list(on_after_request) + ) + self.on_teardown_appcontext = ( + [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + ) def init_app(self, app: FastAPI, *args, **kwargs): pass @@ -50,6 +58,7 @@ def on_event(self, event_type: str) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_event_handler(event_type, func) return func + return decorator async def before_request(self, request) -> None: @@ -72,4 +81,4 @@ async def teardown_appcontext(self, request, response) -> None: if asyncio.iscoroutinefunction(handler): await handler(request, response) else: - handler(request, response) \ No newline at end of file + handler(request, response) diff --git a/chapter13/booking_system/testcase/conftest.py b/chapter13/booking_system/testcase/conftest.py index 4dbe611..e18c976 100644 --- a/chapter13/booking_system/testcase/conftest.py +++ b/chapter13/booking_system/testcase/conftest.py @@ -4,9 +4,10 @@ import asyncio import sys from db.async_database import async_engine + # 需要加载当前项目目录。sys.path.append('E://yuanxiao//code//booking_system//booking_system'), # 不然在项目根目录执行pytest会出现ModuleNotFoundError: No module named 'app' -sys.path.append('E://yuanxiao//code//booking_system//booking_system') +sys.path.append("E://yuanxiao//code//booking_system//booking_system") from app import app # ===========================================同步使用 @@ -14,6 +15,8 @@ from typing import Dict, Generator import pytest from fastapi.testclient import TestClient + + @pytest.fixture(scope="module") def client() -> Generator: with TestClient(app) as c: @@ -25,6 +28,7 @@ def client() -> Generator: # 修改设置优先循环事件 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + # 配置使用哪一种模式的异步 @pytest.fixture( params=[ @@ -34,15 +38,21 @@ def client() -> Generator: def anyio_backend(request): return request.param + # 解决当接口中涉及到依赖注入的数据库使用 async def start_db(): async with async_engine.begin() as conn: pass await async_engine.dispose() + @pytest_asyncio.fixture async def async_client() -> AsyncClient: - async with AsyncClient(app=app,base_url="http://test", headers={"Content-Type": "application/json"},) as async_client: + async with AsyncClient( + app=app, + base_url="http://test", + headers={"Content-Type": "application/json"}, + ) as async_client: await start_db() yield async_client - await async_engine.dispose() \ No newline at end of file + await async_engine.dispose() diff --git a/chapter13/booking_system/testcase/test_async_api_v1.py b/chapter13/booking_system/testcase/test_async_api_v1.py index 0464845..83a728f 100644 --- a/chapter13/booking_system/testcase/test_async_api_v1.py +++ b/chapter13/booking_system/testcase/test_async_api_v1.py @@ -16,8 +16,9 @@ import pytest + @pytest.mark.anyio -@pytest.mark.parametrize('anyio_backend', ['asyncio']) +@pytest.mark.parametrize("anyio_backend", ["asyncio"]) async def test_doctor_list(async_client): res = await async_client.get("/api/v1/doctor_list") assert res.status_code == 200 @@ -25,7 +26,7 @@ async def test_doctor_list(async_client): @pytest.mark.anyio -@pytest.mark.parametrize('anyio_backend', ['asyncio']) +@pytest.mark.parametrize("anyio_backend", ["asyncio"]) async def test_hospital_info(async_client): res = await async_client.get("/api/v1/hospital_info") assert res.status_code == 200 diff --git a/chapter13/booking_system/testcase/test_async_api_v2.py b/chapter13/booking_system/testcase/test_async_api_v2.py index 2c9c53a..a65f873 100644 --- a/chapter13/booking_system/testcase/test_async_api_v2.py +++ b/chapter13/booking_system/testcase/test_async_api_v2.py @@ -2,15 +2,17 @@ # import pytest from httpx import AsyncClient + pytestmark = pytest.mark.anyio + async def test_hospital_info(async_client: AsyncClient): response = await async_client.get("/api/v1/hospital_info") - print('response', response.text) + print("response", response.text) assert response.status_code == 200 async def test_doctor_list(async_client: AsyncClient): response = await async_client.get("/api/v1/doctor_list") - print('response', response.text) - assert response.status_code == 200 \ No newline at end of file + print("response", response.text) + assert response.status_code == 200 diff --git a/chapter13/booking_system/testcase/test_sync_api.py b/chapter13/booking_system/testcase/test_sync_api.py index e6ec0fd..dc18420 100644 --- a/chapter13/booking_system/testcase/test_sync_api.py +++ b/chapter13/booking_system/testcase/test_sync_api.py @@ -34,15 +34,15 @@ from fastapi.testclient import TestClient - -def test_hospitalinfo(client:TestClient): - res = client.get('/api/v1/hospital_info') - print('sdsd',res.text) +def test_hospitalinfo(client: TestClient): + res = client.get("/api/v1/hospital_info") + print("sdsd", res.text) assert res.status_code == 200 assert type(res.status_code) == int -def test_doctorlist(client:TestClient): - res = client.get('/api/v1/doctor_list') - print('dsasd',res.text) + +def test_doctorlist(client: TestClient): + res = client.get("/api/v1/doctor_list") + print("dsasd", res.text) assert res.status_code == 200 - assert type(res.status_code) == int \ No newline at end of file + assert type(res.status_code) == int diff --git a/chapter13/booking_system/utils/cast_helper.py b/chapter13/booking_system/utils/cast_helper.py index c0803c1..4693ad3 100644 --- a/chapter13/booking_system/utils/cast_helper.py +++ b/chapter13/booking_system/utils/cast_helper.py @@ -1,2 +1,2 @@ -def add(a,b): - return a+b; \ No newline at end of file +def add(a, b): + return a + b diff --git a/chapter13/booking_system/utils/datatime_helper.py b/chapter13/booking_system/utils/datatime_helper.py index ab77882..c6e1e6c 100644 --- a/chapter13/booking_system/utils/datatime_helper.py +++ b/chapter13/booking_system/utils/datatime_helper.py @@ -5,48 +5,58 @@ def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False return True - def get_timestamp10(): """获取当前时间长度为10位长度的时间戳""" return int(time.time()) def str_to_datatime(srr_time, strftime="%Y-%m-%d"): - print('strftimestrftimestrftime',strftime) + print("strftimestrftimestrftime", strftime) return datetime.datetime.strptime(srr_time, strftime) -str_to_datatime('2021-12-27 10:00:00',strftime='%Y-%m-%d %H:%M:%S') + +str_to_datatime("2021-12-27 10:00:00", strftime="%Y-%m-%d %H:%M:%S") + def datatime_to_str(data_time: datetime.datetime, strftime="%Y-%m-%d"): return data_time.strftime(strftime) def diff_days_for_now_time(srr_time): - ''' + """ 对比当前的传入日期和当前系统时间的相差的天数 :param srr_time: :return: - ''' - return (datetime.datetime.strptime(srr_time, "%Y-%m-%d") - datetime.datetime.combine(datetime.datetime.now().date(), - datetime.time())).days + """ + return ( + datetime.datetime.strptime(srr_time, "%Y-%m-%d") + - datetime.datetime.combine(datetime.datetime.now().date(), datetime.time()) + ).days # 获取当前日期 # today=time.strftime('%Y-%m-%d',time.localtime(time.time())) + def currday_time_info(): - return time.strftime('%Y-%m-%d', time.localtime(time.time())) + return time.strftime("%Y-%m-%d", time.localtime(time.time())) def currday_time_info_tochane_datetime(today): @@ -55,11 +65,17 @@ def currday_time_info_tochane_datetime(today): def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False @@ -68,9 +84,9 @@ def effectiveness_tiempm(tiempm): # 根据给定的日期,获取前n天或后n天的日期,n为正数则是以后的n天,n为负数则是以前的n天,不包括当天 def get_day_of_day(str2date, n=0): - if (n < 0): + if n < 0: n = abs(n) - return (str2date - timedelta(days=n)) + return str2date - timedelta(days=n) else: return str2date + timedelta(days=n) @@ -83,7 +99,7 @@ def num_to_string(num): 3: "周三", 4: "周四", 5: "周五", - 6: "周六" + 6: "周六", } return numbers.get(num, None) @@ -93,9 +109,9 @@ def get_7day_info_list(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = { - 'weekday': num_to_string(datatime.isoweekday()), - 'datetimeday': datatime.strftime('%Y-%m-%d') + ditcs[datatime.strftime("%Y-%m-%d")] = { + "weekday": num_to_string(datatime.isoweekday()), + "datetimeday": datatime.strftime("%Y-%m-%d"), } return ditcs @@ -105,6 +121,5 @@ def get_7day_info_list_only_data(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = {} + ditcs[datatime.strftime("%Y-%m-%d")] = {} return ditcs - diff --git a/chapter13/booking_system/utils/json_helper.py b/chapter13/booking_system/utils/json_helper.py index f8a3fd2..6a1de21 100644 --- a/chapter13/booking_system/utils/json_helper.py +++ b/chapter13/booking_system/utils/json_helper.py @@ -8,16 +8,16 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) if isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") if isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") if isinstance(obj, decimal.Decimal): return float(obj) if isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") return json.JSONEncoder.default(self, obj) @@ -61,7 +61,7 @@ def class_to_dict(obj): else: dict = {} dict.update(obj.__dict__) - return dict.get('__data__') + return dict.get("__data__") import base64 @@ -125,4 +125,4 @@ def dumps( default=default, sort_keys=sort_keys, **kw - ) \ No newline at end of file + ) diff --git a/chapter13/booking_system/utils/ordernum_helper.py b/chapter13/booking_system/utils/ordernum_helper.py index 6723543..80ec95c 100644 --- a/chapter13/booking_system/utils/ordernum_helper.py +++ b/chapter13/booking_system/utils/ordernum_helper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -37,27 +37,42 @@ def order_num_1(package_id=12345, user_num=56789): # 商品id后1位+下单时间的年月日12+用户2后四位+随机数3位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(100, 999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(100, 999)) + ) return result def order_num_2(package_id=12345, user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(1000, 9999)) + ) return result def order_num_3(user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =f'{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}' + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = f"{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}" return result -def order_num_srt(user_num='56789'): +def order_num_srt(user_num="56789"): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =str(user_num)[-2:] + str(random.randint(100, 999)) + local_time + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(user_num)[-2:] + + str(random.randint(100, 999)) + + local_time + + str(random.randint(1000, 9999)) + ) return result diff --git a/chapter13/booking_system/utils/run_with_asyncio.py b/chapter13/booking_system/utils/run_with_asyncio.py index 0d845ba..edf6416 100644 --- a/chapter13/booking_system/utils/run_with_asyncio.py +++ b/chapter13/booking_system/utils/run_with_asyncio.py @@ -2,11 +2,15 @@ import asyncio from functools import wraps from typing import Any, Awaitable, Callable, TypeVar + T = TypeVar("T") __all__ = ["run_with_asyncio"] + + def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> T: print("pajinlail") return asyncio.run(f(*args, **kwargs)) - return wrapper \ No newline at end of file + + return wrapper diff --git a/chapter13/booking_system/utils/xmlhelper.py b/chapter13/booking_system/utils/xmlhelper.py index a831fd9..883bb15 100644 --- a/chapter13/booking_system/utils/xmlhelper.py +++ b/chapter13/booking_system/utils/xmlhelper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -43,10 +43,16 @@ def parse_xml_data(xml): except (xmltodict.ParsingInterrupted, ExpatError): raise Exception() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise Exception() - data = data['xml'] - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + data = data["xml"] + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) return data diff --git a/chapter13/pytest_demo/cast_helper.py b/chapter13/pytest_demo/cast_helper.py index c0803c1..4693ad3 100644 --- a/chapter13/pytest_demo/cast_helper.py +++ b/chapter13/pytest_demo/cast_helper.py @@ -1,2 +1,2 @@ -def add(a,b): - return a+b; \ No newline at end of file +def add(a, b): + return a + b diff --git a/chapter13/pytest_demo/test_add.py b/chapter13/pytest_demo/test_add.py index a6d9c05..cf9d110 100644 --- a/chapter13/pytest_demo/test_add.py +++ b/chapter13/pytest_demo/test_add.py @@ -4,7 +4,6 @@ class TestMyAddClass: - def setup(self): print("setup前置条件") @@ -23,5 +22,6 @@ def test_add(self): def test_add_v2(self): assert 3 == 5 + if __name__ == "__main__": - pytest.main(['-q']) + pytest.main(["-q"]) diff --git a/chapter13/pytest_fixture_demo/testcase/conftest.py b/chapter13/pytest_fixture_demo/testcase/conftest.py index 5f592fc..6afb694 100644 --- a/chapter13/pytest_fixture_demo/testcase/conftest.py +++ b/chapter13/pytest_fixture_demo/testcase/conftest.py @@ -21,4 +21,3 @@ def action_03(): print("class-类型作用域-前置条件") yield print("class-类型作用域-后置条件") - diff --git a/chapter13/pytest_fixture_demo/testcase/test_case1.py b/chapter13/pytest_fixture_demo/testcase/test_case1.py index 458615f..4bdd0a5 100644 --- a/chapter13/pytest_fixture_demo/testcase/test_case1.py +++ b/chapter13/pytest_fixture_demo/testcase/test_case1.py @@ -1,7 +1,9 @@ import pytest + def test_get_user_role(action_01): print(f"获取当前用户角色:{action_01}") + if __name__ == "__main__": - pytest.main() \ No newline at end of file + pytest.main() diff --git a/chapter13/pytest_fixture_demo/tests/test_fixs.py b/chapter13/pytest_fixture_demo/tests/test_fixs.py index c897d99..dc15c7f 100644 --- a/chapter13/pytest_fixture_demo/tests/test_fixs.py +++ b/chapter13/pytest_fixture_demo/tests/test_fixs.py @@ -2,10 +2,12 @@ def setup(): - print('setup 用例开始前执行') + print("setup 用例开始前执行") + def teardown(): - print('teardown 用例结束后执行') + print("teardown 用例结束后执行") + # 定义一个前后置方法 @pytest.fixture diff --git a/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize.py b/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize.py index 32b5d33..aa38c27 100644 --- a/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize.py +++ b/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize.py @@ -4,13 +4,15 @@ data = ["superadmin", "admin", "common"] data2 = ["superadmin2", "admin2", "common2"] + @pytest.mark.parametrize("request_data", data) def test_get_user_role(request_data): print(f"获取当前用户角色:{request_data}") -@pytest.mark.parametrize("data",data) -@pytest.mark.parametrize("data2",data2) -def test_a(data,data2): + +@pytest.mark.parametrize("data", data) +@pytest.mark.parametrize("data2", data2) +def test_a(data, data2): print(f"测试参数组合,data:{data},data2:{data}") diff --git a/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize_class.py b/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize_class.py index ae48243..ad06220 100644 --- a/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize_class.py +++ b/chapter13/pytest_fixture_demo/tests/test_fixs_parametrize_class.py @@ -1,10 +1,13 @@ import pytest -@pytest.mark.parametrize("role_name,age", [("superadmin",45), ("admin",4), ("common",6)]) +@pytest.mark.parametrize( + "role_name,age", [("superadmin", 45), ("admin", 4), ("common", 6)] +) class TestGetUserRole: - def test_get_user_role(self,role_name,age): + def test_get_user_role(self, role_name, age): print(f"获取当前用户角色:{role_name,age}") + if __name__ == "__main__": - pytest.main() \ No newline at end of file + pytest.main() diff --git a/chapter13/pytest_fixture_demo/tests/test_fixs_params.py b/chapter13/pytest_fixture_demo/tests/test_fixs_params.py index 23515eb..46bf1e7 100644 --- a/chapter13/pytest_fixture_demo/tests/test_fixs_params.py +++ b/chapter13/pytest_fixture_demo/tests/test_fixs_params.py @@ -1,15 +1,17 @@ import pytest -data = ["superadmin", "admin","common"] +data = ["superadmin", "admin", "common"] -@pytest.fixture(scope="function",name='user_role_fixture', params=data,autouse=True) + +@pytest.fixture(scope="function", name="user_role_fixture", params=data, autouse=True) def user_role(request): - print("当前用例使用的参数:",request.param) + print("当前用例使用的参数:", request.param) return request.param + def test_get_user_role(user_role_fixture): print(f"获取当前用户角色:{user_role_fixture}") if __name__ == "__main__": - pytest.main() \ No newline at end of file + pytest.main() diff --git a/chapter13/unittest_demo/main.py b/chapter13/unittest_demo/main.py index 76d080d..e735b59 100644 --- a/chapter13/unittest_demo/main.py +++ b/chapter13/unittest_demo/main.py @@ -1,20 +1,21 @@ # unittest导入 import unittest + # 定义测试类 class UnitTestForAdd(unittest.TestCase): # 测试用例运行之前 def setUp(self) -> None: - print('前置条件') + print("前置条件") # 测试用例运行之后 def tearDown(self) -> None: - print('后置条件') + print("后置条件") # 定义测试用例 - def test_add(self): - self.assertEqual(3,3) + self.assertEqual(3, 3) + -if __name__ == '__main__': - unittest.main() \ No newline at end of file +if __name__ == "__main__": + unittest.main() diff --git a/chapter14/booking_system/apis/doctor/api/__init__.py b/chapter14/booking_system/apis/doctor/api/__init__.py index 3159d25..61c5882 100644 --- a/chapter14/booking_system/apis/doctor/api/__init__.py +++ b/chapter14/booking_system/apis/doctor/api/__init__.py @@ -1,3 +1,6 @@ from fastapi import APIRouter -router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) -from ..api import doctor_api \ No newline at end of file + +router_docrot = APIRouter( + prefix="/api/v1", tags=["医生信息模块"], include_in_schema=True +) +from ..api import doctor_api diff --git a/chapter14/booking_system/apis/doctor/api/doctor_api.py b/chapter14/booking_system/apis/doctor/api/doctor_api.py index c3993ed..ae96995 100644 --- a/chapter14/booking_system/apis/doctor/api/doctor_api.py +++ b/chapter14/booking_system/apis/doctor/api/doctor_api.py @@ -8,19 +8,22 @@ from utils.datatime_helper import diff_days_for_now_time -@router_docrot.get("/doctor_list", summary='获取可以预约医生列表信息') +@router_docrot.get("/doctor_list", summary="获取可以预约医生列表信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): - ''' + """ 获取可以预约医生列表信息\n\n :param db_session: 数据库连接依赖注入对象\n\n :return: 返回可以预约医生列表信息\n\n - ''' + """ info = await DoctorServeries.get_doctor_list_infos(db_session) return Success(result=info) -@router_docrot.get("/doctor_scheduling_info", summary='获取医生排班信息') -async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = Depends(depends_get_db_session)): +@router_docrot.get("/doctor_scheduling_info", summary="获取医生排班信息") +async def callbadk( + forms: SchedulingInfo = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), +): # 当前系统日期对比,判断当前是否是否已操作系统时间,超过系统时间预约信息则无法查询 if forms.start_time: try: @@ -30,25 +33,26 @@ async def callbadk(forms: SchedulingInfo = Depends(), db_session: AsyncSession = except: return Fail(message="当前日期无效,日期格式错误!") # 查询排班信息 - doctor_result, doctor_scheduling_result = await DoctorServeries.get_doctor_scheduling_info(db_session, - dno=forms.dno, - start_time=forms.start_time) + doctor_result, doctor_scheduling_result = ( + await DoctorServeries.get_doctor_scheduling_info( + db_session, dno=forms.dno, start_time=forms.start_time + ) + ) scheduling_info = {} for item in doctor_scheduling_result: - if item.ampm == 'am': - if 'am' not in scheduling_info: - scheduling_info['am'] = [] - scheduling_info['am'].append(item) + if item.ampm == "am": + if "am" not in scheduling_info: + scheduling_info["am"] = [] + scheduling_info["am"].append(item) else: - scheduling_info['am'].append(item) - if item.ampm == 'pm': - if 'pm' not in scheduling_info: - scheduling_info['pm'] = [] - scheduling_info['pm'].append(item) + scheduling_info["am"].append(item) + if item.ampm == "pm": + if "pm" not in scheduling_info: + scheduling_info["pm"] = [] + scheduling_info["pm"].append(item) else: - scheduling_info['pm'].append(item) - backinfo = { - 'doctor': doctor_result, - 'scheduling_info': scheduling_info - } - return Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + scheduling_info["pm"].append(item) + backinfo = {"doctor": doctor_result, "scheduling_info": scheduling_info} + return ( + Success(result=backinfo) if doctor_result else Fail(message="当前医生信息信息") + ) diff --git a/chapter14/booking_system/apis/doctor/repository/__init__.py b/chapter14/booking_system/apis/doctor/repository/__init__.py index b0f4153..2753d20 100644 --- a/chapter14/booking_system/apis/doctor/repository/__init__.py +++ b/chapter14/booking_system/apis/doctor/repository/__init__.py @@ -1,6 +1,6 @@ from sqlalchemy import select, update, delete from sqlalchemy.ext.asyncio import AsyncSession -from db.models import Doctorinfo, DoctorScheduling,DoctorSubscribeinfo +from db.models import Doctorinfo, DoctorScheduling, DoctorSubscribeinfo from typing import Optional from utils.datatime_helper import str_to_datatime, datatime_to_str, datetime @@ -13,73 +13,118 @@ async def get_doctor_list_infos(async_session: AsyncSession, enable: int = 1): # query =select(Doctor).with_only_columns(Doctor.dno,Doctor.dnname,Doctor.fee,Doctor.pic,Doctor.rank) # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.fee, Doctorinfo.pic, Doctorinfo.rank) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.fee, + Doctorinfo.pic, + Doctorinfo.rank, + ) _result = await async_session.execute(query.where(Doctorinfo.enable == enable)) # 调用.scalars()这样会返回的是标量值,不是ROW== return _result.all() @staticmethod - async def get_doctor_scheduling_info(async_session: AsyncSession, dno, enable: int = 1, start_time=None): - ''' + async def get_doctor_scheduling_info( + async_session: AsyncSession, dno, enable: int = 1, start_time=None + ): + """ 返回预约医生的排班信息 :param async_session: :param enable: :param start_time: 当前医生的排班时间起点 默认查询当天的时间排班 :param end_time: 当前医生的排班截止时间点 默认查询当天的时间排班 :return: - ''' + """ # 获取排班信息 # 查询出当前医生的信息 - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.destag, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.describe) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.destag, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.describe, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_scheduling_result = [] if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.nsnum, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.tiempm, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.nsnum, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.tiempm, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno) + query = query.where( + DoctorScheduling.enable == enable, DoctorScheduling.dno == dno + ) if start_time: # 格式化时间处理 start_time = str_to_datatime(start_time) - end_time = str_to_datatime(datatime_to_str((start_time + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str((start_time + datetime.timedelta(days=1))) + ) else: # 格式化时间处理 start_time = str_to_datatime(datatime_to_str(datetime.datetime.now())) - end_time = str_to_datatime(datatime_to_str((datetime.datetime.now() + datetime.timedelta(days=1)))) + end_time = str_to_datatime( + datatime_to_str( + (datetime.datetime.now() + datetime.timedelta(days=1)) + ) + ) - - query = query.where(DoctorScheduling.dnotime >= start_time, DoctorScheduling.dnotime < end_time) + query = query.where( + DoctorScheduling.dnotime >= start_time, + DoctorScheduling.dnotime < end_time, + ) _result = await async_session.execute(query) doctor_scheduling_result = _result.all() return doctor_result, doctor_scheduling_result @staticmethod - async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, dno, nsindex, enable: int = 1): - query = select(Doctorinfo.dno, Doctorinfo.dnname, Doctorinfo.pic, Doctorinfo.rank, Doctorinfo.addr,Doctorinfo.fee) - _result = await async_session.execute(query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno)) + async def get_doctor_curr_nsindex_scheduling_info( + async_session: AsyncSession, dno, nsindex, enable: int = 1 + ): + query = select( + Doctorinfo.dno, + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.rank, + Doctorinfo.addr, + Doctorinfo.fee, + ) + _result = await async_session.execute( + query.where(Doctorinfo.enable == enable, Doctorinfo.dno == dno) + ) doctor_result: Optional[Doctorinfo] = _result.first() # 再查询当前医生下面分开上午 和下午的排班信息 doctor_nsnuminfo_result: Optional[DoctorScheduling] = None if doctor_result: - query = select(DoctorScheduling.nsindex, - DoctorScheduling.ampm, - DoctorScheduling.dnotime, - DoctorScheduling.nsnum, - DoctorScheduling.nsnumstock, - DoctorScheduling.tiempm, - DoctorScheduling.tiemampmstr) + query = select( + DoctorScheduling.nsindex, + DoctorScheduling.ampm, + DoctorScheduling.dnotime, + DoctorScheduling.nsnum, + DoctorScheduling.nsnumstock, + DoctorScheduling.tiempm, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.enable == enable, DoctorScheduling.dno == dno, - DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.enable == enable, + DoctorScheduling.dno == dno, + DoctorScheduling.nsindex == nsindex, + ) _result = await async_session.execute(query) doctor_nsnuminfo_result = _result.first() @@ -87,11 +132,19 @@ async def get_doctor_curr_nsindex_scheduling_info(async_session: AsyncSession, d return doctor_result, doctor_nsnuminfo_result @staticmethod - async def updata_nusnum_info_dno(async_session: AsyncSession, dno, nsindex,isup=True): - response = update(DoctorSubscribeinfo).where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + async def updata_nusnum_info_dno( + async_session: AsyncSession, dno, nsindex, isup=True + ): + response = update(DoctorSubscribeinfo).where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) if isup: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum + 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum + 1) + ) else: - result = await async_session.execute(response.values(use_nsnum=DoctorScheduling.use_nsnum - 1)) + result = await async_session.execute( + response.values(use_nsnum=DoctorScheduling.use_nsnum - 1) + ) await async_session.commit() return result.rowcount diff --git a/chapter14/booking_system/apis/hospital/api/__init__.py b/chapter14/booking_system/apis/hospital/api/__init__.py index c4f3dac..51d08b3 100644 --- a/chapter14/booking_system/apis/hospital/api/__init__.py +++ b/chapter14/booking_system/apis/hospital/api/__init__.py @@ -1,4 +1,5 @@ from fastapi import APIRouter -router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) + +router_hospital = APIRouter(prefix="/api/v1", tags=["医院信息模块"]) # 導入模塊 -from apis.hospital.api import get_hospital_info \ No newline at end of file +from apis.hospital.api import get_hospital_info diff --git a/chapter14/booking_system/apis/hospital/api/get_hospital_info.py b/chapter14/booking_system/apis/hospital/api/get_hospital_info.py index 64dd0dc..c01c2cb 100644 --- a/chapter14/booking_system/apis/hospital/api/get_hospital_info.py +++ b/chapter14/booking_system/apis/hospital/api/get_hospital_info.py @@ -6,7 +6,7 @@ from ..api import router_hospital -@router_hospital.get("/hospital_info", summary='获取医院信息') +@router_hospital.get("/hospital_info", summary="获取医院信息") async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): info = await HospitalServeries.get_hospital_info(db_session, id=1) return Success(result=info) diff --git a/chapter14/booking_system/apis/hospital/repository/__init__.py b/chapter14/booking_system/apis/hospital/repository/__init__.py index 2c5bacd..56c2393 100644 --- a/chapter14/booking_system/apis/hospital/repository/__init__.py +++ b/chapter14/booking_system/apis/hospital/repository/__init__.py @@ -9,7 +9,10 @@ class HospitalServeries: @staticmethod async def get_hospital_info(async_session: AsyncSession, id: int): _result = await async_session.execute( - select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) + select( + Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages + ).where(Hospitalinfo.id == id) + ) scalars_result = _result.first() # scalars_result = _result.scalars().first() return scalars_result diff --git a/chapter14/booking_system/apis/payorders/api/__init__.py b/chapter14/booking_system/apis/payorders/api/__init__.py index 2b58ff6..df56d75 100644 --- a/chapter14/booking_system/apis/payorders/api/__init__.py +++ b/chapter14/booking_system/apis/payorders/api/__init__.py @@ -1,7 +1,8 @@ from fastapi import APIRouter -router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) + +router_payorders = APIRouter(prefix="/api/v1", tags=["支付订单模块"]) from apis.payorders.api import doctor_reserve_order from apis.payorders.api import payback_reserve_order from apis.payorders.api import reserve_order_info from apis.payorders.api import doctor_reserve_reorder -from apis.payorders.api import doctor_order_check \ No newline at end of file +from apis.payorders.api import doctor_order_check diff --git a/chapter14/booking_system/apis/payorders/api/doctor_order_check.py b/chapter14/booking_system/apis/payorders/api/doctor_order_check.py index c5a7c3f..b9536b5 100644 --- a/chapter14/booking_system/apis/payorders/api/doctor_order_check.py +++ b/chapter14/booking_system/apis/payorders/api/doctor_order_check.py @@ -15,19 +15,28 @@ from apis.payorders.repository import PayOrderServeries -@router_payorders.post("/doctor_order_check", summary='订单状态查询') -async def callbadk(forms: SubscribeOrderCheckForm=Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): - +@router_payorders.post("/doctor_order_check", summary="订单状态查询") +async def callbadk( + forms: SubscribeOrderCheckForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(db_session,forms.dno, - forms.visit_uopenid, - forms.orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, forms.dno, forms.visit_uopenid, forms.orderid + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") - return Success(api_code=200, result={'status': doctor_nsnum_info_result.statue}, - message='查询成功') if doctor_nsnum_info_result else Fail(api_code=200, result=None, - message='无排班记录信息,或已过有效期') + return ( + Success( + api_code=200, + result={"status": doctor_nsnum_info_result.statue}, + message="查询成功", + ) + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无排班记录信息,或已过有效期") + ) diff --git a/chapter14/booking_system/apis/payorders/api/doctor_reserve_order.py b/chapter14/booking_system/apis/payorders/api/doctor_reserve_order.py index 7d7e810..91826ec 100644 --- a/chapter14/booking_system/apis/payorders/api/doctor_reserve_order.py +++ b/chapter14/booking_system/apis/payorders/api/doctor_reserve_order.py @@ -8,60 +8,79 @@ from apis.payorders.api import router_payorders from apis.payorders.schemas import PayReserveOrderForm from utils.datatime_helper import datetime -from utils import ordernum_helper,json_helper +from utils import ordernum_helper, json_helper from exts.wechatpy.pay import WeChatPay, WeChatPayException from config.config import get_settings from apis.payorders.dependencies import get_client_ip + # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client from exts.async_rabbit import async_rabbit_client import decimal from asgiref.sync import sync_to_async -@router_payorders.post("/doctor_reserve_order", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + +@router_payorders.post( + "/doctor_reserve_order", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -72,7 +91,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -80,118 +99,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 60 * 15 - order_exchange_name = 'xz-order-exchange' - order_routing_key = 'order_handler' - sync_rabbit_client.send_basic_publish(exchange_name=order_exchange_name, routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange" + order_routing_key = "order_handler" + sync_rabbit_client.send_basic_publish( + exchange_name=order_exchange_name, + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -202,7 +258,7 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -210,122 +266,155 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') - - -@router_payorders.post("/doctor_reserve_order_async_as_tarn", summary='填写预约人员信息,处理订单的提交') -async def callbadk(forms: PayReserveOrderForm, - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) + + +@router_payorders.post( + "/doctor_reserve_order_async_as_tarn", summary="填写预约人员信息,处理订单的提交" +) +async def callbadk( + forms: PayReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 检测是否没支付的订单信息,取消或支付后才可以继续操作预约 - get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state(db_session, - visit_uopenid=forms.visit_uopenid, - statue=1) + get_order_info = await PayOrderServeries.get_order_info_byvisit_uopenid_state( + db_session, visit_uopenid=forms.visit_uopenid, statue=1 + ) if get_order_info: - return Fail(api_code=200, result=None, message='您当前存在未支付的订单记录,请支付或取消后再操作!') + return Fail( + api_code=200, + result=None, + message="您当前存在未支付的订单记录,请支付或取消后再操作!", + ) # 下单处理 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_nsnuminfo_result: - return Fail(api_code=200, result=None, message='排班信息不存在!!') + return Fail(api_code=200, result=None, message="排班信息不存在!!") - tiempmss = str(doctor_nsnuminfo_result.tiempm).split(' ')[1].split(':') + tiempmss = str(doctor_nsnuminfo_result.tiempm).split(" ")[1].split(":") visitday = str(doctor_nsnuminfo_result.dnotime) visitdaytime = f"{visitday} {tiempmss[0]}:{tiempmss[1]}:00" tiemampmstr = doctor_nsnuminfo_result.tiemampmstr - visittime = '{} {} {}'.format(num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', tiemampmstr) + visittime = "{} {} {}".format( + num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + tiemampmstr, + ) # 订单编号 orderid = ordernum_helper.order_num_3(user_num=forms.visit_uphone) payfee = str(doctor_result.fee) order_info = { - 'dno': forms.dno, - 'nsindex': forms.nsindex, - 'orderid': orderid, - 'visit_uphone': forms.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': visittime + "dno": forms.dno, + "nsindex": forms.nsindex, + "orderid": orderid, + "visit_uphone": forms.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": visittime, } # 开始提交微信支付生成订单信息 order_info_json = json_helper.dict_to_json(order_info) # 支付订单生成,但是注意的地方是,这里因为是同步的的,这里回引起阻塞哟! - - - - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) try: # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -336,7 +425,8 @@ async def callbadk(forms: PayReserveOrderForm, attach = f"{forms.dno}|{orderid}|{forms.nsindex}" # 支付响应回调对象 - pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)(trade_type='JSAPI', + pay_wx_res_result = await sync_to_async(func=wx_pay.order.create)( + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -344,7 +434,8 @@ async def callbadk(forms: PayReserveOrderForm, notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid) + out_trade_no=orderid, + ) # pay_wx_res_result = wx_pay.order.create( # trade_type='JSAPI', @@ -360,64 +451,83 @@ async def callbadk(forms: PayReserveOrderForm, pass except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.return_msg'] = wcpayex.errmsg + order_info["wcpayex.return_msg"] = wcpayex.errmsg print(wcpayex.errmsg) - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}') + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!{wcpayex.errmsg}", + ) except Exception: - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) - - - - creat_order_info_result = await PayOrderServeries.creat_order_info(db_session, dno=forms.dno, - orderid=orderid, - # 订单所属-支付诊费 - payfee=payfee, - visit_uname=forms.visit_uname, - visit_uopenid=forms.visit_uopenid, - visit_uphone=forms.visit_uphone, - visit_usex=forms.visit_usex, - visit_uage=forms.visit_uage, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) - statue=1, - # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) - visit_statue=0, - # 订单所属-就诊日期 - visitday=visitday, - # 订单所属-就诊时间(周x-上午-8:00) - visittime=visittime, - create_time=datetime.datetime.now(), - # ========================= - nsindex=forms.nsindex - ) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) + creat_order_info_result = await PayOrderServeries.creat_order_info( + db_session, + dno=forms.dno, + orderid=orderid, + # 订单所属-支付诊费 + payfee=payfee, + visit_uname=forms.visit_uname, + visit_uopenid=forms.visit_uopenid, + visit_uphone=forms.visit_uphone, + visit_usex=forms.visit_usex, + visit_uage=forms.visit_uage, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单) + statue=1, + # 订单所属-就诊状态(0:待预约 1:待就诊 2:已就诊) + visit_statue=0, + # 订单所属-就诊日期 + visitday=visitday, + # 订单所属-就诊时间(周x-上午-8:00) + visittime=visittime, + create_time=datetime.datetime.now(), + # ========================= + nsindex=forms.nsindex, + ) # 订单创建完成后,需要执行预约号源数的库存扣减 # 开始发送订单到消息队列中 # 获取消息操作事件- 15分钟(函数内部已经*1000) pay_message_ttl = 5 - order_exchange_name = 'xz-order-exchange1' - order_routing_key = 'order_handler1' - await async_rabbit_client.send_basic_publish(routing_key=order_routing_key, - body=order_info_json, content_type='application/json', is_delay=True, - message_ttl=pay_message_ttl) + order_exchange_name = "xz-order-exchange1" + order_routing_key = "order_handler1" + await async_rabbit_client.send_basic_publish( + routing_key=order_routing_key, + body=order_info_json, + content_type="application/json", + is_delay=True, + message_ttl=pay_message_ttl, + ) if creat_order_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, message='订单预约成功!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="订单预约成功!", + ) # 记录请求异常回调信息 - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter14/booking_system/apis/payorders/api/doctor_reserve_reorder.py b/chapter14/booking_system/apis/payorders/api/doctor_reserve_reorder.py index 2df8b1f..b098b40 100644 --- a/chapter14/booking_system/apis/payorders/api/doctor_reserve_reorder.py +++ b/chapter14/booking_system/apis/payorders/api/doctor_reserve_reorder.py @@ -12,70 +12,96 @@ import decimal -@router_payorders.get("/doctor_reserve_order", summary='未支付订单重新发起支付') -async def callbadk(forms: PayCancelPayOrderForm = Depends(), - db_session: AsyncSession = Depends(depends_get_db_session), - client_ip: str = Depends(get_client_ip)): +@router_payorders.get("/doctor_reserve_order", summary="未支付订单重新发起支付") +async def callbadk( + forms: PayCancelPayOrderForm = Depends(), + db_session: AsyncSession = Depends(depends_get_db_session), + client_ip: str = Depends(get_client_ip), +): # 获取预约详情信息列表 - doctor_order_info_result = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_order_info_result = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) print(doctor_order_info_result.dno) # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) # 先查询出上次下单的记录到的信息 if not doctor_order_info_result: - return Fail(api_code=200, result=None, message='无此订单记录信息!') + return Fail(api_code=200, result=None, message="无此订单记录信息!") if doctor_order_info_result.statue == 4: - return Fail(api_code=200, result=None, message='订单已超时未支付!建议取消重新下单!') + return Fail( + api_code=200, result=None, message="订单已超时未支付!建议取消重新下单!" + ) # 对订单信息进行校验,只有未付款的清单信息才可以继续下一步的支付的操作 if doctor_order_info_result.statue != 1: - return Fail(api_code=200, result=None, message='订单信息状态异常信息!无法继续支付!建议取消重新下单!') + return Fail( + api_code=200, + result=None, + message="订单信息状态异常信息!无法继续支付!建议取消重新下单!", + ) # 查询当前预约时段 nsindex = doctor_order_info_result.nsindex # 查询排班信息 - doctor_nsnum_info_result = await PayOrderServeries.get_doctor_scheduling_info_info_order(db_session, dno=forms.dno, - nsindex=nsindex) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_doctor_scheduling_info_info_order( + db_session, dno=forms.dno, nsindex=nsindex + ) + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='无排班记录信息!') + return Fail(api_code=200, result=None, message="无排班记录信息!") # 对比当前的预约时段是否有效 - print('doctor_nsnum_info_result.tiempm', doctor_nsnum_info_result.tiempm) + print("doctor_nsnum_info_result.tiempm", doctor_nsnum_info_result.tiempm) if not datatime_helper.effectiveness_tiempm(str(doctor_nsnum_info_result.tiempm)): - return Fail(api_code=200, result=None, message='当前预约时段无效!请更换另一个时段进行预约!') + return Fail( + api_code=200, + result=None, + message="当前预约时段无效!请更换另一个时段进行预约!", + ) order_info = { - 'dno': forms.dno, - 'nsindex': nsindex, - 'orderid': doctor_order_info_result.orderid if doctor_order_info_result.orderid else None, - 'visit_uphone': doctor_order_info_result.visit_uphone, - 'visit_uopenid': forms.visit_uopenid, - 'visittime': doctor_order_info_result.visittime + "dno": forms.dno, + "nsindex": nsindex, + "orderid": ( + doctor_order_info_result.orderid + if doctor_order_info_result.orderid + else None + ), + "visit_uphone": doctor_order_info_result.visit_uphone, + "visit_uopenid": forms.visit_uopenid, + "visittime": doctor_order_info_result.visittime, } # 新手支付生成 try: - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, - mch_id=get_settings().MCH_ID) + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) orderid = doctor_order_info_result.orderid order_info_json = json_helper.dict_to_json(order_info) payfee = doctor_order_info_result.payfee visittime = doctor_order_info_result.visittime # ================= - doctor_info_result = await PayOrderServeries.get_doctor_info(db_session, dno=forms.dno) + doctor_info_result = await PayOrderServeries.get_doctor_info( + db_session, dno=forms.dno + ) dnname = doctor_info_result.dnname # 解决办法:01商户订单号重复 问题 # 保证再次支付下单时发起的请求参数和第一次一样。 # 商品描述 - body = f'XXX中医馆诊费' + body = f"XXX中医馆诊费" # 商品详细描述 - detail = f'XXX中医馆预约时段:{visittime}' + detail = f"XXX中医馆预约时段:{visittime}" # 总金额,单位分 total_fee = decimal.Decimal(payfee) * 100 # total_fee = 1 @@ -86,7 +112,7 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), attach = f"{forms.dno}|{orderid}|{nsindex}" # 支付响应回调对象 pay_wx_res_result = wx_pay.order.create( - trade_type='JSAPI', + trade_type="JSAPI", body=body, detail=detail, total_fee=total_fee, @@ -94,49 +120,72 @@ async def callbadk(forms: PayCancelPayOrderForm = Depends(), notify_url=notify_url, attach=attach, user_id=forms.visit_uopenid, - out_trade_no=orderid + out_trade_no=orderid, ) except WeChatPayException as wcpayex: # 记录请求异常回调信息 - order_info['wcpayex.errmsg'] = wcpayex.errmsg - return Fail(api_code=200, result=None, message=f'微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}') + order_info["wcpayex.errmsg"] = wcpayex.errmsg + return Fail( + api_code=200, + result=None, + message=f"微信支付配置服务异常,请稍后重试!!错误提示{wcpayex.errmsg}", + ) except Exception: import traceback + traceback.print_exc() - return Fail(api_code=200, result=None, message='微信支付服务未知错误异常,请稍后重试!!') + return Fail( + api_code=200, + result=None, + message="微信支付服务未知错误异常,请稍后重试!!", + ) - return_code = pay_wx_res_result.get('return_code') - if return_code == 'SUCCESS': + return_code = pay_wx_res_result.get("return_code") + if return_code == "SUCCESS": # 提取相关的参数信息 - wx_gzx_id = pay_wx_res_result.get('appid') - wx_mch_id = pay_wx_res_result.get('mch_id') - sign = pay_wx_res_result.get('sign') - nonce_str = pay_wx_res_result.get('nonce_str') - prepay_id = pay_wx_res_result.get('prepay_id') + wx_gzx_id = pay_wx_res_result.get("appid") + wx_mch_id = pay_wx_res_result.get("mch_id") + sign = pay_wx_res_result.get("sign") + nonce_str = pay_wx_res_result.get("nonce_str") + prepay_id = pay_wx_res_result.get("prepay_id") # 二次前面返回相关的支付信息 timestamp = str(datatime_helper.get_timestamp10()) - wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai(prepay_id=pay_wx_res_result.get('prepay_id'), - timestamp=timestamp, - nonce_str=pay_wx_res_result.get('nonce_str')) + wx_jsapi_data = wx_pay.order.get_appapi_params_xiugai( + prepay_id=pay_wx_res_result.get("prepay_id"), + timestamp=timestamp, + nonce_str=pay_wx_res_result.get("nonce_str"), + ) # 更新当前支付的订单信息 # 更新没有支付的成功的订单的,状态! - doctor_nsnum_info_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, - dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=1, - ) + doctor_nsnum_info_result = ( + await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=1, + ) + ) if doctor_nsnum_info_result: - return Success(api_code=200, result={'orderid': orderid, 'wx_info': wx_jsapi_data}, - message='您已提交订单,请尽快支付哟!') + return Success( + api_code=200, + result={"orderid": orderid, "wx_info": wx_jsapi_data}, + message="您已提交订单,请尽快支付哟!", + ) else: - order_info['creat_order_info_error'] = '创建订单到数据库的时候异常' - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["creat_order_info_error"] = "创建订单到数据库的时候异常" + return Fail( + api_code=200, + result=None, + message="微信服务请求处理异常,请稍后重试!!", + ) else: # 记录请求异常回调信息 - order_info['wx_return_code'] = pay_wx_res_result.get('return_code') - order_info['wx_return_msg'] = pay_wx_res_result.get('return_msg') - return Fail(api_code=200, result=None, message='微信服务请求处理异常,请稍后重试!!') + order_info["wx_return_code"] = pay_wx_res_result.get("return_code") + order_info["wx_return_msg"] = pay_wx_res_result.get("return_msg") + return Fail( + api_code=200, result=None, message="微信服务请求处理异常,请稍后重试!!" + ) diff --git a/chapter14/booking_system/apis/payorders/api/payback_reserve_order.py b/chapter14/booking_system/apis/payorders/api/payback_reserve_order.py index 7089a56..8edef4c 100644 --- a/chapter14/booking_system/apis/payorders/api/payback_reserve_order.py +++ b/chapter14/booking_system/apis/payorders/api/payback_reserve_order.py @@ -10,60 +10,80 @@ from exts.wechatpy.client import WeChatClient - -@router_payorders.post("/payback_reserve_order", summary='支付订单回调处理') -async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_get_db_session)): - wx_pay = WeChatPay(appid=get_settings().GZX_ID, api_key=get_settings().GZX_PAY_KEY, mch_id=get_settings().MCH_ID) +@router_payorders.post("/payback_reserve_order", summary="支付订单回调处理") +async def callbadk( + request: Request, db_session: AsyncSession = Depends(depends_get_db_session) +): + wx_pay = WeChatPay( + appid=get_settings().GZX_ID, + api_key=get_settings().GZX_PAY_KEY, + mch_id=get_settings().MCH_ID, + ) body = await request.body() try: _result = wx_pay.parse_payment_result(body) except InvalidSignatureException as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - out_trade_no = _result.get('out_trade_no') + out_trade_no = _result.get("out_trade_no") # 微信要求的回复的模式 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="application/xml") except Exception as e: # 日志记录 _result = xmlhelper.parse_xml_data(body) - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") if _result: # 返回状态码信息 - return_code = _result.get('return_code') + return_code = _result.get("return_code") # 处理状态码 - if return_code != 'SUCCESS': + if return_code != "SUCCESS": # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 业务错误处理结果 - result_code = _result.get('result_code') + result_code = _result.get("result_code") # 业务支付成功处理 - if result_code == 'SUCCESS': + if result_code == "SUCCESS": pass - wx_gzx_id = _result.get('appid') - attach = _result.get('attach') - bank_type = _result.get('bank_type') - cash_fee = _result.get('cash_fee') - fee_type = _result.get('fee_type') - is_subscribe = _result.get('is_subscribe') - wx_mch_id = _result.get('mch_id') - nonce_str = _result.get('nonce_str') - openid = _result.get('openid') - out_trade_no = _result.get('out_trade_no') - time_end = _result.get('time_end') - total_fee = _result.get('total_fee') - trade_type = _result.get('trade_type') - transaction_id = _result.get('transaction_id') + wx_gzx_id = _result.get("appid") + attach = _result.get("attach") + bank_type = _result.get("bank_type") + cash_fee = _result.get("cash_fee") + fee_type = _result.get("fee_type") + is_subscribe = _result.get("is_subscribe") + wx_mch_id = _result.get("mch_id") + nonce_str = _result.get("nonce_str") + openid = _result.get("openid") + out_trade_no = _result.get("out_trade_no") + time_end = _result.get("time_end") + total_fee = _result.get("total_fee") + trade_type = _result.get("trade_type") + transaction_id = _result.get("transaction_id") # 回调透传信息 attach-在查询API和支付通知中原样返回,可作为自定义参数使用。 - #attach = f"{forms.dno}|{orderid}|{forms.nsindex}" + # attach = f"{forms.dno}|{orderid}|{forms.nsindex}" attach_info = attach.split("|") attach_dno = attach_info[0] attach_orderid = attach_info[1] @@ -71,73 +91,103 @@ async def callbadk(request: Request, db_session: AsyncSession = Depends(depends_ attach_nsindex = attach_info[2] # 查询当前的订单的支付状态 - doctor_nsnum_info_result = await PayOrderServeries.get_order_info_byorder_dno_state(db_session, attach_dno, - attach_orderid) + doctor_nsnum_info_result = ( + await PayOrderServeries.get_order_info_byorder_dno_state( + db_session, attach_dno, attach_orderid + ) + ) if not doctor_nsnum_info_result: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") # 订单信息存在 # 更新支付的成功状态! # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) if doctor_nsnum_info_result.statue == 2: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") - isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno(db_session, dno=attach_dno, - orderid=attach_orderid, - visit_uopenid=attach_visit_uopenid, - updata={ - 'statue': 2, - # 标记已支付,待就诊! - 'visit_statue': 1, - 'notify_callback_time': 'now()', - 'is_subscribe': is_subscribe, - } - ) + isok, updata_result = await PayOrderServeries.updata_order_info_byorder_dno( + db_session, + dno=attach_dno, + orderid=attach_orderid, + visit_uopenid=attach_visit_uopenid, + updata={ + "statue": 2, + # 标记已支付,待就诊! + "visit_statue": 1, + "notify_callback_time": "now()", + "is_subscribe": is_subscribe, + }, + ) # 设置具体的点击通知URL地址为,查询订单详情页信息地址 visittime = doctor_nsnum_info_result.visittime visitday = doctor_nsnum_info_result.visitday # 模板订单跳转地址详情信息 - template_url = f'http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}' + template_url = f"http://xxxxxxxx/pages/orderDetailed/orderDetailed?did={attach_dno}&oid={attach_orderid}" if isok: # 开发发送预约成功的模板通知信息 - client = WeChatClient(appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET) + client = WeChatClient( + appid=get_settings().GZX_ID, secret=get_settings().GZX_SECRET + ) # client.session = sync_redis_client - resulst = client.message.send_template(to_user_openid=attach_visit_uopenid, - template_id='XXXXXXXXXXXXXXXXXXXXXX', - url=template_url, - data={ - "first": { - "value": f"您预约挂号{visitday}{visittime}成功!", - "color": "#173177" - }, - # 科室 - "keyword2": { - "value": "中医科", - "color": "#173177" - }, - # 就诊地址 - "keyword3": { - "value": "XXXXXXXXXXXXXX中医馆", - "color": "#173177" - }, - # 备注信息 - "remark": { - "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", - "color": "#173177" - } - } - ) + resulst = client.message.send_template( + to_user_openid=attach_visit_uopenid, + template_id="XXXXXXXXXXXXXXXXXXXXXX", + url=template_url, + data={ + "first": { + "value": f"您预约挂号{visitday}{visittime}成功!", + "color": "#173177", + }, + # 科室 + "keyword2": {"value": "中医科", "color": "#173177"}, + # 就诊地址 + "keyword3": { + "value": "XXXXXXXXXXXXXX中医馆", + "color": "#173177", + }, + # 备注信息 + "remark": { + "value": "本次预约成功,如需取消,请在就诊前一天申请,超过时间则申请无效,无法退费,谢谢谅解!", + "color": "#173177", + }, + }, + ) # 响应微信支付回调处理 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") else: # 微信手机支付回调失败订单号 - resXml = "" + "" + "" + " " + resXml = ( + "" + + "" + + "" + + " " + ) return Response(content=resXml, media_type="text/xml; charset=utf-8") diff --git a/chapter14/booking_system/apis/payorders/api/reserve_order_info.py b/chapter14/booking_system/apis/payorders/api/reserve_order_info.py index e5f9139..2f621e0 100644 --- a/chapter14/booking_system/apis/payorders/api/reserve_order_info.py +++ b/chapter14/booking_system/apis/payorders/api/reserve_order_info.py @@ -9,13 +9,17 @@ from utils.datatime_helper import diff_days_for_now_time - -@router_payorders.post("/reserve_order_info", summary='获取预约订单信息') -async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_payorders.post("/reserve_order_info", summary="获取预约订单信息") +async def callbadk( + forms: MakeReserveOrderForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 查询预约信息 - doctor_result, doctor_nsnuminfo_result = await DoctorServeries.get_doctor_curr_nsindex_scheduling_info(db_session, - dno=forms.dno, - nsindex=forms.nsindex) + doctor_result, doctor_nsnuminfo_result = ( + await DoctorServeries.get_doctor_curr_nsindex_scheduling_info( + db_session, dno=forms.dno, nsindex=forms.nsindex + ) + ) if not doctor_result: return Fail(message="当前医生信息不存在!") if not doctor_nsnuminfo_result: @@ -28,11 +32,15 @@ async def callbadk(forms: MakeReserveOrderForm, db_session: AsyncSession = Depen if is_limt_start_time < 0: return Fail(message="当前日期无效,无排班信息!") backresult = { - 'dnotime': str(doctor_nsnuminfo_result.dnotime), - 'dnoampm_tag': '{} {} {}'.format( + "dnotime": str(doctor_nsnuminfo_result.dnotime), + "dnoampm_tag": "{} {} {}".format( num_to_string(doctor_nsnuminfo_result.dnotime.isoweekday()), - '上午' if doctor_nsnuminfo_result.ampm == 'am' else '下午', - doctor_nsnuminfo_result.tiemampmstr - ) + "上午" if doctor_nsnuminfo_result.ampm == "am" else "下午", + doctor_nsnuminfo_result.tiemampmstr, + ), } - return Success(result={**doctor_result, **backresult}) if doctor_result else Fail(message="无当前医生排班信息") \ No newline at end of file + return ( + Success(result={**doctor_result, **backresult}) + if doctor_result + else Fail(message="无当前医生排班信息") + ) diff --git a/chapter14/booking_system/apis/payorders/dependencies/__init__.py b/chapter14/booking_system/apis/payorders/dependencies/__init__.py index 3d64412..60365ca 100644 --- a/chapter14/booking_system/apis/payorders/dependencies/__init__.py +++ b/chapter14/booking_system/apis/payorders/dependencies/__init__.py @@ -1,5 +1,6 @@ from starlette.requests import Request + def get_client_ip(request: Request): """ 获取客户端真实ip @@ -9,4 +10,4 @@ def get_client_ip(request: Request): forwarded = request.headers.get("X-Forwarded-For") if forwarded: return forwarded.split(",")[0] - return request.client.host \ No newline at end of file + return request.client.host diff --git a/chapter14/booking_system/apis/payorders/repository/__init__.py b/chapter14/booking_system/apis/payorders/repository/__init__.py index 26c9bda..f853035 100644 --- a/chapter14/booking_system/apis/payorders/repository/__init__.py +++ b/chapter14/booking_system/apis/payorders/repository/__init__.py @@ -4,78 +4,91 @@ from typing import Optional from db.async_database import async_context_get_db + class PayOrderServeries: @staticmethod - async def get_order_info_dno_orderid_visituopenid_state(async_session: AsyncSession, dno, visit_uopenid, - orderid)->DoctorSubscribeinfo: + async def get_order_info_dno_orderid_visituopenid_state( + async_session: AsyncSession, dno, visit_uopenid, orderid + ) -> DoctorSubscribeinfo: query = select(DoctorSubscribeinfo) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) _result = await async_session.execute(query) # 如果查询时整个模型的需要.scalar() # 如果是查询指定选择某些字段的是则不需要.scalar() # .scalar() 和 _result.scalars().first() 是一样效果 return _result.scalars().first() - - @staticmethod - async def get_doctor_info(async_session: AsyncSession, dno)->Doctorinfo: - - query = select( Doctorinfo.dnname, - Doctorinfo.pic, - Doctorinfo.dno, - Doctorinfo.rank, - Doctorinfo.fee, - Doctorinfo.destag, - Doctorinfo.describe) + async def get_doctor_info(async_session: AsyncSession, dno) -> Doctorinfo: + + query = select( + Doctorinfo.dnname, + Doctorinfo.pic, + Doctorinfo.dno, + Doctorinfo.rank, + Doctorinfo.fee, + Doctorinfo.destag, + Doctorinfo.describe, + ) # 查询当前医生排班信息归属 query = query.where(Doctorinfo.dno == dno) _result = await async_session.execute(query) return _result.first() - - @staticmethod - async def get_doctor_scheduling_info_info_order(async_session: AsyncSession, dno, nsindex) -> DoctorScheduling: - query = select(DoctorScheduling.dnotime, - DoctorScheduling.ampm, - DoctorScheduling.tiempm, - DoctorScheduling.dnotime, - DoctorScheduling.tiemampmstr, - ) + async def get_doctor_scheduling_info_info_order( + async_session: AsyncSession, dno, nsindex + ) -> DoctorScheduling: + query = select( + DoctorScheduling.dnotime, + DoctorScheduling.ampm, + DoctorScheduling.tiempm, + DoctorScheduling.dnotime, + DoctorScheduling.tiemampmstr, + ) # 查询当前医生排班信息归属 - query = query.where(DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex) + query = query.where( + DoctorScheduling.dno == dno, DoctorScheduling.nsindex == nsindex + ) _result = await async_session.execute(query) return _result.first() @staticmethod - async def get_order_info_byvisit_uopenid_state(async_session: AsyncSession, visit_uopenid, statue=1): - ''' + async def get_order_info_byvisit_uopenid_state( + async_session: AsyncSession, visit_uopenid, statue=1 + ): + """ 判断是否存在存在未支付的订单 :param async_session: 数据库会话对象 :param visit_uopenid: 当前用户opendi :param statue: 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 :return: - ''' + """ # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = select(DoctorSubscribeinfo.id) # 查询当前医生排班信息归属 - query = query.where(DoctorSubscribeinfo.statue == statue, DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.statue == statue, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) _result = await async_session.execute(query) return _result.first() @staticmethod async def creat_order_info(async_session: AsyncSession, **kwargs): - ''' + """ 开始创建订单内容,并添加到数据库 :param async_session: :param kwargs: :return: - ''' + """ new_order = DoctorSubscribeinfo(**kwargs) async_session.add(new_order) await async_session.commit() @@ -83,40 +96,57 @@ async def creat_order_info(async_session: AsyncSession, **kwargs): return new_order @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno(async_session: AsyncSession, dno, orderid, visit_uopenid, **updata): + async def updata_order_info_byorder_dno( + async_session: AsyncSession, dno, orderid, visit_uopenid, **updata + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() query = update(DoctorSubscribeinfo) - query = query.where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid) + query = query.where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + ) result = await async_session.execute(query.values(updata)) await async_session.commit() # result.rowcount 1:更新成功 0 更新失败 return result.rowcount -if __name__ == '__main__': +if __name__ == "__main__": import asyncio + async def sdsdf(): async with async_context_get_db() as session: - asdas = await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state(session, - dno='10001', - visit_uopenid='orE7I56mAt_dvtRoXkMw-hY8FkwM', - orderid='2207081548588935269') + asdas = ( + await PayOrderServeries.get_order_info_dno_orderid_visituopenid_state( + session, + dno="10001", + visit_uopenid="orE7I56mAt_dvtRoXkMw-hY8FkwM", + orderid="2207081548588935269", + ) + ) print(asdas.orderid) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter14/booking_system/apis/payorders/schemas/__init__.py b/chapter14/booking_system/apis/payorders/schemas/__init__.py index f9db523..d79c74a 100644 --- a/chapter14/booking_system/apis/payorders/schemas/__init__.py +++ b/chapter14/booking_system/apis/payorders/schemas/__init__.py @@ -6,7 +6,7 @@ class SchedulingInfo(BaseModel): # 预约医生编号 dno: str # 预约时间 - start_time:str = None + start_time: str = None class MakeReserveOrderForm(BaseModel): @@ -16,16 +16,13 @@ class MakeReserveOrderForm(BaseModel): nsindex: str - class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") - - class PayReserveOrderForm(BaseModel): # 预约医生编号 dno: str @@ -34,18 +31,18 @@ class PayReserveOrderForm(BaseModel): # 预约人信息 visit_uname: str visit_uphone: str - visit_uopenid:str =None - visit_usex:str - visit_uage:str + visit_uopenid: str = None + visit_usex: str + visit_uage: str class PayCancelPayOrderForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - orderid:str + orderid: str # 预约医生的编号 - dno:str - + dno: str diff --git a/chapter14/booking_system/apis/userorders/api/__init__.py b/chapter14/booking_system/apis/userorders/api/__init__.py index 5cf6f5a..1226a32 100644 --- a/chapter14/booking_system/apis/userorders/api/__init__.py +++ b/chapter14/booking_system/apis/userorders/api/__init__.py @@ -1,4 +1,10 @@ from fastapi import APIRouter -router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) -from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ - wxauth_login + +router_userorders = APIRouter(prefix="/api/v1", tags=["用户订单模块"]) +from apis.userorders.api import ( + refund_reserve_order, + unpay_reserve_order, + user_order_info, + user_order_list, + wxauth_login, +) diff --git a/chapter14/booking_system/apis/userorders/api/refund_reserve_order.py b/chapter14/booking_system/apis/userorders/api/refund_reserve_order.py index dd9f94f..4d7b772 100644 --- a/chapter14/booking_system/apis/userorders/api/refund_reserve_order.py +++ b/chapter14/booking_system/apis/userorders/api/refund_reserve_order.py @@ -10,54 +10,78 @@ import time -@router_userorders.put("/refund_reserve_order", summary='订单退款申请') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/refund_reserve_order", summary="订单退款申请") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 1: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单还为支付!无法申请退款!') + return Fail(api_code=200, result=None, message="该订单还为支付!无法申请退款!") if doctor_nsnum_info_result.statue == 5: pass - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该已超时未支付,订单已过有效期!不可操作!') + return Fail( + api_code=200, + result=None, + message="该已超时未支付,订单已过有效期!不可操作!", + ) # 已经支付的订单信息 if doctor_nsnum_info_result.statue == 2: pass # 来获取时间差中的秒数。注意,seconds获得的秒只是时间差中的小时、分钟和秒部分的和,并没有包含时间差的天数(既是两个时间点不是同一天,失效) - today = time.strftime('%Y%m%d %H:%M:%S', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 - datiem = (currday_time_info_tochane_datetime(doctor_nsnum_info_result.visitday) - datetime.timedelta(days=1)) - subscribe_times = datetime.datetime.strptime(f"{str(datiem).replace('00:00:00', '')}23:59:59", - "%Y-%m-%d %H:%M:%S") + today = time.strftime("%Y%m%d %H:%M:%S", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 + datiem = currday_time_info_tochane_datetime( + doctor_nsnum_info_result.visitday + ) - datetime.timedelta(days=1) + subscribe_times = datetime.datetime.strptime( + f"{str(datiem).replace('00:00:00', '')}23:59:59", "%Y-%m-%d %H:%M:%S" + ) # 当前时间小于预约时间的最后截止时间之后就不可以预约 if todaydate >= subscribe_times: - return Fail(api_code=200, result=None, message='非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!') - - isok = Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - updata={ - 'statue': 5, - 'refund_statue': 1, - 'apply_refund_time': 'now()' - } - ) - return Success(api_code=200, result=None, message='申请退款成功!已提交审核!') if isok else Fail(api_code=200, result=None, - message='申请退款失败!') + return Fail( + api_code=200, + result=None, + message="非常抱歉,您已超过申请退款约定时间,暂无法给你申请退款处理!", + ) + + isok = Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + updata={"statue": 5, "refund_statue": 1, "apply_refund_time": "now()"}, + ) + return ( + Success(api_code=200, result=None, message="申请退款成功!已提交审核!") + if isok + else Fail(api_code=200, result=None, message="申请退款失败!") + ) diff --git a/chapter14/booking_system/apis/userorders/api/unpay_reserve_order.py b/chapter14/booking_system/apis/userorders/api/unpay_reserve_order.py index 871cc7f..3534acf 100644 --- a/chapter14/booking_system/apis/userorders/api/unpay_reserve_order.py +++ b/chapter14/booking_system/apis/userorders/api/unpay_reserve_order.py @@ -7,40 +7,57 @@ from ..repository import Serveries -@router_userorders.put("/unpay_reserve_order", summary='取消订单支付') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.put("/unpay_reserve_order", summary="取消订单支付") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测订单的状态 - doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state(db_session, dno=forms.dno, - orderid=forms.orderid) + doctor_nsnum_info_result = await Serveries.get_order_info_byorder_dno_state( + db_session, dno=forms.dno, orderid=forms.orderid + ) if not doctor_nsnum_info_result: - return Fail(api_code=200, result=None, message='暂无此订单记录信息!') + return Fail(api_code=200, result=None, message="暂无此订单记录信息!") if doctor_nsnum_info_result.statue == 3: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已操作过取消!请勿重复操作!') + return Fail( + api_code=200, result=None, message="订单已操作过取消!请勿重复操作!" + ) if doctor_nsnum_info_result.statue == 4: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='订单已过有效期!不可操作!') + return Fail(api_code=200, result=None, message="订单已过有效期!不可操作!") if doctor_nsnum_info_result.statue == 2: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单已支付成功!如需取消,请申请操作退款!') + return Fail( + api_code=200, + result=None, + message="该订单已支付成功!如需取消,请申请操作退款!", + ) if doctor_nsnum_info_result.statue == 5: pass # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单) - return Fail(api_code=200, result=None, message='该订单处于申请退款状态,请勿重复操作!') + return Fail( + api_code=200, result=None, message="该订单处于申请退款状态,请勿重复操作!" + ) # 更新没有支付的成功的订单的,状态! - isok = await Serveries.updata_order_info_byorder_dno_olny(db_session, dno=forms.dno, - orderid=forms.orderid, - visit_uopenid=forms.visit_uopenid, - statue=3 - ) - - return Success(api_code=200, result=None, message='订单取消成功') if isok else Fail(api_code=200, result=None, - message='订单取消失败') + isok = await Serveries.updata_order_info_byorder_dno_olny( + db_session, + dno=forms.dno, + orderid=forms.orderid, + visit_uopenid=forms.visit_uopenid, + statue=3, + ) + + return ( + Success(api_code=200, result=None, message="订单取消成功") + if isok + else Fail(api_code=200, result=None, message="订单取消失败") + ) diff --git a/chapter14/booking_system/apis/userorders/api/user_order_info.py b/chapter14/booking_system/apis/userorders/api/user_order_info.py index 8db523d..4c3b182 100644 --- a/chapter14/booking_system/apis/userorders/api/user_order_info.py +++ b/chapter14/booking_system/apis/userorders/api/user_order_info.py @@ -10,15 +10,23 @@ import time -@router_userorders.post("/user_order_info", summary='用户订单详情查看') -async def callbadk(forms: SubscribeOrderCheckForm, db_session: AsyncSession = Depends(depends_get_db_session)): +@router_userorders.post("/user_order_info", summary="用户订单详情查看") +async def callbadk( + forms: SubscribeOrderCheckForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 获取预约详情信息列表 - doctor_nsnum_info_result = await Serveries.get_order_info_list_by_visit_uopenid_detailt( - db_session, - visit_uopenid=forms.visit_uopenid.strip(), - orderid=forms.orderid.strip(), - dno=forms.dno.strip(), + doctor_nsnum_info_result = ( + await Serveries.get_order_info_list_by_visit_uopenid_detailt( + db_session, + visit_uopenid=forms.visit_uopenid.strip(), + orderid=forms.orderid.strip(), + dno=forms.dno.strip(), + ) ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=doctor_nsnum_info_result, message='查询成功') if doctor_nsnum_info_result else Fail( - api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=doctor_nsnum_info_result, message="查询成功") + if doctor_nsnum_info_result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter14/booking_system/apis/userorders/api/user_order_list.py b/chapter14/booking_system/apis/userorders/api/user_order_list.py index fd87bf8..d4a574b 100644 --- a/chapter14/booking_system/apis/userorders/api/user_order_list.py +++ b/chapter14/booking_system/apis/userorders/api/user_order_list.py @@ -6,10 +6,20 @@ from ..schemas import UserOrderIonfoListForm from ..repository import Serveries -@router_userorders.post("/user_order_list", summary='用户自己订单列表') -async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): + +@router_userorders.post("/user_order_list", summary="用户自己订单列表") +async def callbadk( + forms: UserOrderIonfoListForm, + db_session: AsyncSession = Depends(depends_get_db_session), +): # 检测用户的有消息 # 判断当前用户是否已经被拉黑啦,禁用了! - result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) + result = await Serveries.get_order_info_list_by_visit_uopenid_select( + db_session, visit_uopenid=forms.visit_uopenid, statue=forms.statue + ) # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 - return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') + return ( + Success(api_code=200, result=result, message="查询成功") + if result + else Fail(api_code=200, result=None, message="无此订单状态列表信息!") + ) diff --git a/chapter14/booking_system/apis/userorders/api/wxauth_login.py b/chapter14/booking_system/apis/userorders/api/wxauth_login.py index fda5814..e7e2ca3 100644 --- a/chapter14/booking_system/apis/userorders/api/wxauth_login.py +++ b/chapter14/booking_system/apis/userorders/api/wxauth_login.py @@ -3,42 +3,58 @@ from ..api import router_userorders from ..schemas import WxCodeForm from config.config import get_settings -from exts.wechatpy import WeChatClient, WeChatOAuth, WeChatOAuthException, WeChatException +from exts.wechatpy import ( + WeChatClient, + WeChatOAuth, + WeChatOAuthException, + WeChatException, +) def getWeChatOAuth(redirect_url): - return WeChatOAuth(get_settings().GZX_ID, get_settings().GZX_SECRET, redirect_url, 'snsapi_userinfo') + return WeChatOAuth( + get_settings().GZX_ID, + get_settings().GZX_SECRET, + redirect_url, + "snsapi_userinfo", + ) -@router_userorders.get("/login", summary='微信授权登入') +@router_userorders.get("/login", summary="微信授权登入") async def callbadk(*, forms: WxCodeForm = Depends(WxCodeForm)): wechat_oauth = None try: CODE = forms.code.strip() - wechat_oauth = getWeChatOAuth(redirect_url='') + wechat_oauth = getWeChatOAuth(redirect_url="") # 第二步:通过code换取网页授权access_token res_openid = wechat_oauth.fetch_access_token(CODE) except WeChatOAuthException as wcpayex: if not wcpayex.errcode: pass - return Fail(api_code=200, result=None, message='授权处理失败,原因:{}'.format(str(wcpayex.errmsg))) + return Fail( + api_code=200, + result=None, + message="授权处理失败,原因:{}".format(str(wcpayex.errmsg)), + ) except Exception as ex: - return Fail(api_code=200, result=None, message='授权处理失败,原因:未知异常的错误信息') + return Fail( + api_code=200, result=None, message="授权处理失败,原因:未知异常的错误信息" + ) user_info = wechat_oauth.get_user_info() # 正常的获取到用户信息 - openid = user_info.get('openid') - avatar_url = user_info.get('headimgurl') - city = user_info.get('city') - coutry = user_info.get('country') - nick_name = user_info.get('nickname') - province = user_info.get('province') - sex = '男' if user_info.get('sex') == 1 else '女' + openid = user_info.get("openid") + avatar_url = user_info.get("headimgurl") + city = user_info.get("city") + coutry = user_info.get("country") + nick_name = user_info.get("nickname") + province = user_info.get("province") + sex = "男" if user_info.get("sex") == 1 else "女" data = { "openid": openid, "nick_name": nick_name, "avatar_url": avatar_url, - "usex": sex + "usex": sex, } - return Success(api_code=200, result=data, message='获取成功') + return Success(api_code=200, result=data, message="获取成功") diff --git a/chapter14/booking_system/apis/userorders/repository/__init__.py b/chapter14/booking_system/apis/userorders/repository/__init__.py index fcb74e6..cbd7ed0 100644 --- a/chapter14/booking_system/apis/userorders/repository/__init__.py +++ b/chapter14/booking_system/apis/userorders/repository/__init__.py @@ -7,62 +7,86 @@ from typing import Optional - - - - class Serveries: @staticmethod - async def get_order_info_byorder_dno_state(async_session: AsyncSession, dno, orderid): + async def get_order_info_byorder_dno_state( + async_session: AsyncSession, dno, orderid + ): # # 判断是否存在 # stmt = select(User).where(User.name == 'sandy').exists() - query = select(DoctorSubscribeinfo.statue, DoctorSubscribeinfo.dno, DoctorSubscribeinfo.nsindex) + query = select( + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.nsindex, + ) _result = await async_session.execute( - query.where(DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid)) + query.where( + DoctorSubscribeinfo.dno == dno, DoctorSubscribeinfo.orderid == orderid + ) + ) doctor_result: Optional[DoctorSubscribeinfo] = _result.first() return doctor_result @staticmethod - async def updata_order_info_byorder_dno_olny(async_session: AsyncSession, dno, visit_uopenid, orderid, **updata): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny( + async_session: AsyncSession, dno, visit_uopenid, orderid, **updata + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(updata)) await async_session.commit() return result.rowcount @staticmethod - async def updata_order_info_byorder_dno_olny_dict(async_session: AsyncSession, dno, visit_uopenid, orderid, - updata={}): - response = update(DoctorSubscribeinfo).where(DoctorSubscribeinfo.dno == dno, - DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid) + async def updata_order_info_byorder_dno_olny_dict( + async_session: AsyncSession, dno, visit_uopenid, orderid, updata={} + ): + response = update(DoctorSubscribeinfo).where( + DoctorSubscribeinfo.dno == dno, + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + ) result = await async_session.execute(response.values(**updata)) await async_session.commit() return result.rowcount @staticmethod - async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSession, visit_uopenid, statue=1) -> list: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.dnname, - Doctorinfo.addr, - Doctorinfo.rank, - Doctorinfo.pic - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.statue == statue, - ) - - _subscribe_info_result:AsyncResult = await async_session.execute(query_subscribe_info) + async def get_order_info_list_by_visit_uopenid_select( + async_session: AsyncSession, visit_uopenid, statue=1 + ) -> list: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.dnname, + Doctorinfo.addr, + Doctorinfo.rank, + Doctorinfo.pic, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.statue == statue, + ) + ) + + _subscribe_info_result: AsyncResult = await async_session.execute( + query_subscribe_info + ) _rows = _subscribe_info_result.mappings() return [_row for _row in _rows] @@ -77,35 +101,41 @@ async def get_order_info_list_by_visit_uopenid_select(async_session: AsyncSessio # _rows = _subscribe_info_result.all() # return [item._mapping for item in _rows] - - - @staticmethod - async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSession, visit_uopenid, orderid, - dno) -> dict: - query_subscribe_info = select( - DoctorSubscribeinfo.orderid, - # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) - DoctorSubscribeinfo.statue, - DoctorSubscribeinfo.dno, - DoctorSubscribeinfo.visittime, - DoctorSubscribeinfo.visitday, - DoctorSubscribeinfo.payfee, - DoctorSubscribeinfo.visit_statue, - Doctorinfo.addr, - Doctorinfo.dnname, - Doctorinfo.rank, - Doctorinfo.pic, - DoctorSubscribeinfo.create_time, - DoctorSubscribeinfo.visit_uname, - DoctorSubscribeinfo.visit_uphone, - DoctorSubscribeinfo.visit_usex, - DoctorSubscribeinfo.visit_uage, - ).outerjoin_from(DoctorSubscribeinfo, Doctorinfo, DoctorSubscribeinfo.dno == Doctorinfo.dno) \ - .filter(DoctorSubscribeinfo.visit_uopenid == visit_uopenid, - DoctorSubscribeinfo.orderid == orderid, - DoctorSubscribeinfo.dno == dno - ) + async def get_order_info_list_by_visit_uopenid_detailt( + async_session: AsyncSession, visit_uopenid, orderid, dno + ) -> dict: + query_subscribe_info = ( + select( + DoctorSubscribeinfo.orderid, + # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时自动取消) + DoctorSubscribeinfo.statue, + DoctorSubscribeinfo.dno, + DoctorSubscribeinfo.visittime, + DoctorSubscribeinfo.visitday, + DoctorSubscribeinfo.payfee, + DoctorSubscribeinfo.visit_statue, + Doctorinfo.addr, + Doctorinfo.dnname, + Doctorinfo.rank, + Doctorinfo.pic, + DoctorSubscribeinfo.create_time, + DoctorSubscribeinfo.visit_uname, + DoctorSubscribeinfo.visit_uphone, + DoctorSubscribeinfo.visit_usex, + DoctorSubscribeinfo.visit_uage, + ) + .outerjoin_from( + DoctorSubscribeinfo, + Doctorinfo, + DoctorSubscribeinfo.dno == Doctorinfo.dno, + ) + .filter( + DoctorSubscribeinfo.visit_uopenid == visit_uopenid, + DoctorSubscribeinfo.orderid == orderid, + DoctorSubscribeinfo.dno == dno, + ) + ) _subscribe_info_result = await async_session.execute(query_subscribe_info) _row = _subscribe_info_result.first() return {} if not _row else _row._mapping @@ -129,14 +159,15 @@ async def get_order_info_list_by_visit_uopenid_detailt(async_session: AsyncSessi # } -if __name__ == '__main__': +if __name__ == "__main__": + async def sdsdf(): async with async_context_get_db() as session: - asdas = await Serveries.get_order_info_list_by_visit_uopenid_select(session, - visit_uopenid='orE7I59UwXdWzfSK9QGK2fHGtPZ8') + asdas = await Serveries.get_order_info_list_by_visit_uopenid_select( + session, visit_uopenid="orE7I59UwXdWzfSK9QGK2fHGtPZ8" + ) print(asdas) - # asyncio.run(sdsdf()) loop = asyncio.get_event_loop() loop.run_until_complete(sdsdf()) diff --git a/chapter14/booking_system/apis/userorders/schemas/__init__.py b/chapter14/booking_system/apis/userorders/schemas/__init__.py index ad3861b..fb1607c 100644 --- a/chapter14/booking_system/apis/userorders/schemas/__init__.py +++ b/chapter14/booking_system/apis/userorders/schemas/__init__.py @@ -1,4 +1,3 @@ - from pydantic import BaseModel from fastapi import Depends, Query from pydantic.dataclasses import dataclass @@ -6,35 +5,38 @@ class SubscribeOrderCheckForm(BaseModel): # 新增需要时段索引排班索引编号 - dno: str = Query(...,min_length=1,description="医生编号ID") + dno: str = Query(..., min_length=1, description="医生编号ID") orderid: str = Query(..., min_length=1, description="订单编号ID") visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") + class UserOrderIonfoListForm(BaseModel): - ''' + """ 下单需要相关字段信息 - ''' - visit_uopenid: str = Query(..., min_length=1,description="就诊人微信ID") + """ + + visit_uopenid: str = Query(..., min_length=1, description="就诊人微信ID") # 订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单 4:超时未支付订单 5:申请退款状态 6:已退款状态) - statue:int = None + statue: int = None class WxCodeForm(BaseModel): - code: str = Query(..., min_length=1,description="微信CODE") + code: str = Query(..., min_length=1, description="微信CODE") @dataclass class GetOrderinfos(BaseModel): - ''' + """ 连表查询出来的位置要字段要保持一致信息 - ''' + """ + orderid: str - statue:int - dno:str - visittime:str - visitday:str - visit_statue:int - dnname:str - addr:str - rank:str - pic:str + statue: int + dno: str + visittime: str + visitday: str + visit_statue: int + dnname: str + addr: str + rank: str + pic: str diff --git a/chapter14/booking_system/app.py b/chapter14/booking_system/app.py index 0536a07..de683f5 100644 --- a/chapter14/booking_system/app.py +++ b/chapter14/booking_system/app.py @@ -2,20 +2,29 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) try: - app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") + app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" + ) except: pass -@app.get('/docs', include_in_schema=False) + +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -23,8 +32,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -50,35 +61,53 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.async_rabbit import async_rabbit_client + # 启动成功的后的回调 from exts.rabbit import sync_rabbit_client + async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange1' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue1' - order_dead_letter_routing_key = 'xz-dead-letter-queue1' - await async_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) + order_dead_letter_exchange_name = "xz-dead-letter-exchange1" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue1" + order_dead_letter_routing_key = "xz-dead-letter-queue1" + await async_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_dead_letter_queue_name + ) - await async_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - routing_key=order_dead_letter_routing_key) + await async_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange1' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue1' - order_routing_key = 'order_handler1' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await async_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await async_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await async_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, routing_key=order_routing_key) + order_exchange_name = "xz-order-exchange1" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue1" + order_routing_key = "order_handler1" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await async_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await async_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await async_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, routing_key=order_routing_key + ) + -async_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) +async_rabbit_client.init_app( + app=app, rabbitconf=get_settings(), startup_callback=startup_callback_init_data +) def startup_callback_init_data_sync(): @@ -86,32 +115,45 @@ def startup_callback_init_data_sync(): # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' - sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" + sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) - sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name, - queue_name = order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) + sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name,queue_name=order_queue_name,routing_key=order_routing_key) -#try: -# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) -#except: -# pass + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) +# try: +# sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data_sync) +# except: +# pass def creat_app(): diff --git a/chapter14/booking_system/app_sync.py b/chapter14/booking_system/app_sync.py index 7b50432..4c20432 100644 --- a/chapter14/booking_system/app_sync.py +++ b/chapter14/booking_system/app_sync.py @@ -2,17 +2,25 @@ from exts.exceptions import ApiExceptionHandler import os import pathlib -from fastapi.openapi.docs import (get_redoc_html, get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, ) +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) from fastapi.staticfiles import StaticFiles from config.config import get_settings -app = FastAPI(docs_url=None, - title="XX预约挂号系统", - description="可以通过关注微信公众号,在公众号内进行预约挂号的系统") -app.mount("/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static") +app = FastAPI( + docs_url=None, + title="XX预约挂号系统", + description="可以通过关注微信公众号,在公众号内进行预约挂号的系统", +) +app.mount( + "/static", StaticFiles(directory=f"{pathlib.Path.cwd()}/static"), name="static" +) -@app.get('/docs', include_in_schema=False) +@app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): return get_swagger_ui_html( openapi_url=app.openapi_url, @@ -20,8 +28,10 @@ async def custom_swagger_ui_html(): oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, swagger_js_url="/static/swagger-ui-bundle.js", swagger_css_url="/static/swagger-ui.css", - swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png" + swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", ) + + # 注册全局异常 ApiExceptionHandler().init_app(app) @@ -29,8 +39,11 @@ async def custom_swagger_ui_html(): # app.router.route_class = ContextLogerRoute # app.add_middleware(BindContextvarMiddleware) -from middlewares.loger.middleware import LogerMiddleware -app.add_middleware(LogerMiddleware,log_pro_path=os.path.split(os.path.realpath(__file__))[0]) +from middlewares.loger.middleware import LogerMiddleware + +app.add_middleware( + LogerMiddleware, log_pro_path=os.path.split(os.path.realpath(__file__))[0] +) from apis.hospital.api import router_hospital @@ -46,34 +59,55 @@ async def custom_swagger_ui_html(): # 初始化同步连接rabbitmq from exts.rabbit import sync_rabbit_client + + # 启动成功的后的回调 async def startup_callback_init_data(): # 为测试方便每次启动都删除 # sync_rabbit_client.make_exchange_delete('xz-dead-letter-exchange') # sync_rabbit_client.make_exchange_delete('xz-order-exchange') # # 改队列管理一个死信队列的配置 - order_dead_letter_exchange_name = 'xz-dead-letter-exchange' - order_dead_letter_exchange_type = 'fanout' - order_dead_letter_queue_name = 'xz-dead-letter-queue' - order_dead_letter_routing_key = 'xz-dead-letter-queue' + order_dead_letter_exchange_name = "xz-dead-letter-exchange" + order_dead_letter_exchange_type = "fanout" + order_dead_letter_queue_name = "xz-dead-letter-queue" + order_dead_letter_routing_key = "xz-dead-letter-queue" # 创建交换机 - await sync_rabbit_client.make_exchange_declare(exchange_name=order_dead_letter_exchange_name,exchange_type=order_dead_letter_exchange_type) + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_dead_letter_exchange_name, + exchange_type=order_dead_letter_exchange_type, + ) # 设置队列 await sync_rabbit_client.make_queue_declare(queue_name=order_dead_letter_queue_name) # 绑定交换机和队列 - await sync_rabbit_client.make_queue_bind(exchange_name=order_dead_letter_exchange_name,queue_name=order_dead_letter_queue_name,routing_key=order_dead_letter_routing_key) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_dead_letter_exchange_name, + queue_name=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, + ) # # 改队列管理一个死信队列的配置 - order_exchange_name = 'xz-order-exchange' - order_exchange_type='direct' - order_queue_name = 'xz-order-queue' - order_routing_key = 'order_handler' - order_queue_arguments = {'x-dead-letter-exchange': 'xz-dead-letter-exchange'} - await sync_rabbit_client.make_exchange_declare(exchange_name=order_exchange_name, exchange_type=order_exchange_type) - await sync_rabbit_client.make_queue_declare(queue_name=order_queue_name,arguments=order_queue_arguments) - await sync_rabbit_client.make_queue_bind(exchange_name=order_exchange_name, queue_name=order_queue_name, routing_key=order_routing_key) - -sync_rabbit_client.init_app(app=app,rabbitconf=get_settings(),startup_callback=startup_callback_init_data) + order_exchange_name = "xz-order-exchange" + order_exchange_type = "direct" + order_queue_name = "xz-order-queue" + order_routing_key = "order_handler" + order_queue_arguments = {"x-dead-letter-exchange": "xz-dead-letter-exchange"} + await sync_rabbit_client.make_exchange_declare( + exchange_name=order_exchange_name, exchange_type=order_exchange_type + ) + await sync_rabbit_client.make_queue_declare( + queue_name=order_queue_name, arguments=order_queue_arguments + ) + await sync_rabbit_client.make_queue_bind( + exchange_name=order_exchange_name, + queue_name=order_queue_name, + routing_key=order_routing_key, + ) + + +sync_rabbit_client.init_app( + app=app, rabbitconf=get_settings(), startup_callback=startup_callback_init_data +) + def creat_app(): return app diff --git a/chapter14/booking_system/config/config.py b/chapter14/booking_system/config/config.py index 511f29c..bef9399 100644 --- a/chapter14/booking_system/config/config.py +++ b/chapter14/booking_system/config/config.py @@ -1,6 +1,7 @@ from pydantic import BaseSettings from functools import lru_cache + class Settings(BaseSettings): # 连接数据库引擎 @@ -23,25 +24,27 @@ class Settings(BaseSettings): DB_POOL_SIZE: int = 60 DB_MAX_OVERFLOW: int = 0 - #公众号-开发者ID(AppID) - GZX_ID: str = 'wx91df1c5a300ddc3d' # 微信公众号ID - #公众号-开发者密码 - GZX_SECRET:str = '1f484aa3403b7c867d13a5e10c193191' - GZX_PAY_KEY: str = '0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh' # 微信支付秘钥 - MCH_ID: str = '1613748420' # 微信支付ID - NOTIFY_URL = 'http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback' #支付回调 + # 公众号-开发者ID(AppID) + GZX_ID: str = "wx91df1c5a300ddc3d" # 微信公众号ID + # 公众号-开发者密码 + GZX_SECRET: str = "1f484aa3403b7c867d13a5e10c193191" + GZX_PAY_KEY: str = "0wmDjLVuk904Ddyj0fLwpX1ymiBMIkXh" # 微信支付秘钥 + MCH_ID: str = "1613748420" # 微信支付ID + NOTIFY_URL = ( + "http://hx.wohuayuan.com/hs/api/v1/doctor/subscribe/paycallback" # 支付回调 + ) # 没有值的情况下的默认值--默认情况下读取的环境变量的值 # 链接用户名 - RABBIT_USERNAME: str = 'admin' + RABBIT_USERNAME: str = "admin" # 链接密码 - RABBIT_PASSWORD: str = 'admin' + RABBIT_PASSWORD: str = "admin" # 链接的主机 - RABBIT_HOST: str = 'rabbit' + RABBIT_HOST: str = "rabbit" # 链接端口 RABBIT_PORT: int = 5672 # 要链接租户空间名称 - VIRTUAL_HOST: str = 'yuyueguahao' + VIRTUAL_HOST: str = "yuyueguahao" # 心跳检测 RABBIT_HEARTBEAT = 5 diff --git a/chapter14/booking_system/db/async_database.py b/chapter14/booking_system/db/async_database.py index 0f9517b..998bd26 100644 --- a/chapter14/booking_system/db/async_database.py +++ b/chapter14/booking_system/db/async_database.py @@ -8,27 +8,39 @@ from contextlib import asynccontextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings # 创建异步引擎对象 settings = get_settings() -async_engine = create_async_engine(url=URL.create(settings.ASYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +async_engine = create_async_engine( + url=URL.create( + settings.ASYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) # 创建异步的会话管理对象 -AsyncSessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession,autocommit=False,autoflush=False, future=False) +AsyncSessionLocal = sessionmaker( + bind=async_engine, + expire_on_commit=False, + class_=AsyncSession, + autocommit=False, + autoflush=False, + future=False, +) async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: @@ -48,7 +60,7 @@ async def depends_get_db_session() -> AsyncGenerator[AsyncSession, None]: # 需要使用这个来装饰一下,才可以使用with @asynccontextmanager async def async_context_get_db() -> AsyncGenerator: - ''' + """ async def init() -> None: pass async with get_db() as session: @@ -60,7 +72,7 @@ async def init() -> None: # loop = asyncio.get_event_loop() # loop.run_until_complete(init()) :return: - ''' + """ session = AsyncSessionLocal() try: yield session diff --git a/chapter14/booking_system/db/models.py b/chapter14/booking_system/db/models.py index 4749ca8..1bf4496 100644 --- a/chapter14/booking_system/db/models.py +++ b/chapter14/booking_system/db/models.py @@ -1,76 +1,157 @@ # coding: utf-8 -from sqlalchemy import Column, Date, DateTime, Integer, SmallInteger, Text, UniqueConstraint, text,DECIMAL,Numeric +from sqlalchemy import ( + Column, + Date, + DateTime, + Integer, + SmallInteger, + Text, + UniqueConstraint, + text, + DECIMAL, + Numeric, +) from sqlalchemy.dialects.postgresql import TIMESTAMP from db.async_database import Base + metadata = Base.metadata class DoctorScheduling(Base): - __tablename__ = 'doctor_scheduling' - __table_args__ = {'comment': '医生排班信息表'} + __tablename__ = "doctor_scheduling" + __table_args__ = {"comment": "医生排班信息表"} + + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + nsnum = Column(Integer, comment="号源总数") + nsnumstock = Column(Integer, comment="号源库存数") + nsindex = Column( + Text, unique=True, server_default=text("''::text"), comment="号源编号" + ) + dnotime = Column(Date, comment="排班日期,年-月-日") + tiemampmstr = Column( + Text, server_default=text("''::text"), comment="号源时段字符串显示" + ) + ampm = Column( + Text, server_default=text("''::text"), comment="医生工作日:上午 还是 下午" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + enable = Column(Integer, comment="是否可用(1:是 0 否)") + tiempm = Column( + TIMESTAMP(precision=6), comment="医生工作日:号源时段(年-月-日 时:分)" + ) - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_scheduling_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - nsnum = Column(Integer, comment='号源总数') - nsnumstock = Column(Integer, comment='号源库存数') - nsindex = Column(Text, unique=True, server_default=text("''::text"), comment='号源编号') - dnotime = Column(Date, comment='排班日期,年-月-日') - tiemampmstr = Column(Text, server_default=text("''::text"), comment='号源时段字符串显示') - ampm = Column(Text, server_default=text("''::text"), comment='医生工作日:上午 还是 下午') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - tiempm = Column(TIMESTAMP(precision=6), comment='医生工作日:号源时段(年-月-日 时:分)') class DoctorSubscribeinfo(Base): - __tablename__ = 'doctor_subscribeinfo' - __table_args__ = {'comment': '预约信息详情表'} + __tablename__ = "doctor_subscribeinfo" + __table_args__ = {"comment": "预约信息详情表"} - id = Column(Integer, primary_key=True, server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, index=True, server_default=text("''::text"), comment='所属医生编号') - orderid = Column(Text, index=True, server_default=text("''::text"), comment='订单编号') - nsindex = Column(Text, server_default=text("''::text"), comment='订单编号') - statue = Column(Integer, server_default=text("1"), comment='订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单') - visitday = Column(Text, server_default=text("''::text"), comment='就诊日期') - visittime = Column(Text, server_default=text("''::text"), comment='就诊时段') - payfee = Column(Text, server_default=text("''::text"), comment='支付诊费') - visit_uopenid = Column(Text, server_default=text("''::text"), comment='就诊人微信ID') - visit_uname = Column(Text, server_default=text("''::text"), comment='就诊人姓名') - visit_uphone = Column(Text, server_default=text("''::text"), comment='就诊人联系电话') - visit_usex = Column(Text, server_default=text("''::text"), comment='就诊人性别') - visit_uage = Column(Text, server_default=text("''::text"), comment='就诊人年龄') - visit_statue = Column(Integer, server_default=text("1"), comment='订单所属-就诊状态(1:待就诊 2:已就诊)') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - notify_callback_time = Column(TIMESTAMP(precision=0), comment='支付回调时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctor_subscribeinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + index=True, + server_default=text("''::text"), + comment="所属医生编号", + ) + orderid = Column( + Text, index=True, server_default=text("''::text"), comment="订单编号" + ) + nsindex = Column(Text, server_default=text("''::text"), comment="订单编号") + statue = Column( + Integer, + server_default=text("1"), + comment="订单状态(1:订单就绪,还没支付 2:已支付成功 3:取消订单", + ) + visitday = Column(Text, server_default=text("''::text"), comment="就诊日期") + visittime = Column(Text, server_default=text("''::text"), comment="就诊时段") + payfee = Column(Text, server_default=text("''::text"), comment="支付诊费") + visit_uopenid = Column( + Text, server_default=text("''::text"), comment="就诊人微信ID" + ) + visit_uname = Column(Text, server_default=text("''::text"), comment="就诊人姓名") + visit_uphone = Column( + Text, server_default=text("''::text"), comment="就诊人联系电话" + ) + visit_usex = Column(Text, server_default=text("''::text"), comment="就诊人性别") + visit_uage = Column(Text, server_default=text("''::text"), comment="就诊人年龄") + visit_statue = Column( + Integer, + server_default=text("1"), + comment="订单所属-就诊状态(1:待就诊 2:已就诊)", + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + notify_callback_time = Column(TIMESTAMP(precision=0), comment="支付回调时间") class Doctorinfo(Base): - __tablename__ = 'doctorinfo' - __table_args__ = {'comment': '医生信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('doctorinfo_id_seq'::regclass)"), comment='主键Id') - dno = Column(Text, nullable=False, unique=True, server_default=text("''::text"), comment='医生编号') - dnname = Column(Text, server_default=text("''::text"), comment='医生名称') - dnmobile = Column(Text, server_default=text("''::text"), comment='医生号码') - sex = Column(Integer, comment='医生性别:1: 男 2: 女 3:保密') - enable = Column(Integer, comment='是否可用(1:是 0 否)') - rank = Column(Text, server_default=text("''::text"), comment='职称') - fee = Column(Numeric, comment='医生诊费') - grade = Column(Text, server_default=text("''::text"), comment='等级') - destag = Column(Text, server_default=text("''::text"), comment='专业擅长标签') - addr = Column(Text, server_default=text("''::text"), comment='开诊地点') - pic = Column(Text, server_default=text("''::text"), comment='医生图片') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') - describe = Column(Text, comment='说明信息') + __tablename__ = "doctorinfo" + __table_args__ = {"comment": "医生信息表"} -class Hospitalinfo(Base): - __tablename__ = 'hospitalinfo' - __table_args__ = {'comment': '医院信息表'} - - id = Column(Integer, primary_key=True, server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), comment='主键Id') - name = Column(Text, server_default=text("''::text"), comment='医院名称') - describe = Column(Text, server_default=text("''::text"), comment='医院描述') - describeimages = Column(Text, server_default=text("''::text"), comment='describeimages') - create_time = Column(TIMESTAMP(precision=0), server_default=text("now()"), comment='创建时间') + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('doctorinfo_id_seq'::regclass)"), + comment="主键Id", + ) + dno = Column( + Text, + nullable=False, + unique=True, + server_default=text("''::text"), + comment="医生编号", + ) + dnname = Column(Text, server_default=text("''::text"), comment="医生名称") + dnmobile = Column(Text, server_default=text("''::text"), comment="医生号码") + sex = Column(Integer, comment="医生性别:1: 男 2: 女 3:保密") + enable = Column(Integer, comment="是否可用(1:是 0 否)") + rank = Column(Text, server_default=text("''::text"), comment="职称") + fee = Column(Numeric, comment="医生诊费") + grade = Column(Text, server_default=text("''::text"), comment="等级") + destag = Column(Text, server_default=text("''::text"), comment="专业擅长标签") + addr = Column(Text, server_default=text("''::text"), comment="开诊地点") + pic = Column(Text, server_default=text("''::text"), comment="医生图片") + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) + describe = Column(Text, comment="说明信息") +class Hospitalinfo(Base): + __tablename__ = "hospitalinfo" + __table_args__ = {"comment": "医院信息表"} + id = Column( + Integer, + primary_key=True, + server_default=text("nextval('hospitalinfo_id_seq'::regclass)"), + comment="主键Id", + ) + name = Column(Text, server_default=text("''::text"), comment="医院名称") + describe = Column(Text, server_default=text("''::text"), comment="医院描述") + describeimages = Column( + Text, server_default=text("''::text"), comment="describeimages" + ) + create_time = Column( + TIMESTAMP(precision=0), server_default=text("now()"), comment="创建时间" + ) diff --git a/chapter14/booking_system/db/sync_database.py b/chapter14/booking_system/db/sync_database.py index 8e30c82..072840d 100644 --- a/chapter14/booking_system/db/sync_database.py +++ b/chapter14/booking_system/db/sync_database.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from sqlalchemy import MetaData from sqlalchemy.engine.url import URL + # URL地址格式 from config.config import get_settings from sqlalchemy import create_engine @@ -14,20 +15,29 @@ metadata = MetaData() # 创建ORM模型基类 Base = declarative_base(metadata=metadata) -sync_engine = create_engine(url=URL.create(settings.SYNC_DB_DRIVER, - settings.DB_USER, - settings.DB_PASSWORD, - settings.DB_HOST, - settings.DB_PORT, - settings.DB_DATABASE), - echo=settings.DB_ECHO, - pool_size=settings.DB_POOL_SIZE, - max_overflow=settings.DB_MAX_OVERFLOW, - future=True) +sync_engine = create_engine( + url=URL.create( + settings.SYNC_DB_DRIVER, + settings.DB_USER, + settings.DB_PASSWORD, + settings.DB_HOST, + settings.DB_PORT, + settings.DB_DATABASE, + ), + echo=settings.DB_ECHO, + pool_size=settings.DB_POOL_SIZE, + max_overflow=settings.DB_MAX_OVERFLOW, + future=True, +) # 创建异步的会话管理对象 -SyncSessionLocal = sessionmaker(bind=sync_engine, expire_on_commit=False, autocommit=False, autoflush=False, - future=False) +SyncSessionLocal = sessionmaker( + bind=sync_engine, + expire_on_commit=False, + autocommit=False, + autoflush=False, + future=False, +) def depends_get_db_session(): @@ -56,20 +66,32 @@ def sync_context_get_db(): session.close() -if __name__ == '__main__': - from db.models import Hospitalinfo,DoctorSubscribeinfo +if __name__ == "__main__": + from db.models import Hospitalinfo, DoctorSubscribeinfo from sqlalchemy.sql import and_ with sync_context_get_db() as session: - ed_user = Hospitalinfo(name='ed', describe='Ed Jones', describeimages='edsnickname') + ed_user = Hospitalinfo( + name="ed", describe="Ed Jones", describeimages="edsnickname" + ) session.add(ed_user) - _result:DoctorSubscribeinfo = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).one_or_none() + _result: DoctorSubscribeinfo = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ) + .one_or_none() + ) print(_result.dno) - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == '10001', - DoctorSubscribeinfo.visit_uopenid == 'orE7I59UwXdWzfSK9QGK2fHGtPZ8', - DoctorSubscribeinfo.orderid == '2207121523229771546')).update( - {DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) \ No newline at end of file + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == "10001", + DoctorSubscribeinfo.visit_uopenid == "orE7I59UwXdWzfSK9QGK2fHGtPZ8", + DoctorSubscribeinfo.orderid == "2207121523229771546", + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) diff --git a/chapter14/booking_system/exts/async_rabbit/__init__.py b/chapter14/booking_system/exts/async_rabbit/__init__.py index bd0a144..46598c3 100644 --- a/chapter14/booking_system/exts/async_rabbit/__init__.py +++ b/chapter14/booking_system/exts/async_rabbit/__init__.py @@ -32,35 +32,56 @@ async def shutdown_event(): await self._clear_all() async def init_sync_rabbit(self, rabbitconf): - self.connection = await aio_pika.connect_robust(host=rabbitconf.RABBIT_HOST, - port=rabbitconf.RABBIT_PORT, - virtualhost=rabbitconf.VIRTUAL_HOST, - login=rabbitconf.RABBIT_USERNAME, - loop=asyncio.get_event_loop(), - password=rabbitconf.RABBIT_PASSWORD - ) + self.connection = await aio_pika.connect_robust( + host=rabbitconf.RABBIT_HOST, + port=rabbitconf.RABBIT_PORT, + virtualhost=rabbitconf.VIRTUAL_HOST, + login=rabbitconf.RABBIT_USERNAME, + loop=asyncio.get_event_loop(), + password=rabbitconf.RABBIT_PASSWORD, + ) # channel_number: int = None, # publisher_confirms: bool = True, # on_return_raises: bool = False, - self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel(publisher_confirms=False) - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' + self.channel: aio_pika.abc.AbstractChannel = await self.connection.channel( + publisher_confirms=False + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" # if auto_delete and durable is None: # durable = False - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,auto_delete=False,durable=durable) - - - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - self.queue = await self.channel.declare_queue(name=queue_name, durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, auto_delete=False, durable=durable + ) + + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" await self.queue.bind(exchange=exchange_name, routing_key=routing_key) - - async def send_basic_publish(self, routing_key, body, content_type="text/plain", content_encoding='utf-8', - message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 try: @@ -71,20 +92,17 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", expiration=message_ttl * 1000, content_type=content_type, content_encoding=content_encoding, - delivery_mode=delivery_mode + delivery_mode=delivery_mode, ), routing_key=routing_key, ) else: await self.exchange.publish( - Message( - bytes(body, "utf-8"), - delivery_mode=delivery_mode - ), + Message(bytes(body, "utf-8"), delivery_mode=delivery_mode), routing_key=routing_key, ) except UnroutableError: - print('消息发送失败') + print("消息发送失败") async def _close_connect(self): """ @@ -100,13 +118,13 @@ async def _close_channel(self): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") await self.channel.close() async def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" await self._close_connect() self.connection = None diff --git a/chapter14/booking_system/exts/exceptions/__init__.py b/chapter14/booking_system/exts/exceptions/__init__.py index 57d9d64..ecbfd6c 100644 --- a/chapter14/booking_system/exts/exceptions/__init__.py +++ b/chapter14/booking_system/exts/exceptions/__init__.py @@ -14,9 +14,15 @@ from fastapi import FastAPI, Request from starlette.exceptions import HTTPException as StarletteHTTPException from fastapi.exceptions import RequestValidationError -from exts.responses.json_response import InternalErrorException, \ - MethodnotallowedException, \ - NotfoundException, LimiterResException, BadrequestException, ParameterException, Businesserror +from exts.responses.json_response import ( + InternalErrorException, + MethodnotallowedException, + NotfoundException, + LimiterResException, + BadrequestException, + ParameterException, + Businesserror, +) from enum import Enum @@ -32,9 +38,14 @@ class ExceptionEnum(Enum): class BusinessError(Exception): - __slots__ = ['err_code', 'err_code_des'] + __slots__ = ["err_code", "err_code_des"] - def __init__(self, result: ExceptionEnum = None, err_code: str = "0000", err_code_des: str = ""): + def __init__( + self, + result: ExceptionEnum = None, + err_code: str = "0000", + err_code_des: str = "", + ): if result: self.err_code = result.value[0] self.err_code_des = err_code_des or result.value[1] @@ -52,24 +63,36 @@ def __init__(self, app=None, *args, **kwargs): def init_app(self, app: FastAPI): app.add_exception_handler(Exception, handler=self.all_exception_handler) - app.add_exception_handler(StarletteHTTPException, handler=self.http_exception_handler) + app.add_exception_handler( + StarletteHTTPException, handler=self.http_exception_handler + ) app.add_exception_handler(BusinessError, handler=self.all_businesserror_handler) - app.add_exception_handler(RequestValidationError, handler=self.validation_exception_handler) + app.add_exception_handler( + RequestValidationError, handler=self.validation_exception_handler + ) - async def validation_exception_handler(self, request: Request, exc: RequestValidationError): - return ParameterException(http_status_code=400, api_code=400, message='参数校验错误', result={ - "detail": exc.errors(), - "body": exc.body - }) + async def validation_exception_handler( + self, request: Request, exc: RequestValidationError + ): + return ParameterException( + http_status_code=400, + api_code=400, + message="参数校验错误", + result={"detail": exc.errors(), "body": exc.body}, + ) async def all_businesserror_handler(self, request: Request, exc: BusinessError): - return Businesserror(http_status_code=200, api_code=exc.err_code, message=exc.err_code_des) + return Businesserror( + http_status_code=200, api_code=exc.err_code, message=exc.err_code_des + ) async def all_exception_handler(self, request: Request, exc: Exception): return InternalErrorException() - async def http_exception_handler(self, request: Request, exc: StarletteHTTPException): + async def http_exception_handler( + self, request: Request, exc: StarletteHTTPException + ): if exc.status_code == 405: return MethodnotallowedException() if exc.status_code == 404: diff --git a/chapter14/booking_system/exts/logururoute/__init__.py b/chapter14/booking_system/exts/logururoute/__init__.py index 8deed65..76eaf24 100644 --- a/chapter14/booking_system/exts/logururoute/__init__.py +++ b/chapter14/booking_system/exts/logururoute/__init__.py @@ -13,7 +13,7 @@ from time import perf_counter from fastapi.routing import APIRoute -from typing import Callable, List, Dict,Optional +from typing import Callable, List, Dict, Optional from fastapi.responses import Response import shortuuid from datetime import datetime @@ -28,7 +28,8 @@ from fastapi.responses import StreamingResponse from exts.requestvar import request -__all__ = ("setup_ext_loguru", "ContextLogerRoute") +__all__ = ("setup_ext_loguru", "ContextLogerRoute") + class ContextLogerRoute(APIRoute): # 再静态的里面使用self来查询也可以,遵循从内到外的查询 @@ -41,11 +42,15 @@ class ContextLogerRoute(APIRoute): def filter_request_url(self): path_info = request.url.path # 过滤不需要记录日志请求地址URL - return path_info not in ['/favicon.ico'] and 'websocket' not in path_info and request.method != 'OPTIONS' + return ( + path_info not in ["/favicon.ico"] + and "websocket" not in path_info + and request.method != "OPTIONS" + ) - def filter_response_context(self,response: Response): + def filter_response_context(self, response: Response): # 过滤不需要记录日志响应体内容信息L - return 'image' not in response.media_type and hasattr(request.state, 'traceid') + return "image" not in response.media_type and hasattr(request.state, "traceid") async def make_request_start_time(self): pass @@ -55,7 +60,7 @@ async def make_request_start_time(self): # 计算时间 request.state.start_time = perf_counter() - async def make_request_log_msg(self)->Dict: + async def make_request_log_msg(self) -> Dict: log_msg = None if self.filter_request_url(): ip, method, url = request.client.host, request.method, request.url.path @@ -69,14 +74,14 @@ async def make_request_log_msg(self)->Dict: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass # 在这里记录下当前提交的body的数据,用于下文的提取 @@ -96,59 +101,75 @@ async def make_request_log_msg(self)->Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - async def before_request_record_loger(self,log_msg=None): + async def before_request_record_loger(self, log_msg=None): if self.filter_request_url() and log_msg: - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) - async def after_request_record_loger(self, response: Response): + async def after_request_record_loger(self, response: Response): if self.filter_response_context(response=response): - start_time = getattr(request.state, 'start_time') - end_time = f'{(perf_counter() - start_time):.2f}' + start_time = getattr(request.state, "start_time") + end_time = f"{(perf_counter() - start_time):.2f}" # 获取响应报文信息内容 rsp = None if not isinstance(response, StreamingResponse): if isinstance(response, Response): - rsp = str(response.body, encoding='utf-8') + rsp = str(response.body, encoding="utf-8") try: rsp = json_helper.json_to_dict(rsp) except: @@ -156,12 +177,12 @@ async def after_request_record_loger(self, response: Response): log_msg = { # 记录请求耗时 "status_code": response.status_code, - 'cost_time': end_time, + "cost_time": end_time, # 记录请求响应的最终报文信息--eval的作用是去除相关的 转义符号 "\"ok\""===》ok - 'rsp': rsp, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "rsp": rsp, + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - await async_trace_add_log_record(event_type='response', msg=log_msg) + await async_trace_add_log_record(event_type="response", msg=log_msg) async def teardown_requestcontext(self, request: Request, response: Response): pass @@ -192,44 +213,44 @@ async def custom_route_handler(request: Request) -> Response: return custom_route_handler - - - -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str( - getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - - - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) diff --git a/chapter14/booking_system/exts/logururoute/config.py b/chapter14/booking_system/exts/logururoute/config.py index 809ad95..b3aa37f 100644 --- a/chapter14/booking_system/exts/logururoute/config.py +++ b/chapter14/booking_system/exts/logururoute/config.py @@ -4,10 +4,10 @@ def setup_ext_loguru(app: FastAPI, log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ @app.on_event("startup") async def startup(): @@ -16,33 +16,52 @@ async def startup(): def init_loguru_handlers(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: # BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | process_id:{process.id} process_name:{process.name} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # enqueue=True表示 开启异步写入 # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 - logger.add(log_file_path, format=format2, rotation='00:00', compression="zip", encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file \ No newline at end of file + logger.add( + log_file_path, + format=format2, + rotation="00:00", + compression="zip", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file diff --git a/chapter14/booking_system/exts/rabbit/__init__.py b/chapter14/booking_system/exts/rabbit/__init__.py index 7b5a3c9..4adb1c4 100644 --- a/chapter14/booking_system/exts/rabbit/__init__.py +++ b/chapter14/booking_system/exts/rabbit/__init__.py @@ -30,48 +30,81 @@ def shutdown_event(): self._clear_all() def init_sync_rabbit(self, rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() - @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - - self.channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type, durable=durable) + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + + self.channel.exchange_declare( + exchange=exchange_name, exchange_type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - '''创建队列''' + def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + """创建队列""" pass - self.channel.queue_declare(queue=queue_name, durable=durable, auto_delete=auto_delete, arguments=arguments) + self.channel.queue_declare( + queue=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + ) def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' + """同伙routing_key把交换机和队列的绑定""" pass - self.channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) + self.channel.queue_bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='', - content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -100,10 +133,11 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha message_id = str(uuid.uuid4()) if is_delay: - properties = pika.BasicProperties(content_type=content_type, - content_encoding=content_encoding, - delivery_mode=delivery_mode, - ) + properties = pika.BasicProperties( + content_type=content_type, + content_encoding=content_encoding, + delivery_mode=delivery_mode, + ) # expiration 字段以毫秒为单位表示 TTL 值,6 秒的 message properties.expiration = f"{message_ttl * 1000}" # 秒 self.channel.basic_publish( @@ -114,7 +148,7 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 发送的消息的内容 body=body, # 发现的消息的类型 - properties=properties + properties=properties, # pika.BasicProperties中的delivery_mode=2指明message为持久的,1 的话 表示不是持久化 2:表示持久化 ) else: @@ -124,13 +158,13 @@ def send_basic_publish(self, routing_key, body, content_type="text/plain", excha # 默认的匹配的key routing_key=routing_key, # 发送的消息的内容 - body=body + body=body, ) else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -150,13 +184,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None diff --git a/chapter14/booking_system/exts/rabbit2/__init__.py b/chapter14/booking_system/exts/rabbit2/__init__.py index a6bc476..907dc3d 100644 --- a/chapter14/booking_system/exts/rabbit2/__init__.py +++ b/chapter14/booking_system/exts/rabbit2/__init__.py @@ -17,63 +17,95 @@ def __init__(self, app: FastAPI = None): if app is not None: self.init_app(app, None, None) - def init_app(self, app: FastAPI,rabbitconf,startup_callback): + def init_app(self, app: FastAPI, rabbitconf, startup_callback): self.app = app + @app.on_event("startup") def startup_event(): self.init_sync_rabbit(rabbitconf) # 初始化回调 startup_callback() + @app.on_event("shutdown") def shutdown_event(): self._clear_all() - - def init_sync_rabbit(self,rabbitconf): - credentials = pika.PlainCredentials(rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD) + def init_sync_rabbit(self, rabbitconf): + credentials = pika.PlainCredentials( + rabbitconf.RABBIT_USERNAME, rabbitconf.RABBIT_PASSWORD + ) # 关闭心跳检测 # virtual_host 类型多租户情况环境隔离的分区,默认使用'/' - parameters = pika.ConnectionParameters(rabbitconf.RABBIT_HOST, rabbitconf.RABBIT_PORT, rabbitconf.VIRTUAL_HOST, - credentials, heartbeat=0) + parameters = pika.ConnectionParameters( + rabbitconf.RABBIT_HOST, + rabbitconf.RABBIT_PORT, + rabbitconf.VIRTUAL_HOST, + credentials, + heartbeat=0, + ) self.connection = pika.BlockingConnection(parameters) self.channel = self.connection.channel() @property def _check_alive(self): - """ 检查连接与信道是否存活 """ - return self.connection and self.connection.is_open and self.channel and self.channel.is_open - - async def make_exchange_declare(self, exchange_name, exchange_type='fanout', durable=True): - '''创建交换机''' - - self.exchange = await self.channel.declare_exchange(name=exchange_name, type=exchange_type,durable=durable) - + """检查连接与信道是否存活""" + return ( + self.connection + and self.connection.is_open + and self.channel + and self.channel.is_open + ) + + async def make_exchange_declare( + self, exchange_name, exchange_type="fanout", durable=True + ): + """创建交换机""" + + self.exchange = await self.channel.declare_exchange( + name=exchange_name, type=exchange_type, durable=durable + ) def open_confirm_delivery(self): - '''开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹''' + """开启消息发送到交换机过程监听回调机制,开启后可以在发送消息的时候进行异常的吹""" self.channel.confirm_delivery() - async def make_queue_declare(self, queue_name, durable=True, auto_delete=False, arguments=None): - - - self.queue = await self.channel.declare_queue(name=queue_name,durable=durable, auto_delete=auto_delete,arguments=arguments, exclusive=True) + async def make_queue_declare( + self, queue_name, durable=True, auto_delete=False, arguments=None + ): + self.queue = await self.channel.declare_queue( + name=queue_name, + durable=durable, + auto_delete=auto_delete, + arguments=arguments, + exclusive=True, + ) async def make_queue_bind(self, exchange_name, queue_name, routing_key): - '''同伙routing_key把交换机和队列的绑定''' - await self.queue.bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) - - + """同伙routing_key把交换机和队列的绑定""" + await self.queue.bind( + exchange=exchange_name, queue=queue_name, routing_key=routing_key + ) def make_queue_delete(self, queue): """删除队列""" self.channel.queue_delete(queue) - print('delete queue:', queue) + print("delete queue:", queue) def make_exchange_delete(self, exchange_name): self.channel.exchange_delete(exchange_name) - async def send_basic_publish(self, routing_key, body, content_type="text/plain", exchange_name='',content_encoding='utf-8', message_ttl=3, delivery_mode=2, is_delay=False): + async def send_basic_publish( + self, + routing_key, + body, + content_type="text/plain", + exchange_name="", + content_encoding="utf-8", + message_ttl=3, + delivery_mode=2, + is_delay=False, + ): """生产数据""" # 使用简单的所发的方式来避免多线程的不安全引发的问题 @@ -88,14 +120,14 @@ async def send_basic_publish(self, routing_key, body, content_type="text/plain", # mandatory: bool = True, # immediate: bool = False, # timeout: TimeoutType = None - await self.exchange.publish(message, routing_key=routing_key) + await self.exchange.publish(message, routing_key=routing_key) else: - pass + pass else: - print('连接已断开') + print("连接已断开") # self.init_sync_rabbit() except UnroutableError: - print('消息发送失败') + print("消息发送失败") def listen_basic_consume(self, queue, func): """启动循环监听用于数据消费""" @@ -115,13 +147,13 @@ def _close_channel(self, channel): :param channel: :return: """ - if not hasattr(self, 'channel'): + if not hasattr(self, "channel"): raise ValueError("the object of SenderClient has not attr of channel.") self.channel.close() def _clear_all(self): - """ 清理连接与信道 """ + """清理连接与信道""" if self.connection and self.connection.is_open: self.connection.close() self.connection = None @@ -131,4 +163,4 @@ def _clear_all(self): self.channel = None -sync_rabbit_client = RabbitMQClintWithLock() \ No newline at end of file +sync_rabbit_client = RabbitMQClintWithLock() diff --git a/chapter14/booking_system/exts/requestvar/__init__.py b/chapter14/booking_system/exts/requestvar/__init__.py index 2f50ac3..c786445 100644 --- a/chapter14/booking_system/exts/requestvar/__init__.py +++ b/chapter14/booking_system/exts/requestvar/__init__.py @@ -3,12 +3,13 @@ import shortuuid from exts.requestvar.bing import bind_contextvar from starlette.types import ASGIApp, Receive, Scope, Send + request_var: ContextVar[Request] = ContextVar("request") request: Request = bind_contextvar(request_var) + class BindContextvarMiddleware: - def __init__( - self, app: ASGIApp) -> None: + def __init__(self, app: ASGIApp) -> None: self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: diff --git a/chapter14/booking_system/exts/responses/__init__.py b/chapter14/booking_system/exts/responses/__init__.py index f1c6644..1b80a76 100644 --- a/chapter14/booking_system/exts/responses/__init__.py +++ b/chapter14/booking_system/exts/responses/__init__.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/9/23 ------------------------------------------------- - 修改描述-2021/9/23: + 修改描述-2021/9/23: ------------------------------------------------- """ from . import json_response diff --git a/chapter14/booking_system/exts/responses/json_response.py b/chapter14/booking_system/exts/responses/json_response.py index 0a59c3e..5abd98f 100644 --- a/chapter14/booking_system/exts/responses/json_response.py +++ b/chapter14/booking_system/exts/responses/json_response.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/7/15 ------------------------------------------------- - 修改描述-2021/7/15: + 修改描述-2021/7/15: ------------------------------------------------- """ @@ -23,26 +23,30 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) elif isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") elif isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") elif isinstance(obj, datetime.time): return obj.isoformat() elif isinstance(obj, decimal.Decimal): return float(obj) elif isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") elif isinstance(obj.__class__, DeclarativeMeta): # 如果是查询返回所有的那种models类型的,需要处理些 # 将SqlAlchemy结果序列化为JSON--查询全部的时候的处理返回 - return self.default({i.name: getattr(obj, i.name) for i in obj.__table__.columns}) + return self.default( + {i.name: getattr(obj, i.name) for i in obj.__table__.columns} + ) elif isinstance(obj, dict): for k in obj: try: - if isinstance(obj[k], (datetime.datetime, datetime.date, DeclarativeMeta)): + if isinstance( + obj[k], (datetime.datetime, datetime.date, DeclarativeMeta) + ): obj[k] = self.default(obj[k]) else: obj[k] = obj[k] @@ -59,11 +63,19 @@ class ApiResponse(JSONResponse): api_code = 0 # 默认Node.如果是必选的,去掉默认值即可 result: Optional[Dict[str, Any]] = None # 结果可以是{} 或 [] - message = '成功' + message = "成功" success = True timestamp = int(time.time() * 1000) - def __init__(self, success=None, http_status_code=None, api_code=None, result=None, message=None, **options): + def __init__( + self, + success=None, + http_status_code=None, + api_code=None, + result=None, + message=None, + **options + ): self.message = message or self.message self.api_code = api_code or self.api_code self.success = success or self.success @@ -76,9 +88,11 @@ def __init__(self, success=None, http_status_code=None, api_code=None, result=No code=self.api_code, success=self.success, result=self.result, - timestamp=self.timestamp + timestamp=self.timestamp, + ) + super(ApiResponse, self).__init__( + status_code=self.http_status_code, content=body, **options ) - super(ApiResponse, self).__init__(status_code=self.http_status_code, content=body, **options) # 这个render会自动调用,如果这里需要特殊的处理的话,可以重写这个地方 def render(self, content: typing.Any) -> bytes: @@ -88,7 +102,7 @@ def render(self, content: typing.Any) -> bytes: allow_nan=False, indent=None, separators=(",", ":"), - cls=CJsonEncoder + cls=CJsonEncoder, ).encode("utf-8") @@ -96,7 +110,7 @@ class BadrequestException(ApiResponse): http_status_code = 400 api_code = 10031 result = None # 结果可以是{} 或 [] - message = '错误的请求' + message = "错误的请求" success = False @@ -104,14 +118,14 @@ class LimiterResException(ApiResponse): http_status_code = 429 api_code = 429 result = None # 结果可以是{} 或 [] - message = '访问的速度过快' + message = "访问的速度过快" success = False class ParameterException(ApiResponse): http_status_code = 400 result = {} - message = '参数校验错误,请检查提交的参数信息' + message = "参数校验错误,请检查提交的参数信息" api_code = 10031 success = False @@ -119,7 +133,7 @@ class ParameterException(ApiResponse): class UnauthorizedException(ApiResponse): http_status_code = 401 result = {} - message = '未经许可授权' + message = "未经许可授权" api_code = 10032 success = False @@ -127,7 +141,7 @@ class UnauthorizedException(ApiResponse): class ForbiddenException(ApiResponse): http_status_code = 403 result = {} - message = '失败!当前访问没有权限,或操作的数据没权限!' + message = "失败!当前访问没有权限,或操作的数据没权限!" api_code = 10033 success = False @@ -135,7 +149,7 @@ class ForbiddenException(ApiResponse): class NotfoundException(ApiResponse): http_status_code = 404 result = {} - message = '访问地址不存在' + message = "访问地址不存在" api_code = 10034 success = False @@ -143,7 +157,7 @@ class NotfoundException(ApiResponse): class MethodnotallowedException(ApiResponse): http_status_code = 405 result = {} - message = '不允许使用此方法提交访问' + message = "不允许使用此方法提交访问" api_code = 10034 success = False @@ -151,7 +165,7 @@ class MethodnotallowedException(ApiResponse): class OtherException(ApiResponse): http_status_code = 800 result = {} - message = '未知的其他HTTPEOOER异常' + message = "未知的其他HTTPEOOER异常" api_code = 10034 success = False @@ -159,7 +173,7 @@ class OtherException(ApiResponse): class InternalErrorException(ApiResponse): http_status_code = 200 result = {} - message = '程序员哥哥睡眠不足,系统崩溃了!' + message = "程序员哥哥睡眠不足,系统崩溃了!" api_code = 200 success = False @@ -167,13 +181,13 @@ class InternalErrorException(ApiResponse): class InvalidTokenException(ApiResponse): http_status_code = 401 api_code = 401 - message = '很久没操作,令牌失效' + message = "很久没操作,令牌失效" success = False class ExpiredTokenException(ApiResponse): http_status_code = 422 - message = '很久没操作,令牌过期' + message = "很久没操作,令牌过期" api_code = 10050 success = False @@ -182,19 +196,19 @@ class FileTooLargeException(ApiResponse): http_status_code = 413 api_code = 413 result = None # 结果可以是{} 或 [] - message = '文件体积过大' + message = "文件体积过大" class FileTooManyException(ApiResponse): http_status_code = 413 - message = '文件数量过多' + message = "文件数量过多" api_code = 10120 result = None # 结果可以是{} 或 [] class FileExtensionException(ApiResponse): http_status_code = 401 - message = '文件扩展名不符合规范' + message = "文件扩展名不符合规范" api_code = 10121 result = None # 结果可以是{} 或 [] @@ -203,16 +217,15 @@ class Success(ApiResponse): http_status_code = 200 api_code = 200 result = None # 结果可以是{} 或 [] - message = '获取成功' + message = "获取成功" success = True - class Businesserror(ApiResponse): http_status_code = 200 - api_code = '0000' + api_code = "0000" result = None # 结果可以是{} 或 [] - message = '业务错误逻辑处理' + message = "业务错误逻辑处理" success = False @@ -220,5 +233,5 @@ class Fail(ApiResponse): http_status_code = 200 api_code = -1 result = None # 结果可以是{} 或 [] - message = '操作失败' + message = "操作失败" success = False diff --git a/chapter14/booking_system/exts/wechatpy/__init__.py b/chapter14/booking_system/exts/wechatpy/__init__.py index 61c0ac9..24ea439 100644 --- a/chapter14/booking_system/exts/wechatpy/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/__init__.py @@ -4,21 +4,28 @@ from exts.wechatpy.client import WeChatClient # NOQA from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA -from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA +from exts.wechatpy.exceptions import ( + WeChatClientException, + WeChatException, + WeChatOAuthException, + WeChatPayException, +) # NOQA from exts.wechatpy.oauth import WeChatOAuth # NOQA from exts.wechatpy.parser import parse_message # NOQA from exts.wechatpy.pay import WeChatPay # NOQA from exts.wechatpy.replies import create_reply # NOQA -__version__ = '1.8.2' -__author__ = 'messense' +__version__ = "1.8.2" +__author__ = "messense" # Set default logging handler to avoid "No handler found" warnings. try: # Python 2.7+ from logging import NullHandler except ImportError: + class NullHandler(logging.Handler): def emit(self, record): pass + logging.getLogger(__name__).addHandler(NullHandler()) diff --git a/chapter14/booking_system/exts/wechatpy/_compat.py b/chapter14/booking_system/exts/wechatpy/_compat.py index 2306499..87376ce 100644 --- a/chapter14/booking_system/exts/wechatpy/_compat.py +++ b/chapter14/booking_system/exts/wechatpy/_compat.py @@ -1,21 +1,24 @@ # -*- coding: utf-8 -*- """ - wechatpy._compat - ~~~~~~~~~~~~~~~~~ +wechatpy._compat +~~~~~~~~~~~~~~~~~ - This module makes it easy for wechatpy to run on both Python 2 and 3. +This module makes it easy for wechatpy to run on both Python 2 and 3. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import sys import six import warnings -warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" - "use `wechatpy.utils` instead", - DeprecationWarning, stacklevel=2) +warnings.warn( + "Module `wechatpy._compat` is deprecated, will be removed in 2.0" + "use `wechatpy.utils` instead", + DeprecationWarning, + stacklevel=2, +) from exts.wechatpy.utils import get_querystring from exts.wechatpy.utils import json diff --git a/chapter14/booking_system/exts/wechatpy/client/__init__.py b/chapter14/booking_system/exts/wechatpy/client/__init__.py index 18040c0..bcb4f00 100644 --- a/chapter14/booking_system/exts/wechatpy/client/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/client/__init__.py @@ -8,13 +8,12 @@ class WeChatClient(BaseWeChatClient): - """ 微信 API 操作类 通过这个类可以操作微信 API,发送主动消息、群发消息和创建自定义菜单等。 """ - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin/" # API_BASE_URL = 'http://47.99.189.42:30005/cgi-bin/' card = api.WeChatCard() @@ -42,8 +41,15 @@ class WeChatClient(BaseWeChatClient): wxa = api.WeChatWxa() marketing = api.WeChatMarketing() - def __init__(self, appid, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + appid, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( appid, access_token, session, timeout, auto_retry ) @@ -58,27 +64,31 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ return self._fetch_access_token( - url='https://api.weixin.qq.com/cgi-bin/token', + url="https://api.weixin.qq.com/cgi-bin/token", params={ - 'grant_type': 'client_credential', - 'appid': self.appid, - 'secret': self.secret - } + "grant_type": "client_credential", + "appid": self.appid, + "secret": self.secret, + }, ) class WeChatComponentClient(WeChatClient): - """ 开放平台代公众号调用客户端 """ - def __init__(self, appid, component, access_token=None, - refresh_token=None, session=None, timeout=None): + def __init__( + self, + appid, + component, + access_token=None, + refresh_token=None, + session=None, + timeout=None, + ): # 未用到secret,所以这里没有 - super(WeChatComponentClient, self).__init__( - appid, '', '', session, timeout - ) + super(WeChatComponentClient, self).__init__(appid, "", "", session, timeout) self.appid = appid self.component = component # 如果公众号是刚授权,外部还没有缓存access_token和refresh_token @@ -86,18 +96,20 @@ def __init__(self, appid, component, access_token=None, # 如果外部已经缓存,这里只需要传入 appid,component和session即可 cache_access_token = self.session.get(self.access_token_key) - if access_token and (not cache_access_token or cache_access_token != access_token): + if access_token and ( + not cache_access_token or cache_access_token != access_token + ): self.session.set(self.access_token_key, access_token, 7200) if refresh_token: self.session.set(self.refresh_token_key, refresh_token) @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) @property def refresh_token_key(self): - return '{0}_refresh_token'.format(self.appid) + return "{0}_refresh_token".format(self.appid) @property def access_token(self): @@ -123,14 +135,11 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ expires_in = 7200 - result = self.component.refresh_authorizer_token( - self.appid, self.refresh_token) - if 'expires_in' in result: - expires_in = result['expires_in'] + result = self.component.refresh_authorizer_token(self.appid, self.refresh_token) + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - self.access_token_key, - result['authorizer_access_token'], - expires_in + self.access_token_key, result["authorizer_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result diff --git a/chapter14/booking_system/exts/wechatpy/client/api/base.py b/chapter14/booking_system/exts/wechatpy/client/api/base.py index 10bbec4..66cb918 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/base.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/base.py @@ -3,21 +3,21 @@ class BaseWeChatAPI(object): - """ WeChat API base class """ + """WeChat API base class""" def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL - print("当前URL",url) + print("当前URL", url) return self._client.post(url, **kwargs) @property diff --git a/chapter14/booking_system/exts/wechatpy/client/api/card.py b/chapter14/booking_system/exts/wechatpy/client/api/card.py index 9dcb398..7b1b399 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/card.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/card.py @@ -6,7 +6,7 @@ class WeChatCard(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create(self, card_data): """ @@ -16,9 +16,7 @@ def create(self, card_data): :return: 创建的卡券 ID """ result = self._post( - 'card/create', - data=card_data, - result_processor=lambda x: x['card_id'] + "card/create", data=card_data, result_processor=lambda x: x["card_id"] ) return result @@ -30,9 +28,9 @@ def batch_add_locations(self, location_data): :return: 门店 ID 列表,插入失败的门店元素值为 -1 """ result = self._post( - 'card/location/batchadd', + "card/location/batchadd", data=location_data, - result_processor=lambda x: x['location_id_list'] + result_processor=lambda x: x["location_id_list"], ) return result @@ -41,11 +39,7 @@ def batch_get_locations(self, offset=0, count=0): 批量获取门店信息 """ return self._post( - 'card/location/batchget', - data={ - 'offset': offset, - 'count': count - } + "card/location/batchget", data={"offset": offset, "count": count} ) def get_colors(self): @@ -53,10 +47,7 @@ def get_colors(self): 获得卡券的最新颜色列表,用于创建卡券 :return: 颜色列表 """ - result = self._get( - 'card/getcolors', - result_processor=lambda x: x['colors'] - ) + result = self._get("card/getcolors", result_processor=lambda x: x["colors"]) return result def create_qrcode(self, qrcode_data): @@ -67,9 +58,9 @@ def create_qrcode(self, qrcode_data): :return: 二维码 ticket,可使用 :func:show_qrcode 换取二维码文件 """ result = self._post( - 'card/qrcode/create', + "card/qrcode/create", data=qrcode_data, - result_processor=lambda x: x['ticket'] + result_processor=lambda x: x["ticket"], ) return result @@ -77,10 +68,7 @@ def create_landingpage(self, buffer_data): """ 创建货架 """ - result = self._post( - 'card/landingpage/create', - data=buffer_data - ) + result = self._post("card/landingpage/create", data=buffer_data) return result def get_html(self, card_id): @@ -88,11 +76,9 @@ def get_html(self, card_id): 图文消息群发卡券 """ result = self._post( - 'card/mpnews/gethtml', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['content'] + "card/mpnews/gethtml", + data={"card_id": card_id}, + result_processor=lambda x: x["content"], ) return result @@ -100,26 +86,19 @@ def consume_code(self, code, card_id=None): """ 消耗 code """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/consume', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/consume", data=card_data) def decrypt_code(self, encrypt_code): """ 解码加密的 code """ result = self._post( - 'card/code/decrypt', - data={ - 'encrypt_code': encrypt_code - }, - result_processor=lambda x: x['code'] + "card/code/decrypt", + data={"encrypt_code": encrypt_code}, + result_processor=lambda x: x["code"], ) return result @@ -127,68 +106,43 @@ def delete(self, card_id): """ 删除卡券 """ - return self._post( - 'card/delete', - data={ - 'card_id': card_id - } - ) + return self._post("card/delete", data={"card_id": card_id}) def get_code(self, code, card_id=None, check_consume=True): """ 查询 code 信息 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id + card_data["card_id"] = card_id if not check_consume: - card_data['check_consume'] = check_consume - return self._post( - 'card/code/get', - data=card_data - ) + card_data["check_consume"] = check_consume + return self._post("card/code/get", data=card_data) def get_card_list(self, openid, card_id=None): """ 用于获取用户卡包里的,属于该appid下的卡券。 """ - card_data = { - 'openid': openid - } + card_data = {"openid": openid} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/order/getcardlist', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/order/getcardlist", data=card_data) def batch_get(self, offset=0, count=50, status_list=None): """ 批量查询卡券信息 """ - card_data = { - 'offset': offset, - 'count': count - } + card_data = {"offset": offset, "count": count} if status_list: - card_data['status_list'] = status_list - return self._post( - 'card/batchget', - data=card_data - ) + card_data["status_list"] = status_list + return self._post("card/batchget", data=card_data) def get(self, card_id): """ 查询卡券详情 """ result = self._post( - 'card/get', - data={ - 'card_id': card_id - }, - result_processor=lambda x: x['card'] + "card/get", data={"card_id": card_id}, result_processor=lambda x: x["card"] ) return result @@ -197,47 +151,31 @@ def update_code(self, card_id, old_code, new_code): 更新卡券 code """ return self._post( - 'card/code/update', - data={ - 'card_id': card_id, - 'code': old_code, - 'new_code': new_code - } + "card/code/update", + data={"card_id": card_id, "code": old_code, "new_code": new_code}, ) def invalid_code(self, code, card_id=None): """ 设置卡券失效 """ - card_data = { - 'code': code - } + card_data = {"code": code} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/code/unavailable', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/code/unavailable", data=card_data) def update(self, card_data): """ 更新卡券信息 """ - return self._post( - 'card/update', - data=card_data - ) + return self._post("card/update", data=card_data) def set_paycell(self, card_id, is_open): """ 更新卡券信息 """ return self._post( - 'card/paycell/set', - data={ - 'card_id': card_id, - 'is_open': is_open - } + "card/paycell/set", data={"card_id": card_id, "is_open": is_open} ) def set_test_whitelist(self, openids=None, usernames=None): @@ -247,11 +185,7 @@ def set_test_whitelist(self, openids=None, usernames=None): openids = openids or [] usernames = usernames or [] return self._post( - 'card/testwhitelist/set', - data={ - 'openid': openids, - 'username': usernames - } + "card/testwhitelist/set", data={"openid": openids, "username": usernames} ) def activate_membercard(self, membership_number, code, **kwargs): @@ -282,12 +216,9 @@ def activate_membercard(self, membership_number, code, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “6 激活会员卡” 部分 :return: 参见返回示例 """ - kwargs['membership_number'] = membership_number - kwargs['code'] = code - return self._post( - 'card/membercard/activate', - data=kwargs - ) + kwargs["membership_number"] = membership_number + kwargs["code"] = code + return self._post("card/membercard/activate", data=kwargs) def update_membercard(self, code, card_id, **kwargs): """ @@ -334,14 +265,13 @@ def update_membercard(self, code, card_id, **kwargs): :param kwargs: 其他非必填字段,包含则更新对应字段。详情参见微信文档 “7 更新会员信息” 部分 :return: 参见返回示例 """ - kwargs.update({ - 'code': code, - 'card_id': card_id, - }) - return self._post( - 'card/membercard/updateuser', - data=kwargs + kwargs.update( + { + "code": code, + "card_id": card_id, + } ) + return self._post("card/membercard/updateuser", data=kwargs) def get_membercard_user_info(self, card_id, code): """ @@ -354,10 +284,10 @@ def get_membercard_user_info(self, card_id, code): :return: 会员信息,包括激活资料、积分信息以及余额等信息 """ return self._post( - 'card/membercard/userinfo/get', + "card/membercard/userinfo/get", data={ - 'card_id': card_id, - 'code': code, + "card_id": card_id, + "code": code, }, ) @@ -376,20 +306,20 @@ def add_pay_giftcard(self, base_info, extra_info, is_membercard): :return: 规则 ID, 设置成功的列表,以及设置失败的列表 """ if is_membercard: - rule_key = 'member_rule' - rule_type = 'RULE_TYPE_PAY_MEMBER_CARD' + rule_key = "member_rule" + rule_type = "RULE_TYPE_PAY_MEMBER_CARD" else: - rule_key = 'single_pay' - rule_type = 'RULE_TYPE_SINGLE_PAY' + rule_key = "single_pay" + rule_type = "RULE_TYPE_SINGLE_PAY" return self._post( - 'card/paygiftcard/add', + "card/paygiftcard/add", data={ - 'rule_info': { - 'type': rule_type, - 'base_info': base_info, + "rule_info": { + "type": rule_type, + "base_info": base_info, rule_key: extra_info, } - } + }, ) def del_pay_giftcard(self, rule_id): @@ -401,9 +331,9 @@ def del_pay_giftcard(self, rule_id): :param rule_id: 支付即会员的规则 ID """ return self._post( - 'card/paygiftcard/delete', + "card/paygiftcard/delete", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, ) @@ -418,11 +348,11 @@ def get_pay_giftcard(self, rule_id): :rtype: dict """ return self._post( - 'card/paygiftcard/getbyid', + "card/paygiftcard/getbyid", data={ - 'rule_id': rule_id, + "rule_id": rule_id, }, - result_processor=lambda x: x['rule_info'], + result_processor=lambda x: x["rule_info"], ) def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): @@ -441,75 +371,81 @@ def batch_get_pay_giftcard(self, effective=True, offset=0, count=10): :return: 支付后投放卡券规则的总数,以及查询到的列表 """ return self._post( - 'card/paygiftcard/batchget', + "card/paygiftcard/batchget", data={ - 'type': 'RULE_TYPE_PAY_MEMBER_CARD', - 'effective': effective, - 'offset': offset, - 'count': count, + "type": "RULE_TYPE_PAY_MEMBER_CARD", + "effective": effective, + "offset": offset, + "count": count, }, ) - def update_movie_ticket(self, code, ticket_class, show_time, duration, - screening_room, seat_number, card_id=None): + def update_movie_ticket( + self, + code, + ticket_class, + show_time, + duration, + screening_room, + seat_number, + card_id=None, + ): """ 更新电影票 """ ticket = { - 'code': code, - 'ticket_class': ticket_class, - 'show_time': show_time, - 'duration': duration, - 'screening_room': screening_room, - 'seat_number': seat_number + "code": code, + "ticket_class": ticket_class, + "show_time": show_time, + "duration": duration, + "screening_room": screening_room, + "seat_number": seat_number, } if card_id: - ticket['card_id'] = card_id - return self._post( - 'card/movieticket/updateuser', - data=ticket - ) - - def checkin_boardingpass(self, code, passenger_name, seat_class, - etkt_bnr, seat='', gate='', boarding_time=None, - is_cancel=False, qrcode_data=None, card_id=None): + ticket["card_id"] = card_id + return self._post("card/movieticket/updateuser", data=ticket) + + def checkin_boardingpass( + self, + code, + passenger_name, + seat_class, + etkt_bnr, + seat="", + gate="", + boarding_time=None, + is_cancel=False, + qrcode_data=None, + card_id=None, + ): """ 飞机票接口 """ data = { - 'code': code, - 'passenger_name': passenger_name, - 'class': seat_class, - 'etkt_bnr': etkt_bnr, - 'seat': seat, - 'gate': gate, - 'is_cancel': is_cancel + "code": code, + "passenger_name": passenger_name, + "class": seat_class, + "etkt_bnr": etkt_bnr, + "seat": seat, + "gate": gate, + "is_cancel": is_cancel, } if boarding_time: - data['boarding_time'] = boarding_time + data["boarding_time"] = boarding_time if qrcode_data: - data['qrcode_data'] = qrcode_data + data["qrcode_data"] = qrcode_data if card_id: - data['card_id'] = card_id - return self._post( - 'card/boardingpass/checkin', - data=data - ) + data["card_id"] = card_id + return self._post("card/boardingpass/checkin", data=data) def update_luckymoney_balance(self, code, balance, card_id=None): """ 更新红包余额 """ - card_data = { - 'code': code, - 'balance': balance - } + card_data = {"code": code, "balance": balance} if card_id: - card_data['card_id'] = card_id - return self._post( - 'card/luckymoney/updateuserbalance', - data=card_data - ) + card_data["card_id"] = card_id + return self._post("card/luckymoney/updateuserbalance", data=card_data) def get_redirect_url(self, url, encrypt_code, card_id): """ @@ -525,51 +461,33 @@ def get_redirect_url(self, url, encrypt_code, card_id): signer.add_data(card_id) signature = signer.signature - r = '{url}?encrypt_code={code}&card_id={card_id}&signature={signature}' + r = "{url}?encrypt_code={code}&card_id={card_id}&signature={signature}" return r.format( - url=url, - code=encrypt_code, - card_id=card_id, - signature=signature + url=url, code=encrypt_code, card_id=card_id, signature=signature ) def deposit_code(self, card_id, codes): """ 导入code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/deposit', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/deposit", data=card_data) def get_deposit_count(self, card_id): """ 查询导入code数目 """ card_data = { - 'card_id': card_id, + "card_id": card_id, } - return self._post( - 'card/code/getdepositcount', - data=card_data - ) + return self._post("card/code/getdepositcount", data=card_data) def check_code(self, card_id, codes): """ 核查code """ - card_data = { - 'card_id': card_id, - 'code': codes - } - return self._post( - 'card/code/checkcode', - data=card_data - ) + card_data = {"card_id": card_id, "code": codes} + return self._post("card/code/checkcode", data=card_data) def modify_stock(self, card_id, n): """ @@ -578,16 +496,13 @@ def modify_stock(self, card_id, n): if n == 0: return card_data = { - 'card_id': card_id, + "card_id": card_id, } if n > 0: - card_data['increase_stock_value'] = n + card_data["increase_stock_value"] = n elif n < 0: - card_data['reduce_stock_value'] = -n - return self._post( - 'card/modifystock', - data=card_data - ) + card_data["reduce_stock_value"] = -n + return self._post("card/modifystock", data=card_data) def get_activate_url(self, card_id, outer_str=None): """ @@ -600,12 +515,12 @@ def get_activate_url(self, card_id, outer_str=None): :return: 内含调用开卡插件所需的参数的 Url """ return self._post( - 'card/membercard/activate/geturl', + "card/membercard/activate/geturl", data={ - 'card_id': card_id, - 'outer_str': outer_str, + "card_id": card_id, + "outer_str": outer_str, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_activate_info(self, activate_ticket): @@ -618,11 +533,11 @@ def get_activate_info(self, activate_ticket): :return: 用户开卡时填写的字段值 """ return self._post( - 'card/membercard/activatetempinfo/get', + "card/membercard/activatetempinfo/get", data={ - 'activate_ticket': activate_ticket, + "activate_ticket": activate_ticket, }, - result_processor=lambda x: x['info'], + result_processor=lambda x: x["info"], ) def set_activate_user_form(self, card_id, **kwargs): @@ -693,8 +608,5 @@ def set_activate_user_form(self, card_id, **kwargs): :param card_id: 卡券ID :param kwargs: 其他非必填参数,见微信文档 """ - kwargs['card_id'] = card_id - return self._post( - 'card/membercard/activateuserform/set', - data=kwargs - ) + kwargs["card_id"] = card_id + return self._post("card/membercard/activateuserform/set", data=kwargs) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/customservice.py b/chapter14/booking_system/exts/wechatpy/client/api/customservice.py index a5c2471..89d0cc4 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/customservice.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/customservice.py @@ -26,12 +26,8 @@ def add_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/add', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/add", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def update_account(self, account, nickname, password): @@ -48,12 +44,8 @@ def update_account(self, account, nickname, password): password = to_binary(password) password = hashlib.md5(password).hexdigest() return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/update', - data={ - 'kf_account': account, - 'nickname': nickname, - 'password': password - } + "https://api.weixin.qq.com/customservice/kfaccount/update", + data={"kf_account": account, "nickname": nickname, "password": password}, ) def delete_account(self, account): @@ -66,13 +58,12 @@ def delete_account(self, account): :return: 返回的 JSON 数据包 """ params_data = [ - 'access_token={0}'.format(quote(self.access_token)), - 'kf_account={0}'.format(quote(to_binary(account), safe=b'/@')), + "access_token={0}".format(quote(self.access_token)), + "kf_account={0}".format(quote(to_binary(account), safe=b"/@")), ] - params = '&'.join(params_data) + params = "&".join(params_data) return self._get( - 'https://api.weixin.qq.com/customservice/kfaccount/del', - params=params + "https://api.weixin.qq.com/customservice/kfaccount/del", params=params ) def get_accounts(self): @@ -84,8 +75,7 @@ def get_accounts(self): :return: 客服账号列表 """ res = self._get( - 'customservice/getkflist', - result_processor=lambda x: x['kf_list'] + "customservice/getkflist", result_processor=lambda x: x["kf_list"] ) return res @@ -100,13 +90,9 @@ def upload_headimg(self, account, media_file): :return: 返回的 JSON 数据包 """ return self._post( - 'https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg', - params={ - 'kf_account': account - }, - files={ - 'media': media_file - } + "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg", + params={"kf_account": account}, + files={"media": media_file}, ) def get_online_accounts(self): @@ -118,8 +104,8 @@ def get_online_accounts(self): :return: 客服接待信息列表 """ res = self._get( - 'customservice/getonlinekflist', - result_processor=lambda x: x['kf_online_list'] + "customservice/getonlinekflist", + result_processor=lambda x: x["kf_online_list"], ) return res @@ -134,14 +120,9 @@ def create_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/create', - data=data + "https://api.weixin.qq.com/customservice/kfsession/create", data=data ) def close_session(self, openid, account, text=None): @@ -155,14 +136,9 @@ def close_session(self, openid, account, text=None): :param text: 附加信息,可选 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=openid, - kf_account=account, - text=text - ) + data = optionaldict(openid=openid, kf_account=account, text=text) return self._post( - 'https://api.weixin.qq.com/customservice/kfsession/close', - data=data + "https://api.weixin.qq.com/customservice/kfsession/close", data=data ) def get_session(self, openid): @@ -175,8 +151,8 @@ def get_session(self, openid): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsession', - params={'openid': openid} + "https://api.weixin.qq.com/customservice/kfsession/getsession", + params={"openid": openid}, ) def get_session_list(self, account): @@ -189,9 +165,9 @@ def get_session_list(self, account): :return: 客服的会话列表 """ res = self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getsessionlist', - params={'kf_account': account}, - result_processor=lambda x: x['sessionlist'] + "https://api.weixin.qq.com/customservice/kfsession/getsessionlist", + params={"kf_account": account}, + result_processor=lambda x: x["sessionlist"], ) return res @@ -204,11 +180,10 @@ def get_wait_case(self): :return: 返回的 JSON 数据包 """ return self._get( - 'https://api.weixin.qq.com/customservice/kfsession/getwaitcase' + "https://api.weixin.qq.com/customservice/kfsession/getwaitcase" ) - def get_records(self, start_time, end_time, msgid=1, - number=10000): + def get_records(self, start_time, end_time, msgid=1, number=10000): """ 获取客服聊天记录 @@ -224,13 +199,13 @@ def get_records(self, start_time, end_time, msgid=1, if isinstance(end_time, datetime.datetime): end_time = time.mktime(end_time.timetuple()) record_data = { - 'starttime': int(start_time), - 'endtime': int(end_time), - 'msgid': msgid, - 'number': number + "starttime": int(start_time), + "endtime": int(end_time), + "msgid": msgid, + "number": number, } res = self._post( - 'https://api.weixin.qq.com/customservice/msgrecord/getmsglist', + "https://api.weixin.qq.com/customservice/msgrecord/getmsglist", data=record_data, ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/datacube.py b/chapter14/booking_system/exts/wechatpy/client/api/datacube.py index ef80f89..d4fafac 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/datacube.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/datacube.py @@ -9,16 +9,16 @@ class WeChatDataCube(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/datacube/' + API_BASE_URL = "https://api.weixin.qq.com/datacube/" @classmethod def _to_date_str(cls, date): if isinstance(date, (datetime.datetime, datetime.date)): - return date.strftime('%Y-%m-%d') + return date.strftime("%Y-%m-%d") elif isinstance(date, six.string_types): return date else: - raise ValueError('Can not convert %s type to str', type(date)) + raise ValueError("Can not convert %s type to str", type(date)) def get_user_summary(self, begin_date, end_date): """ @@ -31,13 +31,13 @@ def get_user_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersummary', + "getusersummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) - } + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), + }, ) - return res['list'] + return res["list"] def get_user_cumulate(self, begin_date, end_date): """ @@ -50,12 +50,12 @@ def get_user_cumulate(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusercumulate', + "getusercumulate", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -70,12 +70,12 @@ def get_interface_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummary', + "getinterfacesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -90,12 +90,12 @@ def get_interface_summary_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getinterfacesummaryhour', + "getinterfacesummaryhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -110,12 +110,12 @@ def get_article_summary(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticlesummary', + "getarticlesummary", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -130,12 +130,12 @@ def get_article_total(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getarticletotal', + "getarticletotal", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -150,12 +150,12 @@ def get_user_read(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserread', + "getuserread", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -170,12 +170,12 @@ def get_user_read_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getuserreadhour', + "getuserreadhour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -190,12 +190,12 @@ def get_user_share(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusershare', + "getusershare", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -210,12 +210,12 @@ def get_user_share_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getusersharehour', + "getusersharehour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -230,12 +230,12 @@ def get_upstream_msg(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsg', + "getupstreammsg", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -250,12 +250,12 @@ def get_upstream_msg_hour(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsghour', + "getupstreammsghour", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -270,12 +270,12 @@ def get_upstream_msg_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgweek', + "getupstreammsgweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -290,12 +290,12 @@ def get_upstream_msg_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgmonth', + "getupstreammsgmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -310,12 +310,12 @@ def get_upstream_msg_dist(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdist', + "getupstreammsgdist", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -330,12 +330,12 @@ def get_upstream_msg_dist_week(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistweek', + "getupstreammsgdistweek", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res @@ -350,11 +350,11 @@ def get_upstream_msg_dist_month(self, begin_date, end_date): :return: 统计数据列表 """ res = self._post( - 'getupstreammsgdistmonth', + "getupstreammsgdistmonth", data={ - 'begin_date': self._to_date_str(begin_date), - 'end_date': self._to_date_str(end_date) + "begin_date": self._to_date_str(begin_date), + "end_date": self._to_date_str(end_date), }, - result_processor=lambda x: x['list'] + result_processor=lambda x: x["list"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/device.py b/chapter14/booking_system/exts/wechatpy/client/api/device.py index 01aecb2..be27851 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/device.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/device.py @@ -9,7 +9,7 @@ class WeChatDevice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/device/' + API_BASE_URL = "https://api.weixin.qq.com/device/" def send_message(self, device_type, device_id, user_id, content): """ @@ -25,16 +25,18 @@ def send_message(self, device_type, device_id, user_id, content): """ content = to_text(base64.b64encode(to_binary(content))) return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'content': content - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "content": content, + }, ) - def send_status_message(self, device_type, device_id, user_id, msg_type, device_status): + def send_status_message( + self, device_type, device_id, user_id, msg_type, device_status + ): """ 第三方主动发送设备状态消息给微信终端 详情请参考 @@ -48,14 +50,14 @@ def send_status_message(self, device_type, device_id, user_id, msg_type, device_ :return: 返回的 JSON 数据包 """ return self._post( - 'transmsg', + "transmsg", data={ - 'device_type': device_type, - 'device_id': device_id, - 'open_id': user_id, - 'msg_type': msg_type, - 'device_status': device_status, - } + "device_type": device_type, + "device_id": device_id, + "open_id": user_id, + "msg_type": msg_type, + "device_status": device_status, + }, ) def create_qrcode(self, device_ids): @@ -68,11 +70,8 @@ def create_qrcode(self, device_ids): :return: 返回的 JSON 数据包 """ return self._post( - 'create_qrcode', - data={ - 'device_num': len(device_ids), - 'device_id_list': device_ids - } + "create_qrcode", + data={"device_num": len(device_ids), "device_id_list": device_ids}, ) def get_qrcode_url(self, ticket, data=None): @@ -85,12 +84,12 @@ def get_qrcode_url(self, ticket, data=None): :param data: 额外数据 :return: 二维码地址 """ - url = 'https://we.qq.com/d/{ticket}'.format(ticket=ticket) + url = "https://we.qq.com/d/{ticket}".format(ticket=ticket) if data: if isinstance(data, (dict, tuple, list)): data = urllib.urlencode(data) data = to_text(base64.b64encode(to_binary(data))) - url = '{base}#{data}'.format(base=url, data=data) + url = "{base}#{data}".format(base=url, data=data) return url def bind(self, ticket, device_id, user_id): @@ -105,12 +104,7 @@ def bind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'bind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "bind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def unbind(self, ticket, device_id, user_id): @@ -125,12 +119,7 @@ def unbind(self, ticket, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'unbind', - data={ - 'ticket': ticket, - 'device_id': device_id, - 'openid': user_id - } + "unbind", data={"ticket": ticket, "device_id": device_id, "openid": user_id} ) def compel_bind(self, device_id, user_id): @@ -144,11 +133,7 @@ def compel_bind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_bind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_bind", data={"device_id": device_id, "openid": user_id} ) force_bind = compel_bind @@ -164,11 +149,7 @@ def compel_unbind(self, device_id, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'compel_unbind', - data={ - 'device_id': device_id, - 'openid': user_id - } + "compel_unbind", data={"device_id": device_id, "openid": user_id} ) force_unbind = compel_unbind @@ -182,10 +163,7 @@ def get_stat(self, device_id): :param device_id: 设备id :return: 返回的 JSON 数据包 """ - return self._get( - 'get_stat', - params={'device_id': device_id} - ) + return self._get("get_stat", params={"device_id": device_id}) def verify_qrcode(self, ticket): """ @@ -196,10 +174,7 @@ def verify_qrcode(self, ticket): :param ticket: 设备二维码的ticket :return: 返回的 JSON 数据包 """ - return self._post( - 'verify_qrcode', - data={'ticket': ticket} - ) + return self._post("verify_qrcode", data={"ticket": ticket}) def get_user_id(self, device_type, device_id): """ @@ -212,11 +187,7 @@ def get_user_id(self, device_type, device_id): :return: 返回的 JSON 数据包 """ return self._get( - 'get_openid', - params={ - 'device_type': device_type, - 'device_id': device_id - } + "get_openid", params={"device_type": device_type, "device_id": device_id} ) get_open_id = get_user_id @@ -230,10 +201,7 @@ def get_binded_devices(self, user_id): :param user_id: 要查询的用户的openid :return: 返回的 JSON 数据包 """ - return self._get( - 'get_bind_device', - params={'openid': user_id} - ) + return self._get("get_bind_device", params={"openid": user_id}) get_bind_device = get_binded_devices @@ -246,12 +214,12 @@ def get_qrcode(self, product_id=1): :param product_id: 设备的产品编号 :return: 返回的 JSON 数据包 """ - if product_id == '1' or product_id == 1: + if product_id == "1" or product_id == 1: params = None else: - params = {'product_id': product_id} + params = {"product_id": product_id} - return self._get('getqrcode', params=params) + return self._get("getqrcode", params=params) def authorize(self, devices, op_type=1): """ @@ -264,10 +232,10 @@ def authorize(self, devices, op_type=1): :return: 返回的 JSON 数据包 """ return self._post( - 'authorize_device', + "authorize_device", data={ - 'device_num': len(devices), - 'device_list': devices, - 'op_type': op_type - } + "device_num": len(devices), + "device_list": devices, + "op_type": op_type, + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/group.py b/chapter14/booking_system/exts/wechatpy/client/api/group.py index a3e5927..6dc4e94 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/group.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/group.py @@ -26,10 +26,7 @@ def create(self, name): """ name = to_text(name) - return self._post( - 'groups/create', - data={'group': {'name': name}} - ) + return self._post("groups/create", data={"group": {"name": name}}) def get(self, user_id=None): """ @@ -50,15 +47,12 @@ def get(self, user_id=None): """ if user_id is None: - res = self._get( - 'groups/get', - result_processor=lambda x: x['groups'] - ) + res = self._get("groups/get", result_processor=lambda x: x["groups"]) else: res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -83,13 +77,7 @@ def update(self, group_id, name): """ name = to_text(name) return self._post( - 'groups/update', - data={ - 'group': { - 'id': int(group_id), - 'name': name - } - } + "groups/update", data={"group": {"id": int(group_id), "name": name}} ) def move_user(self, user_id, group_id): @@ -111,13 +99,13 @@ def move_user(self, user_id, group_id): res = client.group.move_user('openid', 1234) """ - data = {'to_groupid': group_id} + data = {"to_groupid": group_id} if isinstance(user_id, (tuple, list)): - endpoint = 'groups/members/batchupdate' - data['openid_list'] = user_id + endpoint = "groups/members/batchupdate" + data["openid_list"] = user_id else: - endpoint = 'groups/members/update' - data['openid'] = user_id + endpoint = "groups/members/update" + data["openid"] = user_id return self._post(endpoint, data=data) def delete(self, group_id): @@ -138,11 +126,4 @@ def delete(self, group_id): res = client.group.delete(1234) """ - return self._post( - 'groups/delete', - data={ - 'group': { - 'id': group_id - } - } - ) + return self._post("groups/delete", data={"group": {"id": group_id}}) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/invoice.py b/chapter14/booking_system/exts/wechatpy/client/api/invoice.py index f0182d5..b2808c2 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/invoice.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/invoice.py @@ -5,7 +5,7 @@ class WeChatInvoice(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/card/invoice/' + API_BASE_URL = "https://api.weixin.qq.com/card/invoice/" def get_url(self): """ @@ -16,9 +16,9 @@ def get_url(self): :return:该开票平台专用的授权链接 """ return self._post( - 'seturl', + "seturl", data={}, - result_processor=lambda x: x['invoice_url'], + result_processor=lambda x: x["invoice_url"], ) def create_card(self, base_info, payee, invoice_type, detail=None): @@ -36,19 +36,29 @@ def create_card(self, base_info, payee, invoice_type, detail=None): :return: 发票卡券模板的编号,用于后续该商户发票生成后,作为必填参数在调用插卡接口时传入 """ return self._post( - 'platform/createcard', + "platform/createcard", data={ - 'invoice_info': { - 'base_info': base_info, - 'payee': payee, - 'type': invoice_type, - 'detail': detail, + "invoice_info": { + "base_info": base_info, + "payee": payee, + "type": invoice_type, + "detail": detail, }, }, - result_processor=lambda x: x['card_id'], + result_processor=lambda x: x["card_id"], ) - def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, auth_type, redirect_url=None): + def get_auth_url( + self, + s_pappid, + order_id, + money, + timestamp, + source, + ticket, + auth_type, + redirect_url=None, + ): """ 获取授权页链接 详情请参考 @@ -67,25 +77,27 @@ def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, aut :param redirect_url: 授权成功后跳转页面。本字段只有在source为H5的时候需要填写。 :return: 获取授权页链接 """ - if source not in {'app', 'web', 'wap'}: - raise ValueError('Unsupported source. Valid sources are "app", "web" or "wap"') - if source == 'web' and redirect_url is None: - raise ValueError('redirect_url is required if source is web') + if source not in {"app", "web", "wap"}: + raise ValueError( + 'Unsupported source. Valid sources are "app", "web" or "wap"' + ) + if source == "web" and redirect_url is None: + raise ValueError("redirect_url is required if source is web") if not (0 <= auth_type <= 2): - raise ValueError('Unsupported auth type. Valid auth types are 0, 1 or 2') + raise ValueError("Unsupported auth type. Valid auth types are 0, 1 or 2") return self._post( - 'getauthurl', + "getauthurl", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'money': money, - 'timestamp': timestamp, - 'source': source, - 'ticket': ticket, - 'type': auth_type, - 'redirect_url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "money": money, + "timestamp": timestamp, + "source": source, + "ticket": ticket, + "type": auth_type, + "redirect_url": redirect_url, }, - result_processor=lambda x: x['auth_url'], + result_processor=lambda x: x["auth_url"], ) def set_auth_field(self, user_field, biz_field): @@ -100,14 +112,14 @@ def set_auth_field(self, user_field, biz_field): :type biz_field: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_auth_field', + "action": "set_auth_field", }, data={ - 'auth_field': { - 'user_field': user_field, - 'biz_field': biz_field, + "auth_field": { + "user_field": user_field, + "biz_field": biz_field, }, }, ) @@ -122,9 +134,9 @@ def get_auth_field(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_auth_field', + "action": "get_auth_field", }, data={}, ) @@ -141,10 +153,10 @@ def get_auth_data(self, s_pappid, order_id): :rtype: dict """ return self._post( - 'getauthdata', + "getauthdata", data={ - 's_pappid': s_pappid, - 'order_id': order_id, + "s_pappid": s_pappid, + "order_id": order_id, }, ) @@ -160,12 +172,12 @@ def reject_insert(self, s_pappid, order_id, reason, redirect_url=None): :param redirect_url: 跳转链接 """ return self._post( - 'rejectinsert', + "rejectinsert", data={ - 's_pappid': s_pappid, - 'order_id': order_id, - 'reason': reason, - 'url': redirect_url, + "s_pappid": s_pappid, + "order_id": order_id, + "reason": reason, + "url": redirect_url, }, ) @@ -183,12 +195,12 @@ def insert(self, order_id, card_id, appid, card_ext): :return: 随机防重字符串,以及用户 Open ID """ return self._post( - 'insert', + "insert", data={ - 'order_id': order_id, - 'card_id': card_id, - 'appid': appid, - 'card_ext': card_ext, + "order_id": order_id, + "card_id": card_id, + "appid": appid, + "card_ext": card_ext, }, ) @@ -202,11 +214,11 @@ def upload_pdf(self, pdf): :return: 64位整数,在将发票卡券插入用户卡包时使用用于关联pdf和发票卡券。有效期为3天。 """ return self._post( - 'platform/setpdf', + "platform/setpdf", files={ - 'pdf': pdf, + "pdf": pdf, }, - result_processor=lambda x: x['s_media_id'], + result_processor=lambda x: x["s_media_id"], ) def get_pdf(self, s_media_id): @@ -220,12 +232,12 @@ def get_pdf(self, s_media_id): :rtype: dict """ return self._post( - 'platform/getpdf', + "platform/getpdf", params={ - 'action': 'get_url', + "action": "get_url", }, data={ - 's_media_id': s_media_id, + "s_media_id": s_media_id, }, ) @@ -240,11 +252,11 @@ def update_status(self, card_id, code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'platform/updatestatus', + "platform/updatestatus", data={ - 'card_id': card_id, - 'code': code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "code": code, + "reimburse_status": reimburse_status, }, ) @@ -258,14 +270,14 @@ def set_pay_mch(self, mchid, s_pappid): :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供 """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'set_pay_mch', + "action": "set_pay_mch", }, data={ - 'paymch_info': { - 'mchid': mchid, - 's_pappid': s_pappid, + "paymch_info": { + "mchid": mchid, + "s_pappid": s_pappid, }, }, ) @@ -280,9 +292,9 @@ def get_pay_mch(self): :rtype: dict """ return self._post( - 'setbizattr', + "setbizattr", params={ - 'action': 'get_pay_mch', + "action": "get_pay_mch", }, data={}, ) @@ -299,10 +311,10 @@ def get_reimburse(self, card_id, encrypt_code): :rtype: dict """ return self._post( - 'reimburse/getinvoiceinfo', + "reimburse/getinvoiceinfo", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, + "card_id": card_id, + "encrypt_code": encrypt_code, }, ) @@ -317,11 +329,11 @@ def update_reimburse(self, card_id, encrypt_code, reimburse_status): :param reimburse_status: 发票报销状态 """ return self._post( - 'reimburse/updateinvoicestatus', + "reimburse/updateinvoicestatus", data={ - 'card_id': card_id, - 'encrypt_code': encrypt_code, - 'reimburse_status': reimburse_status, + "card_id": card_id, + "encrypt_code": encrypt_code, + "reimburse_status": reimburse_status, }, ) @@ -337,17 +349,25 @@ def batch_update_reimburse(self, openid, reimburse_status, invoice_list): :type invoice_list: list[dict] """ return self._post( - 'reimburse/updatestatusbatch', + "reimburse/updatestatusbatch", data={ - 'openid': openid, - 'reimburse_status': reimburse_status, - 'invoice_list': invoice_list, + "openid": openid, + "reimburse_status": reimburse_status, + "invoice_list": invoice_list, }, ) def get_user_title_url( - self, user_fill, title=None, phone=None, tax_no=None, addr=None, bank_type=None, bank_no=None, - out_title_id=None): + self, + user_fill, + title=None, + phone=None, + tax_no=None, + addr=None, + bank_type=None, + bank_no=None, + out_title_id=None, + ): """ 获取添加发票链接 获取链接,发送给用户。用户同意以后,发票抬头信息将会录入到用户微信中 @@ -366,20 +386,20 @@ def get_user_title_url( :return: 添加发票的链接 """ if user_fill and title is None: - raise ValueError('title is required when user_fill is False') + raise ValueError("title is required when user_fill is False") return self._post( - 'biz/getusertitleurl', + "biz/getusertitleurl", data={ - 'user_fill': int(user_fill), - 'title': title, - 'phone': phone, - 'tax_no': tax_no, - 'addr': addr, - 'bank_type': bank_type, - 'bank_no': bank_no, - 'out_title_id': out_title_id, + "user_fill": int(user_fill), + "title": title, + "phone": phone, + "tax_no": tax_no, + "addr": addr, + "bank_type": bank_type, + "bank_no": bank_no, + "out_title_id": out_title_id, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def get_select_title_url(self, attach=None): @@ -393,11 +413,11 @@ def get_select_title_url(self, attach=None): :return: 商户专属开票链接 """ return self._post( - 'biz/getselecttitleurl', + "biz/getselecttitleurl", data={ - 'attach': attach, + "attach": attach, }, - result_processor=lambda x: x['url'], + result_processor=lambda x: x["url"], ) def scan_title(self, scan_text): @@ -412,8 +432,8 @@ def scan_title(self, scan_text): :rtype: dict """ return self._post( - 'scantitle', + "scantitle", data={ - 'scan_text': scan_text, + "scan_text": scan_text, }, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/jsapi.py b/chapter14/booking_system/exts/wechatpy/client/api/jsapi.py index 0bbcd5c..d7db0b9 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/jsapi.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/jsapi.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.client.jsapi - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.client.jsapi +~~~~~~~~~~~~~~~~~~~~ - This module provides some APIs for JS SDK +This module provides some APIs for JS SDK - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -19,16 +19,13 @@ class WeChatJSAPI(BaseWeChatAPI): - def get_ticket(self, type='jsapi'): + def get_ticket(self, type="jsapi"): """ 获取微信 JS-SDK ticket :return: 返回的 JSON 数据包 """ - return self._get( - 'ticket/getticket', - params={'type': type} - ) + return self._get("ticket/getticket", params={"type": type}) def get_jsapi_ticket(self): """ @@ -38,14 +35,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{0}_jsapi_ticket'.format(self.appid) - expires_at_key = '{0}_jsapi_ticket_expires_at'.format(self.appid) + ticket_key = "{0}_jsapi_ticket".format(self.appid) + expires_at_key = "{0}_jsapi_ticket_expires_at".format(self.appid) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): - jsapi_ticket_response = self.get_ticket('jsapi') - ticket = jsapi_ticket_response['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket_response['expires_in']) + jsapi_ticket_response = self.get_ticket("jsapi") + ticket = jsapi_ticket_response["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket_response["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -61,12 +58,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -78,15 +75,17 @@ def get_jsapi_card_ticket(self): :return: ticket """ - jsapi_card_ticket_key = '{0}_jsapi_card_ticket'.format(self.appid) - jsapi_card_ticket_expire_at_key = '{0}_jsapi_card_ticket_expires_at'.format(self.appid) + jsapi_card_ticket_key = "{0}_jsapi_card_ticket".format(self.appid) + jsapi_card_ticket_expire_at_key = "{0}_jsapi_card_ticket_expires_at".format( + self.appid + ) ticket = self.session.get(jsapi_card_ticket_key) expires_at = self.session.get(jsapi_card_ticket_expire_at_key, 0) if not ticket or int(expires_at) < int(time.time()): - ticket_response = self.get_ticket('wx_card') - ticket = ticket_response['ticket'] - expires_at = int(time.time()) + int(ticket_response['expires_in']) + ticket_response = self.get_ticket("wx_card") + ticket = ticket_response["ticket"] + expires_at = int(time.time()) + int(ticket_response["expires_in"]) self.session.set(jsapi_card_ticket_key, ticket) self.session.set(jsapi_card_ticket_expire_at_key, expires_at) return ticket @@ -95,18 +94,18 @@ def get_jsapi_card_params(self, card_ticket, card_type, **kwargs): """ 参数意义见微信文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html :param card_ticket: 用于卡券的微信 api_ticket - :param card_type: + :param card_type: :param kwargs: 非必须参数:noncestr, timestamp, code, openid, fixed_begintimestamp, outer_str :return: 包含调用jssdk所有所需参数的 dict """ card_signature_dict = { - 'card_type': card_type, - 'noncestr': kwargs.get('noncestr', random_string()), - 'api_ticket': card_ticket, - 'appid': self.appid, - 'timestamp': kwargs.get('timestamp', str(int(time.time()))), + "card_type": card_type, + "noncestr": kwargs.get("noncestr", random_string()), + "api_ticket": card_ticket, + "appid": self.appid, + "timestamp": kwargs.get("timestamp", str(int(time.time()))), } list_before_sign = sorted([str(x) for x in card_signature_dict.values()]) str_to_sign = "".join(list_before_sign).encode() - card_signature_dict['sign'] = hashlib.sha1(str_to_sign).hexdigest() + card_signature_dict["sign"] = hashlib.sha1(str_to_sign).hexdigest() return card_signature_dict diff --git a/chapter14/booking_system/exts/wechatpy/client/api/marketing.py b/chapter14/booking_system/exts/wechatpy/client/api/marketing.py index 4aa9461..5192f8a 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/marketing.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/marketing.py @@ -10,9 +10,9 @@ class WeChatMarketing(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/marketing/' + API_BASE_URL = "https://api.weixin.qq.com/marketing/" - def add_user_action_sets(self, _type, name, description, version='v1.0'): + def add_user_action_sets(self, _type, name, description, version="v1.0"): """ 创建数据源 https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 @@ -24,18 +24,15 @@ def add_user_action_sets(self, _type, name, description, version='v1.0'): :return: 数据源唯一ID """ return self._post( - 'user_action_sets/add', - params={'version': version}, + "user_action_sets/add", + params={"version": version}, json=optionaldict( - type=_type, - name=name, - description=description, - version=version + type=_type, name=name, description=description, version=version ), - result_processor=lambda x: x['data']['user_action_set_id'] + result_processor=lambda x: x["data"]["user_action_set_id"], ) - def get_user_action_sets(self, user_action_set_id, version='v1.0'): + def get_user_action_sets(self, user_action_set_id, version="v1.0"): """ 获取数据源信息 @@ -43,12 +40,12 @@ def get_user_action_sets(self, user_action_set_id, version='v1.0'): :param version: 版本号 v1.0 """ return self._get( - 'user_action_sets/get', - params={'version': version, 'user_action_set_id': user_action_set_id}, - result_processor=lambda x: x['data']['list'] + "user_action_sets/get", + params={"version": version, "user_action_set_id": user_action_set_id}, + result_processor=lambda x: x["data"]["list"], ) - def add_user_actions(self, actions=(), version='v1.0'): + def add_user_actions(self, actions=(), version="v1.0"): """ 回传数据 @@ -58,12 +55,18 @@ def add_user_actions(self, actions=(), version='v1.0'): :param version: 版本号 v1.0 """ return self._post( - 'user_actions/add', - params={'version': version}, - json={'actions': actions} + "user_actions/add", params={"version": version}, json={"actions": actions} ) - def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, page_size=100, version='v1.0'): + def get_ad_leads( + self, + start_date=None, + end_date=None, + filtering=(), + page=1, + page_size=100, + version="v1.0", + ): """ 获取朋友圈销售线索数据接口 @@ -85,13 +88,13 @@ def get_ad_leads(self, start_date=None, end_date=None, filtering=(), page=1, pag end_date = end_date.strftime("%Y-%m-%d") return self._get( - 'wechat_ad_leads/get', + "wechat_ad_leads/get", params=optionaldict( - date_range=json.dumps({'start_date': start_date, 'end_date': end_date}), + date_range=json.dumps({"start_date": start_date, "end_date": end_date}), filtering=json.dumps(filtering) if filtering else None, page=page, page_size=page_size, - version=version + version=version, ), - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/material.py b/chapter14/booking_system/exts/wechatpy/client/api/material.py index 9754776..af2b40e 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/material.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/material.py @@ -18,23 +18,22 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0), - 'need_open_comment': int(article.get('need_open_comment', False)), - 'only_fans_can_comment': int(article.get('only_fans_can_comment', False)), - }) - return self._post( - 'material/add_news', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + "need_open_comment": int(article.get("need_open_comment", False)), + "only_fans_can_comment": int( + article.get("only_fans_can_comment", False) + ), + } + ) + return self._post("material/add_news", data={"articles": articles_data}) def add(self, media_type, media_file, title=None, introduction=None): """ @@ -48,24 +47,14 @@ def add(self, media_type, media_file, title=None, introduction=None): :param introduction: 视频素材简介,仅上传视频素材时需要 :return: 返回的 JSON 数据包 """ - params = { - 'access_token': self.access_token, - 'type': media_type - } - if media_type == 'video': - assert title, 'Video title must be set' - assert introduction, 'Video introduction must be set' - description = { - 'title': title, - 'introduction': introduction - } - params['description'] = json.dumps(description) + params = {"access_token": self.access_token, "type": media_type} + if media_type == "video": + assert title, "Video title must be set" + assert introduction, "Video introduction must be set" + description = {"title": title, "introduction": introduction} + params["description"] = json.dumps(description) return self._post( - 'material/add_material', - params=params, - files={ - 'media': media_file - } + "material/add_material", params=params, files={"media": media_file} ) def get(self, media_id): @@ -77,19 +66,18 @@ def get(self, media_id): :param media_id: 素材的 media_id :return: 图文素材返回图文列表,其它类型为素材的内容 """ + def _processor(res): if isinstance(res, dict): - if 'news_item' in res: + if "news_item" in res: # 图文素材 - return res['news_item'] + return res["news_item"] return res res = self._post( - 'material/get_material', - data={ - 'media_id': media_id - }, - result_processor=_processor + "material/get_material", + data={"media_id": media_id}, + result_processor=_processor, ) return res @@ -102,12 +90,7 @@ def delete(self, media_id): :param media_id: 素材的 media_id :return: 返回的 JSON 数据包 """ - return self._post( - 'material/del_material', - data={ - 'media_id': media_id - } - ) + return self._post("material/del_material", data={"media_id": media_id}) def update_article(self, media_id, index, article): """ @@ -121,21 +104,17 @@ def update_article(self, media_id, index, article): :return: 返回的 JSON 数据包 """ article_data = { - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } return self._post( - 'material/update_news', - data={ - 'media_id': media_id, - 'index': index, - 'articles': article_data - } + "material/update_news", + data={"media_id": media_id, "index": index, "articles": article_data}, ) def update_articles(self, media_id, index, articles): @@ -163,12 +142,8 @@ def batchget(self, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget_material', - data={ - 'type': media_type, - 'offset': offset, - 'count': count - } + "material/batchget_material", + data={"type": media_type, "offset": offset, "count": count}, ) def get_count(self): @@ -179,7 +154,7 @@ def get_count(self): :return: 返回的 JSON 数据包 """ - return self._get('material/get_materialcount') + return self._get("material/get_materialcount") def open_comment(self, msg_data_id, index=1): """ @@ -187,94 +162,102 @@ def open_comment(self, msg_data_id, index=1): https://mp.weixin.qq.com/wiki?id=mp1494572718_WzHIY """ return self._post( - 'comment/open', + "comment/open", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def close_comment(self, msg_data_id, index=1): """ 关闭已群发文章评论 """ return self._post( - 'comment/close', + "comment/close", data={ - 'msg_data_id': msg_data_id, - 'index': index, - }) + "msg_data_id": msg_data_id, + "index": index, + }, + ) def list_comment(self, msg_data_id, index=1, begin=0, count=50, type=0): """ 查看指定文章的评论数据 """ return self._post( - 'comment/list', + "comment/list", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'begin': begin, - 'count': count, - 'type': type - }) + "msg_data_id": msg_data_id, + "index": index, + "begin": begin, + "count": count, + "type": type, + }, + ) def markelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论标记精选 """ return self._post( - 'comment/markelect', + "comment/markelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def unmarkelect_comment(self, msg_data_id, index, user_comment_id): """ 将评论取消精选 """ return self._post( - 'comment/unmarkelect', + "comment/unmarkelect", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def delete_comment(self, msg_data_id, index, user_comment_id): """ 删除评论 """ return self._post( - 'comment/delete', + "comment/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) def add_reply_comment(self, msg_data_id, index, user_comment_id, content): """ 回复评论 """ return self._post( - 'comment/reply/add', + "comment/reply/add", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - 'content': content - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + "content": content, + }, + ) def delete_reply_comment(self, msg_data_id, index, user_comment_id): """ 删除回复 """ return self._post( - 'comment/reply/delete', + "comment/reply/delete", data={ - 'msg_data_id': msg_data_id, - 'index': index, - 'user_comment_id': user_comment_id, - }) + "msg_data_id": msg_data_id, + "index": index, + "user_comment_id": user_comment_id, + }, + ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/media.py b/chapter14/booking_system/exts/wechatpy/client/api/media.py index b4338b3..3b414c6 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/media.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/media.py @@ -17,13 +17,7 @@ def upload(self, media_type, media_file): :return: 返回的 JSON 数据包 """ return self._post( - url='media/upload', - params={ - 'type': media_type - }, - files={ - 'media': media_file - } + url="media/upload", params={"type": media_type}, files={"media": media_file} ) def download(self, media_id): @@ -36,12 +30,7 @@ def download(self, media_id): :return: requests 的 Response 实例 """ - return self._get( - 'media/get', - params={ - 'media_id': media_id - } - ) + return self._get("media/get", params={"media_id": media_id}) def get_url(self, media_id): """ @@ -51,13 +40,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://api.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://api.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def upload_video(self, media_id, title, description): """ @@ -72,12 +61,8 @@ def upload_video(self, media_id, title, description): :return: 返回的 JSON 数据包 """ return self._post( - url='media/uploadvideo', - data={ - 'media_id': media_id, - 'title': title, - 'description': description - } + url="media/uploadvideo", + data={"media_id": media_id, "title": title, "description": description}, ) def upload_articles(self, articles): @@ -91,21 +76,18 @@ def upload_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'media/uploadnews', - data={ - 'articles': articles_data - } - ) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) + return self._post("media/uploadnews", data={"articles": articles_data}) def upload_image(self, media_file): """ @@ -117,11 +99,9 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='media/uploadimg', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="media/uploadimg", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/menu.py b/chapter14/booking_system/exts/wechatpy/client/api/menu.py index f0f6ce7..d509bc6 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/menu.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/menu.py @@ -24,7 +24,7 @@ def get(self): """ try: - return self._get('menu/get') + return self._get("menu/get") except WeChatClientException as e: if e.errcode == 46003: # menu not exist @@ -81,10 +81,7 @@ def create(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/create', - data=menu_data - ) + return self._post("menu/create", data=menu_data) def update(self, menu_data): """ @@ -153,7 +150,7 @@ def delete(self): res = client.menu.delete() """ - return self._get('menu/delete') + return self._get("menu/delete") def get_menu_info(self): """ @@ -171,7 +168,7 @@ def get_menu_info(self): menu_info = client.menu.get_menu_info() """ - return self._get('get_current_selfmenu_info') + return self._get("get_current_selfmenu_info") def add_conditional(self, menu_data): """ @@ -230,10 +227,7 @@ def add_conditional(self, menu_data): :return: 返回的 JSON 数据包 """ - return self._post( - 'menu/addconditional', - data=menu_data - ) + return self._post("menu/addconditional", data=menu_data) def del_conditional(self, menu_id): """ @@ -254,10 +248,7 @@ def del_conditional(self, menu_id): res = client.menu.del_conditional('menu_id') """ - return self._post( - 'menu/delconditional', - data={'menuid': menu_id} - ) + return self._post("menu/delconditional", data={"menuid": menu_id}) def try_match(self, user_id): """ @@ -278,7 +269,4 @@ def try_match(self, user_id): res = client.menu.try_match('openid') """ - return self._post( - 'menu/trymatch', - data={'user_id': user_id} - ) + return self._post("menu/trymatch", data={"user_id": user_id}) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/__init__.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/__init__.py index d8342ac..710b104 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/__init__.py @@ -12,7 +12,7 @@ class WeChatMerchant(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def __init__(self, *args, **kwargs): super(WeChatMerchant, self).__init__(*args, **kwargs) @@ -28,54 +28,30 @@ def __init__(self, *args, **kwargs): def create(self, product_data): """增加商品""" - return self._post( - 'merchant/create', - data=product_data - ) + return self._post("merchant/create", data=product_data) def delete(self, product_id): """删除商品""" - return self._post( - 'merchant/del', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/del", data={"product_id": product_id}) def update(self, product_id, product_data): """修改商品""" - product_data['product_id'] = product_id - return self._post( - 'merchant/update', - data=product_data - ) + product_data["product_id"] = product_id + return self._post("merchant/update", data=product_data) def get(self, product_id): """查询商品""" - return self._post( - 'merchant/get', - data={ - 'product_id': product_id - } - ) + return self._post("merchant/get", data={"product_id": product_id}) def get_by_status(self, status): """获取指定状态的所有商品""" - return self._post( - 'merchant/getbystatus', - data={ - 'status': status - } - ) + return self._post("merchant/getbystatus", data={"status": status}) def update_product_status(self, product_id, status): """商品上下架""" return self._post( - 'merchant/modproductstatus', - data={ - 'product_id': product_id, - 'status': status - } + "merchant/modproductstatus", + data={"product_id": product_id, "status": status}, ) def get_subcategories(self, cate_id): @@ -85,12 +61,7 @@ def get_subcategories(self, cate_id): :param cate_id: 大分类ID(根节点分类id为1) :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsub', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsub", data={"cate_id": cate_id}) def get_category_sku(self, cate_id): """ @@ -99,12 +70,7 @@ def get_category_sku(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getsku', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getsku", data={"cate_id": cate_id}) def get_category_property(self, cate_id): """ @@ -113,12 +79,7 @@ def get_category_property(self, cate_id): :param cate_id: 商品子分类ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/category/getproperty', - data={ - 'cate_id': cate_id - } - ) + return self._post("merchant/category/getproperty", data={"cate_id": cate_id}) def add_stock(self, product_id, sku_info, quantity): """ @@ -130,12 +91,8 @@ def add_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/add', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/add", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def reduce_stock(self, product_id, sku_info, quantity): @@ -148,12 +105,8 @@ def reduce_stock(self, product_id, sku_info, quantity): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/stock/reduce', - data={ - "product_id": product_id, - "sku_info": sku_info, - "quantity": quantity - } + "merchant/stock/reduce", + data={"product_id": product_id, "sku_info": sku_info, "quantity": quantity}, ) def add_express(self, product_data): @@ -163,10 +116,7 @@ def add_express(self, product_data): :param product_data: 邮费信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/add', - data=product_data - ) + return self._post("merchant/express/add", data=product_data) def del_express(self, template_id): """ @@ -175,12 +125,7 @@ def del_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update_express(self, template_id, delivery_template): """ @@ -190,11 +135,8 @@ def update_express(self, template_id, delivery_template): :param delivery_template: 邮费模板信息(字段说明详见增加邮费模板) :return: 返回的 JSON 数据包 """ - delivery_template['template_id'] = template_id - return self._post( - 'merchant/express/update', - data=delivery_template - ) + delivery_template["template_id"] = template_id + return self._post("merchant/express/update", data=delivery_template) def get_express(self, template_id): """ @@ -203,12 +145,7 @@ def get_express(self, template_id): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/getbyid", data={"template_id": template_id}) def get_all_express(self): """ @@ -217,9 +154,7 @@ def get_all_express(self): :param template_id: 邮费模板ID :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/express/getall' - ) + return self._get("merchant/express/getall") def add_group(self, group_detail): """ @@ -228,10 +163,7 @@ def add_group(self, group_detail): :param group_detail: 商品分组信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/add', - data=group_detail - ) + return self._post("merchant/group/add", data=group_detail) def del_group(self, group_id): """ @@ -240,12 +172,7 @@ def del_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update_group_property(self, group_id, group_properties): """ @@ -255,11 +182,8 @@ def update_group_property(self, group_id, group_properties): :param group_properties: 商品分组属性 :return: 返回的 JSON 数据包 """ - group_properties['group_id'] = group_id - return self._post( - 'merchant/group/propertymod', - data=group_properties - ) + group_properties["group_id"] = group_id + return self._post("merchant/group/propertymod", data=group_properties) def update_group_product(self, group_id, product_data): """ @@ -269,11 +193,8 @@ def update_group_product(self, group_id, product_data): :param product_data: 分组商品信息 :return: 返回的 JSON 数据包 """ - product_data['group_id'] = group_id - return self._post( - 'merchant/group/productmod', - data=product_data - ) + product_data["group_id"] = group_id + return self._post("merchant/group/productmod", data=product_data) def get_all_groups(self): """ @@ -281,9 +202,7 @@ def get_all_groups(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/group/getall' - ) + return self._get("merchant/group/getall") def get_group(self, group_id): """ @@ -292,12 +211,7 @@ def get_group(self, group_id): :param group_id: 商品分组ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/getbyid", data={"group_id": group_id}) def add_shelf(self, shelf_data): """ @@ -306,10 +220,7 @@ def add_shelf(self, shelf_data): :param shelf_data: 货架详情信息 :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/add', - data=shelf_data - ) + return self._post("merchant/shelf/add", data=shelf_data) def del_shelf(self, shelf_id): """ @@ -318,12 +229,7 @@ def del_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update_shelf(self, shelf_id, shelf_data): """ @@ -333,11 +239,8 @@ def update_shelf(self, shelf_id, shelf_data): :param shelf_data: 货架详情 :return: 返回的 JSON 数据包 """ - shelf_data['shelf_id'] = shelf_id - return self._post( - 'merchant/shelf/mod', - data=shelf_data - ) + shelf_data["shelf_id"] = shelf_id + return self._post("merchant/shelf/mod", data=shelf_data) def get_all_shelves(self): """ @@ -345,9 +248,7 @@ def get_all_shelves(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'merchant/shelf/getall' - ) + return self._get("merchant/shelf/getall") def get_shelf(self, shelf_id): """ @@ -356,12 +257,7 @@ def get_shelf(self, shelf_id): :param shelf_id: 货架ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) def get_order(self, order_id): """ @@ -370,12 +266,7 @@ def get_order(self, order_id): :param order_id: 订单ID :return: 返回的 JSON 数据包 """ - return self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/getbyid", data={"order_id": order_id}) def query_order(self, status=None, begintime=None, endtime=None): """ @@ -387,12 +278,8 @@ def query_order(self, status=None, begintime=None, endtime=None): :return: 返回的 JSON 数据包 """ return self._post( - 'merchant/order/getbyfilter', - data={ - 'status': status, - 'begintime': begintime, - 'endtime': endtime - } + "merchant/order/getbyfilter", + data={"status": status, "begintime": begintime, "endtime": endtime}, ) def set_delivery(self, order_id, delivery_data): @@ -403,11 +290,8 @@ def set_delivery(self, order_id, delivery_data): :param delivery_data: 商品物流信息 :return: 返回的 JSON 数据包 """ - delivery_data['order_id'] = order_id - return self._post( - 'merchant/shelf/setdeliverymod', - data=delivery_data - ) + delivery_data["order_id"] = order_id + return self._post("merchant/shelf/setdeliverymod", data=delivery_data) def upload_image(self, media_file): """ @@ -417,10 +301,8 @@ def upload_image(self, media_file): :return: 上传成功时返回图片 URL """ res = self._post( - url='merchant/common/upload_img', - files={ - 'media': media_file - }, - result_processor=lambda x: x['url'] + url="merchant/common/upload_img", + files={"media": media_file}, + result_processor=lambda x: x["url"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/category.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/category.py index 3297125..584a902 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/category.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/category.py @@ -5,28 +5,28 @@ class MerchantCategory(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get_sub_categories(self, cate_id): res = self._post( - 'merchant/category/getsub', - data={'cate_id': cate_id}, - result_processor=lambda x: x['cate_list'] + "merchant/category/getsub", + data={"cate_id": cate_id}, + result_processor=lambda x: x["cate_list"], ) return res def get_sku_list(self, cate_id): res = self._post( - 'merchant/category/getsku', - data={'cate_id': cate_id}, - result_processor=lambda x: x['sku_table'] + "merchant/category/getsku", + data={"cate_id": cate_id}, + result_processor=lambda x: x["sku_table"], ) return res def get_properties(self, cate_id): res = self._post( - 'merchant/category/getproperty', - data={'cate_id': cate_id}, - result_processor=lambda x: x['properties'] + "merchant/category/getproperty", + data={"cate_id": cate_id}, + result_processor=lambda x: x["properties"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/common.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/common.py index e1d3323..2700e77 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/common.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/common.py @@ -5,15 +5,13 @@ class MerchantCommon(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def upload_image(self, filename, image_data): res = self._post( - 'merchant/common/upload_img', - params={ - 'filename': filename - }, + "merchant/common/upload_img", + params={"filename": filename}, data=image_data, - result_processor=lambda x: x['image_url'] + result_processor=lambda x: x["image_url"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/express.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/express.py index e6e2e5c..488e05d 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/express.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/express.py @@ -5,46 +5,32 @@ class MerchantExpress(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, delivery_template): return self._post( - 'merchant/express/add', - data={ - 'delivery_template': delivery_template - } + "merchant/express/add", data={"delivery_template": delivery_template} ) def delete(self, template_id): - return self._post( - 'merchant/express/del', - data={ - 'template_id': template_id - } - ) + return self._post("merchant/express/del", data={"template_id": template_id}) def update(self, template_id, delivery_template): return self._post( - 'merchant/express/update', - data={ - 'template_id': template_id, - 'delivery_template': delivery_template - } + "merchant/express/update", + data={"template_id": template_id, "delivery_template": delivery_template}, ) def get(self, template_id): res = self._post( - 'merchant/express/getbyid', - data={ - 'template_id': template_id - }, - result_processor=lambda x: x['template_info'] + "merchant/express/getbyid", + data={"template_id": template_id}, + result_processor=lambda x: x["template_info"], ) return res def get_all(self): res = self._get( - 'merchant/express/getall', - result_processor=lambda x: x['template_info'] + "merchant/express/getall", result_processor=lambda x: x["template_info"] ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/group.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/group.py index acaf1df..02c17d6 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/group.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/group.py @@ -5,58 +5,38 @@ class MerchantGroup(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, product_list): return self._post( - 'merchant/group/add', - data={ - 'group_detail': { - 'group_name': name, - 'product_list': product_list - } - } + "merchant/group/add", + data={"group_detail": {"group_name": name, "product_list": product_list}}, ) def delete(self, group_id): - return self._post( - 'merchant/group/del', - data={ - 'group_id': group_id - } - ) + return self._post("merchant/group/del", data={"group_id": group_id}) def update(self, group_id, name): return self._post( - 'merchant/group/propertymod', - data={ - 'group_id': group_id, - 'group_name': name - } + "merchant/group/propertymod", + data={"group_id": group_id, "group_name": name}, ) def update_product(self, group_id, product): return self._post( - 'merchant/group/productmod', - data={ - 'group_id': group_id, - 'product': product - } + "merchant/group/productmod", data={"group_id": group_id, "product": product} ) def get_all(self): res = self._get( - 'merchant/group/getall', - result_processor=lambda x: x['groups_detail'] + "merchant/group/getall", result_processor=lambda x: x["groups_detail"] ) return res def get(self, group_id): res = self._post( - 'merchant/group/getbyid', - data={ - 'group_id': group_id - }, - result_processor=lambda x: x['group_detail'] + "merchant/group/getbyid", + data={"group_id": group_id}, + result_processor=lambda x: x["group_detail"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/order.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/order.py index 7e49412..7938633 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/order.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/order.py @@ -6,49 +6,39 @@ class MerchantOrder(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def get(self, order_id): res = self._post( - 'merchant/order/getbyid', - data={ - 'order_id': order_id - }, - result_processor=lambda x: x['order'] + "merchant/order/getbyid", + data={"order_id": order_id}, + result_processor=lambda x: x["order"], ) return res def get_by_filter(self, status=None, begin_time=None, end_time=None): filter_dict = optionaldict( - status=status, - begintime=begin_time, - endtime=end_time + status=status, begintime=begin_time, endtime=end_time ) res = self._post( - 'merchant/order/getbyfilter', + "merchant/order/getbyfilter", data=dict(filter_dict), - result_processor=lambda x: x['order_list'] + result_processor=lambda x: x["order_list"], ) return res - def set_delivery(self, order_id, company, track_no, - need_delivery=1, is_others=0): + def set_delivery(self, order_id, company, track_no, need_delivery=1, is_others=0): return self._post( - 'merchant/order/setdelivery', + "merchant/order/setdelivery", data={ - 'order_id': order_id, - 'delivery_company': company, - 'delivery_track_no': track_no, - 'need_delivery': need_delivery, - 'is_others': is_others - } + "order_id": order_id, + "delivery_company": company, + "delivery_track_no": track_no, + "need_delivery": need_delivery, + "is_others": is_others, + }, ) def close(self, order_id): - return self._post( - 'merchant/order/close', - data={ - 'order_id': order_id - } - ) + return self._post("merchant/order/close", data={"order_id": order_id}) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/shelf.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/shelf.py index afca61f..b6dc2a8 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/shelf.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/shelf.py @@ -5,48 +5,33 @@ class MerchantShelf(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def add(self, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', - data={ - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "merchant/shelf/add", + data={"shelf_name": name, "shelf_banner": banner, "shelf_data": shelf_data}, ) def delete(self, shelf_id): - return self._post( - 'merchant/shelf/del', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/del", data={"shelf_id": shelf_id}) def update(self, shelf_id, name, banner, shelf_data): return self._post( - 'merchant/shelf/add', + "merchant/shelf/add", data={ - 'shelf_id': shelf_id, - 'shelf_name': name, - 'shelf_banner': banner, - 'shelf_data': shelf_data - } + "shelf_id": shelf_id, + "shelf_name": name, + "shelf_banner": banner, + "shelf_data": shelf_data, + }, ) def get_all(self): res = self._get( - 'merchant/shelf/getall', - result_processor=lambda x: x['shelves'] + "merchant/shelf/getall", result_processor=lambda x: x["shelves"] ) return res def get(self, shelf_id): - return self._post( - 'merchant/shelf/getbyid', - data={ - 'shelf_id': shelf_id - } - ) + return self._post("merchant/shelf/getbyid", data={"shelf_id": shelf_id}) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/merchant/stock.py b/chapter14/booking_system/exts/wechatpy/client/api/merchant/stock.py index b2a6b1c..295eddb 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/merchant/stock.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/merchant/stock.py @@ -5,24 +5,16 @@ class MerchantStock(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" - def add(self, product_id, quantity, sku_info=''): + def add(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/add', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/add", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) - def reduce(self, product_id, quantity, sku_info=''): + def reduce(self, product_id, quantity, sku_info=""): return self._post( - 'merchant/stock/reduce', - data={ - 'product_id': product_id, - 'quantity': quantity, - 'sku_info': sku_info - } + "merchant/stock/reduce", + data={"product_id": product_id, "quantity": quantity, "sku_info": sku_info}, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/message.py b/chapter14/booking_system/exts/wechatpy/client/api/message.py index 8dacb07..c418a02 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/message.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/message.py @@ -12,16 +12,13 @@ class WeChatMessage(BaseWeChatAPI): - OPENID_RE = re.compile(r'^[\w\-]{28}$', re.I) + OPENID_RE = re.compile(r"^[\w\-]{28}$", re.I) def _send_custom_message(self, data, account=None): data = data or {} if account: - data['customservice'] = {'kf_account': account} - return self._post( - 'message/custom/send', - data=data - ) + data["customservice"] = {"kf_account": account} + return self._post("message/custom/send", data=data) def send_text(self, user_id, content, account=None): """ @@ -43,11 +40,7 @@ def send_text(self, user_id, content, account=None): res = client.message.send_text('openid', 'text') """ - data = { - 'touser': user_id, - 'msgtype': 'text', - 'text': {'content': content} - } + data = {"touser": user_id, "msgtype": "text", "text": {"content": content}} return self._send_custom_message(data, account=account) def send_image(self, user_id, media_id, account=None): @@ -70,13 +63,7 @@ def send_image(self, user_id, media_id, account=None): res = client.message.send_image('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'image', - 'image': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "image", "image": {"media_id": media_id}} return self._send_custom_message(data, account=account) def send_voice(self, user_id, media_id, account=None): @@ -99,17 +86,10 @@ def send_voice(self, user_id, media_id, account=None): res = client.message.send_voice('openid', 'media_id') """ - data = { - 'touser': user_id, - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - } - } + data = {"touser": user_id, "msgtype": "voice", "voice": {"media_id": media_id}} return self._send_custom_message(data, account=account) - def send_video(self, user_id, media_id, title=None, - description=None, account=None): + def send_video(self, user_id, media_id, title=None, description=None, account=None): """ 发送视频消息 @@ -131,22 +111,26 @@ def send_video(self, user_id, media_id, title=None, res = client.message.send_video('openid', 'media_id', 'title', 'description') """ video_data = { - 'media_id': media_id, + "media_id": media_id, } if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'video', - 'video': video_data - } + data = {"touser": user_id, "msgtype": "video", "video": video_data} return self._send_custom_message(data, account=account) - def send_music(self, user_id, url, hq_url, thumb_media_id, - title=None, description=None, account=None): + def send_music( + self, + user_id, + url, + hq_url, + thumb_media_id, + title=None, + description=None, + account=None, + ): """ 发送音乐消息 @@ -163,20 +147,16 @@ def send_music(self, user_id, url, hq_url, thumb_media_id, :return: 返回的 JSON 数据包 """ music_data = { - 'musicurl': url, - 'hqmusicurl': hq_url, - 'thumb_media_id': thumb_media_id + "musicurl": url, + "hqmusicurl": hq_url, + "thumb_media_id": thumb_media_id, } if title: - music_data['title'] = title + music_data["title"] = title if description: - music_data['description'] = description + music_data["description"] = description - data = { - 'touser': user_id, - 'msgtype': 'music', - 'music': music_data - } + data = {"touser": user_id, "msgtype": "music", "music": music_data} return self._send_custom_message(data, account=account) def send_articles(self, user_id, articles, account=None): @@ -194,26 +174,26 @@ def send_articles(self, user_id, articles, account=None): if isinstance(articles, (tuple, list)): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article.get('image', article.get('picurl')), - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article.get("image", article.get("picurl")), + } + ) data = { - 'touser': user_id, - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } + "touser": user_id, + "msgtype": "news", + "news": {"articles": articles_data}, } else: data = { - 'touser': user_id, - 'msgtype': 'mpnews', - 'mpnews': { - 'media_id': articles, - } + "touser": user_id, + "msgtype": "mpnews", + "mpnews": { + "media_id": articles, + }, } return self._send_custom_message(data, account=account) @@ -231,14 +211,14 @@ def send_card(self, user_id, card_id, card_ext=None, account=None): :return: 返回的 JSON 数据包 """ wxcard = { - 'card_id': card_id, + "card_id": card_id, } if card_ext: - wxcard['card_ext'] = card_ext + wxcard["card_ext"] = card_ext data = { - 'touser': user_id, - 'msgtype': 'wxcard', - 'wxcard': wxcard, + "touser": user_id, + "msgtype": "wxcard", + "wxcard": wxcard, } return self._send_custom_message(data, account=account) @@ -254,9 +234,9 @@ def send_mini_program_page(self, user_id, miniprogrampage, account=None): :return: 返回的 JSON 数据包 """ data = { - 'touser': user_id, - 'msgtype': 'miniprogrampage', - 'miniprogrampage': miniprogrampage + "touser": user_id, + "msgtype": "miniprogrampage", + "miniprogrampage": miniprogrampage, } return self._send_custom_message(data, account=account) @@ -278,55 +258,60 @@ def delete_mass(self, msg_id): res = client.message.delete_mass('message id') """ - return self._post( - 'message/mass/delete', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/delete", data={"msg_id": msg_id}) - def _send_mass_message(self, group_or_users, msg_type, msg, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def _send_mass_message( + self, + group_or_users, + msg_type, + msg, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): data = { - 'msgtype': msg_type, - 'send_ignore_reprint': send_ignore_reprint, + "msgtype": msg_type, + "send_ignore_reprint": send_ignore_reprint, } if client_msg_id is not None: - data['clientmsgid'] = client_msg_id + data["clientmsgid"] = client_msg_id if not preview: if isinstance(group_or_users, (tuple, list)): # send by order ids - data['touser'] = group_or_users - endpoint = 'message/mass/send' + data["touser"] = group_or_users + endpoint = "message/mass/send" else: # send by group id - data['filter'] = { - 'group_id': group_or_users, - 'is_to_all': is_to_all, + data["filter"] = { + "group_id": group_or_users, + "is_to_all": is_to_all, } - endpoint = 'message/mass/sendall' + endpoint = "message/mass/sendall" else: if not isinstance(group_or_users, six.string_types): - raise ValueError('group_or_users should be string types') + raise ValueError("group_or_users should be string types") # 预览接口 if self.OPENID_RE.match(group_or_users): # 按照 openid 预览群发 - data['touser'] = group_or_users + data["touser"] = group_or_users else: # 按照微信号预览群发 - data['towxname'] = group_or_users - endpoint = 'message/mass/preview' + data["towxname"] = group_or_users + endpoint = "message/mass/preview" data.update(msg) - return self._post( - endpoint, - data=data - ) - - def send_mass_text(self, group_or_users, content, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + return self._post(endpoint, data=data) + + def send_mass_text( + self, + group_or_users, + content, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发文本消息 @@ -353,21 +338,23 @@ def send_mass_text(self, group_or_users, content, """ return self._send_mass_message( group_or_users, - 'text', - { - 'text': { - 'content': content - } - }, + "text", + {"text": {"content": content}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_image(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_image( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图片消息 @@ -394,21 +381,23 @@ def send_mass_image(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'image', - { - 'image': { - 'media_id': media_id - } - }, + "image", + {"image": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_voice(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_voice( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发语音消息 @@ -435,21 +424,25 @@ def send_mass_voice(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'voice', - { - 'voice': { - 'media_id': media_id - } - }, + "voice", + {"voice": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_video(self, group_or_users, media_id, title=None, - description=None, is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_video( + self, + group_or_users, + media_id, + title=None, + description=None, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发视频消息 @@ -476,28 +469,30 @@ def send_mass_video(self, group_or_users, media_id, title=None, :return: 返回的 JSON 数据包 """ - video_data = { - 'media_id': media_id - } + video_data = {"media_id": media_id} if title: - video_data['title'] = title + video_data["title"] = title if description: - video_data['description'] = description + video_data["description"] = description return self._send_mass_message( group_or_users, - 'mpvideo', - { - 'mpvideo': video_data - }, + "mpvideo", + {"mpvideo": video_data}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def send_mass_article(self, group_or_users, media_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_article( + self, + group_or_users, + media_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发图文消息 @@ -524,12 +519,8 @@ def send_mass_article(self, group_or_users, media_id, """ return self._send_mass_message( group_or_users, - 'mpnews', - { - 'mpnews': { - 'media_id': media_id - } - }, + "mpnews", + {"mpnews": {"media_id": media_id}}, is_to_all, preview, send_ignore_reprint, @@ -554,14 +545,11 @@ def get_mass(self, msg_id): res = client.message.get_mass('mass message id') """ - return self._post( - 'message/mass/get', - data={ - 'msg_id': msg_id - } - ) + return self._post("message/mass/get", data={"msg_id": msg_id}) - def send_template(self, to_user_openid, template_id, data, url=None, mini_program=None): + def send_template( + self, to_user_openid, template_id, data, url=None, mini_program=None + ): """ 发送模板消息 @@ -582,10 +570,7 @@ def send_template(self, to_user_openid, template_id, data, url=None, mini_progra miniprogram=mini_program, data=data, ) - return self._post( - 'message/template/send', - data=tpl_data - ) + return self._post("message/template/send", data=tpl_data) def get_autoreply_info(self): """ @@ -604,11 +589,17 @@ def get_autoreply_info(self): info = client.message.get_autoreply_info() """ - return self._get('get_current_autoreply_info') + return self._get("get_current_autoreply_info") - def send_mass_card(self, group_or_users, card_id, - is_to_all=False, preview=False, - send_ignore_reprint=0, client_msg_id=None): + def send_mass_card( + self, + group_or_users, + card_id, + is_to_all=False, + preview=False, + send_ignore_reprint=0, + client_msg_id=None, + ): """ 群发卡券消息 @@ -635,19 +626,17 @@ def send_mass_card(self, group_or_users, card_id, """ return self._send_mass_message( group_or_users, - 'wxcard', - { - 'wxcard': { - 'card_id': card_id - } - }, + "wxcard", + {"wxcard": {"card_id": card_id}}, is_to_all, preview, send_ignore_reprint, client_msg_id, ) - def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved=None): + def get_subscribe_authorize_url( + self, scene, template_id, redirect_url, reserved=None + ): """ 构造请求用户授权的url 详情请参阅: @@ -661,20 +650,24 @@ def get_subscribe_authorize_url(self, scene, template_id, redirect_url, reserved """ if reserved is None: reserved = random_string() - base_url = 'https://mp.weixin.qq.com/mp/subscribemsg' + base_url = "https://mp.weixin.qq.com/mp/subscribemsg" params = [ - ('action', 'get_confirm'), - ('appid', self.appid), - ('scene', scene), - ('template_id', template_id), - ('redirect_url', redirect_url), - ('reserved', reserved), + ("action", "get_confirm"), + ("appid", self.appid), + ("scene", scene), + ("template_id", template_id), + ("redirect_url", redirect_url), + ("reserved", reserved), ] encoded_params = six.moves.urllib.parse.urlencode(params) - url = '{base}?{params}#wechat_redirect'.format(base=base_url, params=encoded_params) + url = "{base}?{params}#wechat_redirect".format( + base=base_url, params=encoded_params + ) return url - def send_subscribe_template(self, openid, template_id, scene, title, data, url=None): + def send_subscribe_template( + self, openid, template_id, scene, title, data, url=None + ): """ 一次性订阅消息,通过API推送订阅模板消息给到授权微信用户。 详情请参阅: @@ -690,16 +683,16 @@ def send_subscribe_template(self, openid, template_id, scene, title, data, url=N :param url: 点击消息跳转的链接,需要有ICP备案 """ post_data = { - 'touser': openid, - 'template_id': template_id, - 'url': url, - 'scene': scene, - 'title': title, - 'data': data, + "touser": openid, + "template_id": template_id, + "url": url, + "scene": scene, + "title": title, + "data": data, } if url is not None: - post_data['url'] = url + post_data["url"] = url return self._post( - 'message/template/subscribe', + "message/template/subscribe", data=post_data, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/misc.py b/chapter14/booking_system/exts/wechatpy/client/api/misc.py index 8a8f996..a6eacb6 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/misc.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/misc.py @@ -23,11 +23,7 @@ def short_url(self, long_url): """ return self._post( - 'shorturl', - data={ - 'action': 'long2short', - 'long_url': long_url - } + "shorturl", data={"action": "long2short", "long_url": long_url} ) def get_wechat_ips(self): @@ -44,8 +40,5 @@ def get_wechat_ips(self): ips = client.misc.get_wechat_ips() """ - res = self._get( - 'getcallbackip', - result_processor=lambda x: x['ip_list'] - ) + res = self._get("getcallbackip", result_processor=lambda x: x["ip_list"]) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/poi.py b/chapter14/booking_system/exts/wechatpy/client/api/poi.py index 0acfb7d..6bceefd 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/poi.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/poi.py @@ -15,7 +15,7 @@ def add(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/addpoi', data=poi_data) + return self._post("poi/addpoi", data=poi_data) def get(self, poi_id): """ @@ -27,7 +27,7 @@ def get(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/getpoi', data={'poi_id': poi_id}) + return self._post("poi/getpoi", data={"poi_id": poi_id}) def list(self, begin=0, limit=20): """ @@ -41,11 +41,11 @@ def list(self, begin=0, limit=20): :return: 返回的 JSON 数据包 """ return self._post( - 'poi/getpoilist', + "poi/getpoilist", data={ - 'begin': begin, - 'limit': limit, - } + "begin": begin, + "limit": limit, + }, ) def update(self, poi_data): @@ -58,7 +58,7 @@ def update(self, poi_data): :param poi_data: 门店信息字典 :return: 返回的 JSON 数据包 """ - return self._post('poi/updatepoi', data=poi_data) + return self._post("poi/updatepoi", data=poi_data) def delete(self, poi_id): """ @@ -70,7 +70,7 @@ def delete(self, poi_id): :param poi_id: 门店 ID :return: 返回的 JSON 数据包 """ - return self._post('poi/delpoi', data={'poi_id': poi_id}) + return self._post("poi/delpoi", data={"poi_id": poi_id}) def get_categories(self): """ @@ -82,7 +82,6 @@ def get_categories(self): :return: 门店类目表 """ res = self._get( - 'api_getwxcategory', - result_processor=lambda x: x['category_list'] + "api_getwxcategory", result_processor=lambda x: x["category_list"] ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/qrcode.py b/chapter14/booking_system/exts/wechatpy/client/api/qrcode.py index 51b7af1..07dcc9b 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/qrcode.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/qrcode.py @@ -38,10 +38,7 @@ def create(self, qrcode_data): }) """ - return self._post( - 'qrcode/create', - data=qrcode_data - ) + return self._post("qrcode/create", data=qrcode_data) def show(self, ticket): """ @@ -61,12 +58,9 @@ def show(self, ticket): """ if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] return requests.get( - url='https://mp.weixin.qq.com/cgi-bin/showqrcode', - params={ - 'ticket': ticket - } + url="https://mp.weixin.qq.com/cgi-bin/showqrcode", params={"ticket": ticket} ) @classmethod @@ -87,8 +81,8 @@ def get_url(cls, ticket): url = client.qrcode.get_url('ticket data') """ - url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}' + url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ticket}" if isinstance(ticket, dict): - ticket = ticket['ticket'] + ticket = ticket["ticket"] ticket = six.moves.urllib.parse.quote(ticket) return url.format(ticket=ticket) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/scan.py b/chapter14/booking_system/exts/wechatpy/client/api/scan.py index c7a1589..1fb2d4a 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/scan.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/scan.py @@ -6,7 +6,7 @@ class WeChatScan(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/scan/' + API_BASE_URL = "https://api.weixin.qq.com/scan/" def get_merchant_info(self): """ @@ -24,7 +24,7 @@ def get_merchant_info(self): client = WeChatClient('appid', 'secret') info = client.scan.get_merchant_info() """ - return self._get('merchantinfo/get') + return self._get("merchantinfo/get") def create_product(self, product_data): """ @@ -35,7 +35,7 @@ def create_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/create', data=product_data) + return self._post("product/create", data=product_data) def modify_product_status(self, standard, key, status): """ @@ -50,11 +50,11 @@ def modify_product_status(self, standard, key, status): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, - 'status': status, + "keystandard": standard, + "keystr": key, + "status": status, } - return self._post('product/modstatus', data=data) + return self._post("product/modstatus", data=data) def publish_product(self, standard, key): """ @@ -62,7 +62,7 @@ def publish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'on')`` """ - return self.modify_product_status(standard, key, 'on') + return self.modify_product_status(standard, key, "on") def unpublish_product(self, standard, key): """ @@ -70,7 +70,7 @@ def unpublish_product(self, standard, key): 等同于调用 ``modify_product_status(standard, key, 'off')`` """ - return self.modify_product_status(standard, key, 'off') + return self.modify_product_status(standard, key, "off") def set_test_whitelist(self, userids=None, usernames=None): """ @@ -85,11 +85,8 @@ def set_test_whitelist(self, userids=None, usernames=None): :param usernames: 可选,测试人员的微信号列表 :return: 返回的 JSON 数据包 """ - data = optionaldict( - openid=userids, - username=usernames - ) - return self._post('testwhitelist/set', data=data) + data = optionaldict(openid=userids, username=usernames) + return self._post("testwhitelist/set", data=data) def get_product(self, standard, key): """ @@ -103,10 +100,10 @@ def get_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/get', data=data) + return self._post("product/get", data=data) def list_product(self, offset=0, limit=10, status=None, key=None): """ @@ -128,7 +125,7 @@ def list_product(self, offset=0, limit=10, status=None, key=None): status=status, keystr=key, ) - return self._post('product/getlist', data=data) + return self._post("product/getlist", data=data) def update_product(self, product_data): """ @@ -139,7 +136,7 @@ def update_product(self, product_data): :return: 返回的 JSON 数据包 """ - return self._post('product/update', data=product_data) + return self._post("product/update", data=product_data) def clear_product(self, standard, key): """ @@ -153,10 +150,10 @@ def clear_product(self, standard, key): :return: 返回的 JSON 数据包 """ data = { - 'keystandard': standard, - 'keystr': key, + "keystandard": standard, + "keystr": key, } - return self._post('product/clear', data=data) + return self._post("product/clear", data=data) def check_ticket(self, ticket): """ @@ -168,4 +165,4 @@ def check_ticket(self, ticket): :param ticket: 请求 URL 中带上的 wxticket 参数 :return: 返回的 JSON 数据包 """ - return self._post('scanticket/check', data={'ticket': ticket}) + return self._post("scanticket/check", data={"ticket": ticket}) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/semantic.py b/chapter14/booking_system/exts/wechatpy/client/api/semantic.py index 73325ed..4a234eb 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/semantic.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/semantic.py @@ -7,14 +7,16 @@ class WeChatSemantic(BaseWeChatAPI): - def search(self, - query, - category, - uid=None, - latitude=None, - longitude=None, - city=None, - region=None): + def search( + self, + query, + category, + uid=None, + latitude=None, + longitude=None, + city=None, + region=None, + ): """ 发送语义理解请求 详情请参考 @@ -42,18 +44,17 @@ def search(self, """ if isinstance(category, (tuple, list)): - category = ','.join(category) + category = ",".join(category) data = optionaldict() - data['query'] = query - data['category'] = category - data['uid'] = uid - data['latitude'] = latitude - data['longitude'] = longitude - data['city'] = city - data['region'] = region - data['appid'] = self._client.appid + data["query"] = query + data["category"] = category + data["uid"] = uid + data["latitude"] = latitude + data["longitude"] = longitude + data["city"] = city + data["region"] = region + data["appid"] = self._client.appid return self._post( - url='https://api.weixin.qq.com/semantic/semproxy/search', - data=data + url="https://api.weixin.qq.com/semantic/semproxy/search", data=data ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/shakearound.py b/chapter14/booking_system/exts/wechatpy/client/api/shakearound.py index cca5ba7..52fdb37 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/shakearound.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/shakearound.py @@ -11,12 +11,12 @@ class WeChatShakeAround(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" @classmethod def _to_timestamp(cls, date): if isinstance(date, six.string_types): - date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S') + date = datetime.strptime(date, "%Y-%m-%d %H:%M:%S") if isinstance(date, datetime): timestamp = int(time.mktime(date.timetuple())) return timestamp @@ -35,19 +35,20 @@ def apply_device_id(self, quantity, reason, poi_id=None, comment=None): :return: 申请的设备信息 """ data = optionaldict() - data['quantity'] = quantity - data['apply_reason'] = reason - data['poi_id'] = poi_id - data['comment'] = comment + data["quantity"] = quantity + data["apply_reason"] = reason + data["poi_id"] = poi_id + data["comment"] = comment res = self._post( - 'shakearound/device/applyid', + "shakearound/device/applyid", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res - def update_device(self, device_id=None, uuid=None, major=None, - minor=None, comment=None): + def update_device( + self, device_id=None, uuid=None, major=None, minor=None, comment=None + ): """ 更新设备信息 详情请参考 @@ -61,20 +62,18 @@ def update_device(self, device_id=None, uuid=None, major=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['comment'] = comment - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["comment"] = comment + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/update', - data=data - ) + return self._post("shakearound/device/update", data=data) - def bind_device_location(self, poi_id, device_id=None, uuid=None, - major=None, minor=None): + def bind_device_location( + self, poi_id, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与门店的关联关系 详情请参考 @@ -88,20 +87,16 @@ def bind_device_location(self, poi_id, device_id=None, uuid=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['poi_id'] = poi_id - data['device_identifier'] = { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + data["poi_id"] = poi_id + data["device_identifier"] = { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, } - return self._post( - 'shakearound/device/bindlocation', - data=data - ) + return self._post("shakearound/device/bindlocation", data=data) - def search_device(self, identifiers=None, apply_id=None, - begin=0, count=10): + def search_device(self, identifiers=None, apply_id=None, begin=0, count=10): """ 查询设备列表 详情请参考 @@ -114,15 +109,13 @@ def search_device(self, identifiers=None, apply_id=None, :return: 设备列表 """ data = optionaldict() - data['begin'] = begin - data['count'] = count - data['apply_id'] = apply_id + data["begin"] = begin + data["count"] = count + data["apply_id"] = apply_id if identifiers: - data['device_identifiers'] = identifiers + data["device_identifiers"] = identifiers res = self._post( - 'shakearound/device/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/device/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -141,20 +134,19 @@ def add_page(self, title, description, icon_url, page_url, comment=None): :return: 页面信息 """ data = optionaldict() - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/add', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/add", data=data, result_processor=lambda x: x["data"] ) return res - def update_page(self, page_id, title, description, - icon_url, page_url, comment=None): + def update_page( + self, page_id, title, description, icon_url, page_url, comment=None + ): """ 编辑页面信息 详情请参考 @@ -170,16 +162,14 @@ def update_page(self, page_id, title, description, :return: 页面信息 """ data = optionaldict() - data['page_id'] = page_id - data['title'] = title - data['description'] = description - data['icon_url'] = icon_url - data['page_url'] = page_url - data['comment'] = comment + data["page_id"] = page_id + data["title"] = title + data["description"] = description + data["icon_url"] = icon_url + data["page_url"] = page_url + data["comment"] = comment res = self._post( - 'shakearound/page/update', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/update", data=data, result_processor=lambda x: x["data"] ) return res @@ -195,23 +185,14 @@ def search_pages(self, page_ids=None, begin=0, count=10): :return: 页面查询结果信息 """ if not page_ids: - data = { - 'type': 2, - 'begin': begin, - 'count': count - } + data = {"type": 2, "begin": begin, "count": count} else: if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] - data = { - 'type': 1, - 'page_ids': page_ids - } + data = {"type": 1, "page_ids": page_ids} res = self._post( - 'shakearound/page/search', - data=data, - result_processor=lambda x: x['data'] + "shakearound/page/search", data=data, result_processor=lambda x: x["data"] ) return res @@ -224,14 +205,9 @@ def delete_page(self, page_id): :param page_id: 指定页面的id列表 :return: 返回的 JSON 数据包 """ - return self._post( - 'shakearound/page/delete', - data={ - 'page_id': page_id - } - ) + return self._post("shakearound/page/delete", data={"page_id": page_id}) - def add_material(self, media_file, media_type='icon'): + def add_material(self, media_file, media_type="icon"): """ 上传图片素材 详情请参考 @@ -242,19 +218,16 @@ def add_material(self, media_file, media_type='icon'): :return: 上传的素材信息 """ res = self._post( - 'shakearound/material/add', - files={ - 'media': media_file - }, - params={ - 'type': media_type - }, - result_processor=lambda x: x['data'] + "shakearound/material/add", + files={"media": media_file}, + params={"type": media_type}, + result_processor=lambda x: x["data"], ) return res - def bind_device_pages(self, page_ids, bind, append, device_id=None, - uuid=None, major=None, minor=None): + def bind_device_pages( + self, page_ids, bind, append, device_id=None, uuid=None, major=None, minor=None + ): """ 配置设备与页面的关联关系 详情请参考 @@ -272,20 +245,17 @@ def bind_device_pages(self, page_ids, bind, append, device_id=None, if not isinstance(page_ids, (tuple, list)): page_ids = [page_ids] data = { - 'page_ids': page_ids, - 'bind': int(bind), - 'append': int(append), - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor - } + "page_ids": page_ids, + "bind": int(bind), + "append": int(append), + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, + }, } - return self._post( - 'shakearound/device/bindpage', - data=data - ) + return self._post("shakearound/device/bindpage", data=data) def get_shake_info(self, ticket): """ @@ -297,16 +267,15 @@ def get_shake_info(self, ticket): :return: 设备及用户信息 """ res = self._post( - 'shakearound/order/getshakeinfo', - data={ - 'ticket': ticket - }, - result_processor=lambda x: x['data'] + "shakearound/order/getshakeinfo", + data={"ticket": ticket}, + result_processor=lambda x: x["data"], ) return res - def get_device_statistics(self, begin_date, end_date, device_id=None, - uuid=None, major=None, minor=None): + def get_device_statistics( + self, begin_date, end_date, device_id=None, uuid=None, major=None, minor=None + ): """ 以设备为维度的数据统计接口 http://mp.weixin.qq.com/wiki/0/8a24bcacad40fe7ee98d1573cb8a6764.html @@ -319,19 +288,19 @@ def get_device_statistics(self, begin_date, end_date, device_id=None, :param minor: minor """ data = { - 'device_identifier': { - 'device_id': device_id, - 'uuid': uuid, - 'major': major, - 'minor': minor + "device_identifier": { + "device_id": device_id, + "uuid": uuid, + "major": major, + "minor": minor, }, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date) + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), } res = self._post( - 'shakearound/statistics/device', + "shakearound/statistics/device", data=data, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -347,13 +316,13 @@ def get_page_statistics(self, page_id, begin_date, end_date): :return: 统计数据 """ res = self._post( - 'shakearound/statistics/page', + "shakearound/statistics/page", data={ - 'page_id': page_id, - 'begin_date': self._to_timestamp(begin_date), - 'end_date': self._to_timestamp(end_date), + "page_id": page_id, + "begin_date": self._to_timestamp(begin_date), + "end_date": self._to_timestamp(end_date), }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -367,10 +336,10 @@ def get_apply_status(self, apply_id): :return: 批次状态信息 """ res = self._post( - 'shakearound/device/applystatus', + "shakearound/device/applystatus", data={ - 'apply_id': apply_id, + "apply_id": apply_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/tag.py b/chapter14/booking_system/exts/wechatpy/client/api/tag.py index 6c2a9aa..daf553d 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/tag.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/tag.py @@ -17,9 +17,9 @@ def create(self, name): """ name = to_text(name) return self._post( - 'tags/create', - data={'tag': {'name': name}}, - result_processor=lambda x: x['tag'] + "tags/create", + data={"tag": {"name": name}}, + result_processor=lambda x: x["tag"], ) def get(self): @@ -30,10 +30,7 @@ def get(self): """ - res = self._get( - 'tags/get', - result_processor=lambda x: x['tags'] - ) + res = self._get("tags/get", result_processor=lambda x: x["tags"]) return res @@ -48,13 +45,7 @@ def update(self, tag_id, name): """ name = to_text(name) return self._post( - 'tags/update', - data={ - 'tag': { - 'id': int(tag_id), - 'name': name - } - } + "tags/update", data={"tag": {"id": int(tag_id), "name": name}} ) def delete(self, tag_id): @@ -65,14 +56,7 @@ def delete(self, tag_id): :return: 返回的 JSON 数据包 """ - return self._post( - 'tags/delete', - data={ - 'tag': { - 'id': tag_id - } - } - ) + return self._post("tags/delete", data={"tag": {"id": tag_id}}) def tag_user(self, tag_id, user_id): """ @@ -84,12 +68,14 @@ def tag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchtagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchtagging", data=data) def untag_user(self, tag_id, user_id): """ @@ -101,12 +87,14 @@ def untag_user(self, tag_id, user_id): :return: 返回的 JSON 数据包 """ - data = {'tagid': tag_id} + data = {"tagid": tag_id} if isinstance(user_id, (tuple, list)): - data['openid_list'] = user_id + data["openid_list"] = user_id else: - data['openid_list'] = [user_id, ] - return self._post('tags/members/batchuntagging', data=data) + data["openid_list"] = [ + user_id, + ] + return self._post("tags/members/batchuntagging", data=data) def get_user_tag(self, user_id): """ @@ -116,11 +104,9 @@ def get_user_tag(self, user_id): :return: 返回的 JSON 数据包 """ return self._post( - 'tags/getidlist', - data={ - 'openid': user_id - }, - result_processor=lambda x: x['tagid_list'] + "tags/getidlist", + data={"openid": user_id}, + result_processor=lambda x: x["tagid_list"], ) def get_tag_users(self, tag_id, first_user_id=None): @@ -132,14 +118,11 @@ def get_tag_users(self, tag_id, first_user_id=None): :return: 返回的 JSON 数据包 """ data = { - 'tagid': tag_id, + "tagid": tag_id, } if first_user_id: - data['next_openid'] = first_user_id - return self._post( - 'order/tag/get', - data=data - ) + data["next_openid"] = first_user_id + return self._post("order/tag/get", data=data) def iter_tag_users(self, tag_id, first_user_id=None): """ @@ -158,11 +141,11 @@ def iter_tag_users(self, tag_id, first_user_id=None): """ while True: follower_data = self.get_tag_users(tag_id, first_user_id) - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid - first_user_id = follower_data.get('next_openid') + first_user_id = follower_data.get("next_openid") if not first_user_id: return @@ -178,9 +161,9 @@ def get_black_list(self, begin_openid=None): """ data = {} if begin_openid: - data['begin_openid'] = begin_openid + data["begin_openid"] = begin_openid return self._post( - 'tags/members/getblacklist', + "tags/members/getblacklist", data=data, ) @@ -194,9 +177,9 @@ def batch_black_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchblacklist', + "tags/members/batchblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) @@ -210,8 +193,8 @@ def batch_unblack_list(self, openid_list): :type openid_list: list """ return self._post( - 'tags/members/batchunblacklist', + "tags/members/batchunblacklist", data={ - 'openid_list': openid_list, + "openid_list": openid_list, }, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/template.py b/chapter14/booking_system/exts/wechatpy/client/api/template.py index 5d202da..01f9bbd 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/template.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/template.py @@ -17,11 +17,8 @@ def set_industry(self, industry_id1, industry_id2): :return: 返回的 JSON 数据包 """ return self._post( - 'template/api_set_industry', - data={ - 'industry_id1': industry_id1, - 'industry_id2': industry_id2 - } + "template/api_set_industry", + data={"industry_id1": industry_id1, "industry_id2": industry_id2}, ) def get_industry(self): @@ -32,9 +29,7 @@ def get_industry(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_industry' - ) + return self._get("template/get_industry") def get(self, template_id_short): """ @@ -46,11 +41,9 @@ def get(self, template_id_short): :return: 模板 ID """ res = self._post( - 'template/api_add_template', - data={ - 'template_id_short': template_id_short - }, - result_processor=lambda x: x['template_id'] + "template/api_add_template", + data={"template_id_short": template_id_short}, + result_processor=lambda x: x["template_id"], ) return res @@ -64,9 +57,7 @@ def get_all_private_template(self): :return: 返回的 JSON 数据包 """ - return self._get( - 'template/get_all_private_template' - ) + return self._get("template/get_all_private_template") def del_private_template(self, template_id): """ @@ -78,8 +69,5 @@ def del_private_template(self, template_id): :return: 返回的 JSON 数据包 """ return self._post( - 'template/del_private_template', - data={ - 'template_id': template_id - } + "template/del_private_template", data={"template_id": template_id} ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/user.py b/chapter14/booking_system/exts/wechatpy/client/api/user.py index 6e2a428..977310d 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/user.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/user.py @@ -8,7 +8,7 @@ class WeChatUser(BaseWeChatAPI): - def get(self, user_id, lang='zh_CN'): + def get(self, user_id, lang="zh_CN"): """ 获取用户基本信息(包括UnionID机制) 详情请参考 @@ -26,15 +26,13 @@ def get(self, user_id, lang='zh_CN'): order = client.order.get('openid') """ - assert lang in ('zh_CN', 'zh_TW', 'en'), 'lang can only be one of \ - zh_CN, zh_TW, en language codes' - return self._get( - 'order/info', - params={ - 'openid': user_id, - 'lang': lang - } - ) + assert lang in ( + "zh_CN", + "zh_TW", + "en", + ), "lang can only be one of \ + zh_CN, zh_TW, en language codes" + return self._get("order/info", params={"openid": user_id, "lang": lang}) def get_followers(self, first_user_id=None): """ @@ -56,11 +54,8 @@ def get_followers(self, first_user_id=None): """ params = {} if first_user_id: - params['next_openid'] = first_user_id - return self._get( - 'order/get', - params=params - ) + params["next_openid"] = first_user_id + return self._get("order/get", params=params) def iter_followers(self, first_user_id=None): """ @@ -86,9 +81,9 @@ def iter_followers(self, first_user_id=None): # 微信有个bug(或者叫feature),没有下一页,也返回next_openid这个字段 # 所以要通过total_count和data的长度比较判断(比较麻烦,并且不稳定) # 或者获得结果前先判断data是否存在 - if 'data' not in follower_data: + if "data" not in follower_data: return - for openid in follower_data['data']['openid']: + for openid in follower_data["data"]["openid"]: yield openid if not first_user_id: return @@ -113,11 +108,7 @@ def update_remark(self, user_id, remark): """ return self._post( - 'order/info/updateremark', - data={ - 'openid': user_id, - 'remark': remark - } + "order/info/updateremark", data={"openid": user_id, "remark": remark} ) def get_group_id(self, user_id): @@ -139,9 +130,9 @@ def get_group_id(self, user_id): """ res = self._post( - 'groups/getid', - data={'openid': user_id}, - result_processor=lambda x: x['groupid'] + "groups/getid", + data={"openid": user_id}, + result_processor=lambda x: x["groupid"], ) return res @@ -169,16 +160,16 @@ def get_batch(self, user_list): """ if all((isinstance(x, six.string_types) for x in user_list)): - user_list = [{'openid': oid} for oid in user_list] + user_list = [{"openid": oid} for oid in user_list] res = self._post( - 'order/info/batchget', - data={'user_list': user_list}, - result_processor=lambda x: x['user_info_list'] + "order/info/batchget", + data={"user_list": user_list}, + result_processor=lambda x: x["user_info_list"], ) return res def change_openid(self, from_appid, openid_list): - '''微信公众号主体变更迁移用户 openid + """微信公众号主体变更迁移用户 openid 详情请参考 http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html @@ -186,9 +177,9 @@ def change_openid(self, from_appid, openid_list): :param from_appid: 原公众号的 appid :param openid_list: 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 :return: 转换后的 openid 信息列表 - ''' + """ return self._post( - 'changeopenid', - data={'from_appid': from_appid, 'openid_list': openid_list}, - result_processor=lambda x: x['result_list'] + "changeopenid", + data={"from_appid": from_appid, "openid_list": openid_list}, + result_processor=lambda x: x["result_list"], ) diff --git a/chapter14/booking_system/exts/wechatpy/client/api/wifi.py b/chapter14/booking_system/exts/wechatpy/client/api/wifi.py index 0852103..a513764 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/wifi.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/wifi.py @@ -8,7 +8,7 @@ class WeChatWiFi(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/bizwifi/' + API_BASE_URL = "https://api.weixin.qq.com/bizwifi/" def list_shops(self, page_index=1, page_size=20): """ @@ -22,12 +22,12 @@ def list_shops(self, page_index=1, page_size=20): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/list', + "shop/list", data={ - 'pageindex': page_index, - 'pagesize': page_size, + "pageindex": page_index, + "pagesize": page_size, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -40,11 +40,11 @@ def get_shop(self, shop_id=0): :return: 返回的 JSON 数据包 """ res = self._post( - 'shop/get', + "shop/get", data={ - 'shop_id': shop_id, + "shop_id": shop_id, }, - result_processor=lambda x: x['data'] + result_processor=lambda x: x["data"], ) return res @@ -63,13 +63,13 @@ def add_device(self, shop_id, ssid, password, bssid): :return: 返回的 JSON 数据包 """ return self._post( - 'device/add', + "device/add", data={ - 'shop_id': shop_id, - 'ssid': ssid, - 'password': password, - 'bssid': bssid, - } + "shop_id": shop_id, + "ssid": ssid, + "password": password, + "bssid": bssid, + }, ) def list_devices(self, shop_id=None, page_index=1, page_size=20): @@ -84,16 +84,8 @@ def list_devices(self, shop_id=None, page_index=1, page_size=20): :param page_size: 可选,每页的个数,默认20个,最大20个 :return: 返回的 JSON 数据包 """ - data = optionaldict( - shop_id=shop_id, - pageindex=page_index, - pagesize=page_size - ) - res = self._post( - 'device/list', - data=data, - result_processor=lambda x: x['data'] - ) + data = optionaldict(shop_id=shop_id, pageindex=page_index, pagesize=page_size) + res = self._post("device/list", data=data, result_processor=lambda x: x["data"]) return res def delete_device(self, bssid): @@ -106,7 +98,7 @@ def delete_device(self, bssid): :param bssid: 无线网络设备无线mac地址,格式冒号分隔,字符长度17个,并且字母小写 :return: 返回的 JSON 数据包 """ - return self._post('device/delete', data={'bssid': bssid}) + return self._post("device/delete", data={"bssid": bssid}) def get_qrcode_url(self, shop_id, img_id): """ @@ -121,12 +113,12 @@ def get_qrcode_url(self, shop_id, img_id): :return: 二维码图片网址 """ res = self._post( - 'qrcode/get', + "qrcode/get", data={ - 'shop_id': shop_id, - 'img_id': img_id, + "shop_id": shop_id, + "img_id": img_id, }, - result_processor=lambda x: x['data']['qrcode_url'] + result_processor=lambda x: x["data"]["qrcode_url"], ) return res @@ -143,12 +135,12 @@ def set_homepage(self, shop_id, template_id, url=None): :return: 返回的 JSON 数据包 """ data = { - 'shop_id': shop_id, - 'template_id': template_id, + "shop_id": shop_id, + "template_id": template_id, } if url: - data['struct'] = {'url': url} - return self._post('homepage/set', data=data) + data["struct"] = {"url": url} + return self._post("homepage/set", data=data) def get_homepage(self, shop_id): """ @@ -161,9 +153,9 @@ def get_homepage(self, shop_id): :return: 返回的 JSON 数据包 """ res = self._post( - 'homepage/get', - data={'shop_id': shop_id}, - result_processor=lambda x: x['data'] + "homepage/get", + data={"shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res @@ -180,16 +172,12 @@ def list_statistics(self, begin_date, end_date, shop_id=-1): :return: 返回的 JSON 数据包 """ if isinstance(begin_date, (datetime, date)): - begin_date = begin_date.strftime('%Y-%m-%d') + begin_date = begin_date.strftime("%Y-%m-%d") if isinstance(end_date, (datetime, date)): - end_date = end_date.strftime('%Y-%m-%d') + end_date = end_date.strftime("%Y-%m-%d") res = self._post( - 'statistics/list', - data={ - 'begin_date': begin_date, - 'end_date': end_date, - 'shop_id': shop_id - }, - result_processor=lambda x: x['data'] + "statistics/list", + data={"begin_date": begin_date, "end_date": end_date, "shop_id": shop_id}, + result_processor=lambda x: x["data"], ) return res diff --git a/chapter14/booking_system/exts/wechatpy/client/api/wxa.py b/chapter14/booking_system/exts/wechatpy/client/api/wxa.py index 1c44460..91077d3 100644 --- a/chapter14/booking_system/exts/wechatpy/client/api/wxa.py +++ b/chapter14/booking_system/exts/wechatpy/client/api/wxa.py @@ -7,7 +7,7 @@ class WeChatWxa(BaseWeChatAPI): - API_BASE_URL = 'https://api.weixin.qq.com/' + API_BASE_URL = "https://api.weixin.qq.com/" def create_qrcode(self, path, width=430): """ @@ -16,49 +16,49 @@ def create_qrcode(self, path, width=430): https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'cgi-bin/wxaapp/createwxaqrcode', - data={ - 'path': path, - 'width': width - } + "cgi-bin/wxaapp/createwxaqrcode", data={"path": path, "width": width} ) - def get_wxa_code(self, - path, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - is_hyaline=False): + def get_wxa_code( + self, + path, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + is_hyaline=False, + ): """ 创建小程序码(接口A: 适用于需要的码数量较少的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacode', + "wxa/getwxacode", data={ - 'path': path, - 'width': width, - 'auto_color': auto_color, - 'line_color': line_color, - 'is_hyaline': is_hyaline, - } + "path": path, + "width": width, + "auto_color": auto_color, + "line_color": line_color, + "is_hyaline": is_hyaline, + }, ) - def get_wxa_code_unlimited(self, - scene, - width=430, - auto_color=False, - line_color={"r": "0", "g": "0", "b": "0"}, - page=None, - is_hyaline=False): + def get_wxa_code_unlimited( + self, + scene, + width=430, + auto_color=False, + line_color={"r": "0", "g": "0", "b": "0"}, + page=None, + is_hyaline=False, + ): """ 创建小程序码(接口B:适用于需要的码数量极多,或仅临时使用的业务场景) 详情请参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html """ return self._post( - 'wxa/getwxacodeunlimit', + "wxa/getwxacodeunlimit", data=optionaldict( scene=scene, page=page, @@ -66,10 +66,19 @@ def get_wxa_code_unlimited(self, auto_color=auto_color, line_color=line_color, is_hyaline=is_hyaline, - ) + ), ) - def send_template_message(self, user_id, template_id, data, form_id, page=None, color=None, emphasis_keyword=None): + def send_template_message( + self, + user_id, + template_id, + data, + form_id, + page=None, + color=None, + emphasis_keyword=None, + ): """ 发送模板消息 详情请参考 @@ -84,12 +93,16 @@ def send_template_message(self, user_id, template_id, data, form_id, page=None, color=color, emphasis_keyword=emphasis_keyword, ) - return self._post( - 'cgi-bin/message/wxopen/template/send', - data=tpl_data - ) + return self._post("cgi-bin/message/wxopen/template/send", data=tpl_data) - def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_domain=(), download_domain=()): + def modify_domain( + self, + action, + request_domain=(), + wsrequest_domain=(), + upload_domain=(), + download_domain=(), + ): """ 修改小程序服务器授权域名 详情请参考 @@ -102,14 +115,14 @@ def modify_domain(self, action, request_domain=(), wsrequest_domain=(), upload_d :param download_domain: download file 合法域名 """ return self._post( - 'wxa/modify_domain', + "wxa/modify_domain", data={ - 'action': action, - 'requestdomain': request_domain, - 'wsrequestdomain': wsrequest_domain, - 'uploaddomain': upload_domain, - 'downloaddomain': download_domain, - } + "action": action, + "requestdomain": request_domain, + "wsrequestdomain": wsrequest_domain, + "uploaddomain": upload_domain, + "downloaddomain": download_domain, + }, ) def bind_tester(self, wechat_id): @@ -121,10 +134,10 @@ def bind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/bind_tester', + "wxa/bind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def unbind_tester(self, wechat_id): @@ -136,10 +149,10 @@ def unbind_tester(self, wechat_id): :param wechat_id: 微信号 """ return self._post( - 'wxa/unbind_tester', + "wxa/unbind_tester", data={ - 'wechatid': wechat_id, - } + "wechatid": wechat_id, + }, ) def commit(self, template_id, ext_json, version, description): @@ -154,12 +167,12 @@ def commit(self, template_id, ext_json, version, description): :param description: 代码描述,开发者可自定义 """ return self._post( - 'wxa/commit', + "wxa/commit", data={ - 'template_id': template_id, - 'ext_json': ext_json, - 'user_version': version, - 'user_desc': description, + "template_id": template_id, + "ext_json": ext_json, + "user_version": version, + "user_desc": description, }, ) @@ -172,7 +185,7 @@ def get_qrcode(self): :rtype: requests.Response """ - return self._get('wxa/get_qrcode') + return self._get("wxa/get_qrcode") def get_category(self): """ @@ -183,8 +196,8 @@ def get_category(self): :rtype: list[dict] """ return self._get( - 'wxa/get_category', - result_processor=lambda x: x['category_list'], + "wxa/get_category", + result_processor=lambda x: x["category_list"], ) def get_page(self): @@ -196,8 +209,8 @@ def get_page(self): :rtype: list """ return self._get( - 'wxa/get_page', - result_processor=lambda x: x['page_list'], + "wxa/get_page", + result_processor=lambda x: x["page_list"], ) def submit_audit(self, item_list): @@ -212,11 +225,11 @@ def submit_audit(self, item_list): :rtype: int """ return self._post( - 'wxa/submit_audit', + "wxa/submit_audit", data={ - 'item_list': item_list, + "item_list": item_list, }, - result_processor=lambda x: x['auditid'], + result_processor=lambda x: x["auditid"], ) def get_audit_status(self, auditid): @@ -230,9 +243,9 @@ def get_audit_status(self, auditid): :return: 一个包含 status, reason 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ return self._post( - 'wxa/get_auditstatus', + "wxa/get_auditstatus", data={ - 'auditid': auditid, + "auditid": auditid, }, ) @@ -244,9 +257,7 @@ def get_latest_audit_status(self): :return: 一个包含 status, reason, auditid 的 dict。status 0为审核成功,1为审核失败,2为审核中。 """ - return self._get( - 'wxa/get_latest_auditstatus' - ) + return self._get("wxa/get_latest_auditstatus") def release(self): """ @@ -255,7 +266,7 @@ def release(self): https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&id=open1489140610_Uavc4 """ return self._post( - 'wxa/release', + "wxa/release", data={}, ) @@ -269,9 +280,9 @@ def change_visit_status(self, close=False): :type close: bool """ return self._post( - 'wxa/change_visitstatus', + "wxa/change_visitstatus", data={ - 'action': 'close' if close else 'open', + "action": "close" if close else "open", }, ) @@ -289,10 +300,10 @@ def list_library_templates(self, offset=0, count=20): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/list', + "cgi-bin/wxopen/template/library/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, ) @@ -306,9 +317,9 @@ def get_library_template(self, template_short_id): :rtype: dict """ return self._post( - 'cgi-bin/wxopen/template/library/get', + "cgi-bin/wxopen/template/library/get", data={ - 'id': template_short_id, + "id": template_short_id, }, ) @@ -326,12 +337,12 @@ def list_templates(self, offset=0, count=20): :rtype: list[dict] """ return self._post( - 'cgi-bin/wxopen/template/list', + "cgi-bin/wxopen/template/list", data={ - 'offset': offset, - 'count': count, + "offset": offset, + "count": count, }, - result_processor=lambda x: x['list'], + result_processor=lambda x: x["list"], ) def add_template(self, template_short_id, keyword_id_list): @@ -346,12 +357,12 @@ def add_template(self, template_short_id, keyword_id_list): :return: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/add', + "cgi-bin/wxopen/template/add", data={ - 'id': template_short_id, - 'keyword_id_list': keyword_id_list, + "id": template_short_id, + "keyword_id_list": keyword_id_list, }, - result_processor=lambda x: x['template_id'], + result_processor=lambda x: x["template_id"], ) def del_template(self, template_id): @@ -363,9 +374,9 @@ def del_template(self, template_id): :param template_id: 模板ID """ return self._post( - 'cgi-bin/wxopen/template/del', + "cgi-bin/wxopen/template/del", data={ - 'template_id': template_id, + "template_id": template_id, }, ) @@ -379,11 +390,11 @@ def create_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/create', + "cgi-bin/open/create", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def get_open(self, appid): @@ -396,11 +407,11 @@ def get_open(self, appid): :return: 开放平台的 appid """ return self._post( - 'cgi-bin/open/get', + "cgi-bin/open/get", data={ - 'appid': appid, + "appid": appid, }, - result_processor=lambda x: x['open_appid'], + result_processor=lambda x: x["open_appid"], ) def bind_open(self, appid, open_appid): @@ -413,11 +424,11 @@ def bind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/bind', + "cgi-bin/open/bind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def unbind_open(self, appid, open_appid): @@ -430,11 +441,11 @@ def unbind_open(self, appid, open_appid): :param open_appid: 开放平台帐号 appid """ return self._post( - 'cgi-bin/open/unbind', + "cgi-bin/open/unbind", data={ - 'appid': appid, - 'open_appid': open_appid, - } + "appid": appid, + "open_appid": open_appid, + }, ) def code_to_session(self, js_code): @@ -447,11 +458,11 @@ def code_to_session(self, js_code): :return: """ return self._get( - 'sns/jscode2session', + "sns/jscode2session", params={ - 'appid': self.appid, - 'secret': self.secret, - 'js_code': js_code, - 'grant_type': 'authorization_code' - } + "appid": self.appid, + "secret": self.secret, + "js_code": js_code, + "grant_type": "authorization_code", + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/client/base.py b/chapter14/booking_system/exts/wechatpy/client/base.py index 88c7b85..1ac1b91 100644 --- a/chapter14/booking_system/exts/wechatpy/client/base.py +++ b/chapter14/booking_system/exts/wechatpy/client/base.py @@ -23,7 +23,7 @@ def _is_api_endpoint(obj): class BaseWeChatClient(object): - API_BASE_URL = '' + API_BASE_URL = "" def __new__(cls, *args, **kwargs): self = super(BaseWeChatClient, cls).__new__(cls) @@ -34,7 +34,9 @@ def __new__(cls, *args, **kwargs): setattr(self, name, api) return self - def __init__(self, appid, access_token=None, session=None, timeout=None, auto_retry=True): + def __init__( + self, appid, access_token=None, session=None, timeout=None, auto_retry=True + ): self._http = requests.Session() self.appid = appid self.expires_at = None @@ -47,7 +49,7 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -58,35 +60,30 @@ def __init__(self, appid, access_token=None, session=None, timeout=None, auto_re @property def access_token_key(self): - return '{0}_access_token'.format(self.appid) + return "{0}_access_token".format(self.appid) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'access_token' not in kwargs['params']: - kwargs['params']['access_token'] = self.access_token - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - result_processor = kwargs.pop('result_processor', None) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "access_token" not in kwargs["params"] + ): + kwargs["params"]["access_token"] = self.access_token + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + result_processor = kwargs.pop("result_processor", None) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -95,24 +92,23 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - return self._handle_result( - res, method, url, result_processor, **kwargs - ) + return self._handle_result(res, method, url, result_processor, **kwargs) def _decode_result(self, res): try: - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) except (TypeError, ValueError): # Return origin response object if we can not decode it as JSON - logger.debug('Can not decode response as JSON', exc_info=True) + logger.debug("Can not decode response as JSON", exc_info=True) return res return result - def _handle_result(self, res, method=None, url=None, - result_processor=None, **kwargs): + def _handle_result( + self, res, method=None, url=None, result_processor=None, **kwargs + ): if not isinstance(res, dict): # Dirty hack around asyncio based AsyncWeChatClient result = self._decode_result(res) @@ -122,23 +118,24 @@ def _handle_result(self, res, method=None, url=None, if not isinstance(result, dict): return result - if 'base_resp' in result: + if "base_resp" in result: # Different response in device APIs. Fuck tencent! - result.update(result.pop('base_resp')) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result.update(result.pop("base_resp")) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Access token expired, fetch a new one and retry request') + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info("Access token expired, fetch a new one and retry request") self.fetch_access_token() access_token = self.session.get(self.access_token_key) - kwargs['params']['access_token'] = access_token + kwargs["params"]["access_token"] = access_token return self._request( method=method, url_or_endpoint=url, @@ -148,56 +145,43 @@ def _handle_result(self, res, method=None, url=None, elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result if not result_processor else result_processor(result) def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def _get(self, url, **kwargs): - warnings.warn('`_get` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `get` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_get` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `get` instead", + DeprecationWarning, + stacklevel=2, + ) return self.get(url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def _post(self, url, **kwargs): - warnings.warn('`_post` method of `WeChatClient` is deprecated, will be removed in 1.6,' - 'Use `post` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`_post` method of `WeChatClient` is deprecated, will be removed in 1.6," + "Use `post` instead", + DeprecationWarning, + stacklevel=2, + ) return self.post(url, **kwargs) def _fetch_access_token(self, url, params): - """ The real fetch access token """ - logger.info('Fetching access token') - res = self._http.get( - url=url, - params=params - ) + """The real fetch access token""" + logger.info("Fetching access token") + res = self._http.get(url=url, params=params) try: res.raise_for_status() except requests.RequestException as reqe: @@ -206,26 +190,22 @@ def _fetch_access_token(self, url, params): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] - self.session.set( - self.access_token_key, - result['access_token'], - expires_in - ) + if "expires_in" in result: + expires_in = result["expires_in"] + self.session.set(self.access_token_key, result["access_token"], expires_in) self.expires_at = int(time.time()) + expires_in return result @@ -234,7 +214,7 @@ def fetch_access_token(self): @property def access_token(self): - """ WeChat access token """ + """WeChat access token""" access_token = self.session.get(self.access_token_key) if access_token: if not self.expires_at: diff --git a/chapter14/booking_system/exts/wechatpy/component.py b/chapter14/booking_system/exts/wechatpy/component.py index 980daa4..e663e23 100644 --- a/chapter14/booking_system/exts/wechatpy/component.py +++ b/chapter14/booking_system/exts/wechatpy/component.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.component - ~~~~~~~~~~~~~~~ +wechatpy.component +~~~~~~~~~~~~~~~ - This module provides client library for WeChat Open Platform +This module provides client library for WeChat Open Platform - :copyright: (c) 2015 by hunter007. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2015 by hunter007. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -22,8 +22,12 @@ from exts.wechatpy.client import WeChatComponentClient from exts.wechatpy.constants import WeChatErrorCode from exts.wechatpy.crypto import WeChatCrypto -from exts.wechatpy.exceptions import APILimitedException, WeChatClientException, WeChatOAuthException, \ - WeChatComponentOAuthException +from exts.wechatpy.exceptions import ( + APILimitedException, + WeChatClientException, + WeChatOAuthException, + WeChatComponentOAuthException, +) from exts.wechatpy.fields import DateTimeField, StringField from exts.wechatpy.messages import MessageMetaClass from exts.wechatpy.session.memorystorage import MemoryStorage @@ -38,22 +42,23 @@ def register_component_message(msg_type): def register(cls): COMPONENT_MESSAGE_TYPES[msg_type] = cls return cls + return register class BaseComponentMessage(six.with_metaclass(MessageMetaClass)): """Base class for all component messages and events""" - type = 'unknown' - appid = StringField('AppId') - create_time = DateTimeField('CreateTime') + + type = "unknown" + appid = StringField("AppId") + create_time = DateTimeField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -61,60 +66,67 @@ def __repr__(self): return to_text(_repr) -@register_component_message('component_verify_ticket') +@register_component_message("component_verify_ticket") class ComponentVerifyTicketMessage(BaseComponentMessage): """ component_verify_ticket协议 """ - type = 'component_verify_ticket' - verify_ticket = StringField('ComponentVerifyTicket') + + type = "component_verify_ticket" + verify_ticket = StringField("ComponentVerifyTicket") -@register_component_message('unauthorized') +@register_component_message("unauthorized") class ComponentUnauthorizedMessage(BaseComponentMessage): """ 取消授权通知 """ - type = 'unauthorized' - authorizer_appid = StringField('AuthorizerAppid') + type = "unauthorized" + authorizer_appid = StringField("AuthorizerAppid") -@register_component_message('authorized') + +@register_component_message("authorized") class ComponentAuthorizedMessage(ComponentUnauthorizedMessage): """ 新增授权通知 """ - type = 'authorized' - authorization_code = StringField('AuthorizationCode') - authorization_code_expired_time = StringField('AuthorizationCodeExpiredTime') - pre_auth_code = StringField('PreAuthCode') + + type = "authorized" + authorization_code = StringField("AuthorizationCode") + authorization_code_expired_time = StringField("AuthorizationCodeExpiredTime") + pre_auth_code = StringField("PreAuthCode") -@register_component_message('updateauthorized') +@register_component_message("updateauthorized") class ComponentUpdateauthorizedMessage(ComponentAuthorizedMessage): """ 更新授权通知 """ - type = 'updateauthorized' + + type = "updateauthorized" class ComponentUnknownMessage(BaseComponentMessage): """ 未知通知 """ - type = 'unknown' + type = "unknown" -class BaseWeChatComponent(object): - API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin' - def __init__(self, - component_appid, - component_appsecret, - component_token, - encoding_aes_key, - session=None, - auto_retry=True): +class BaseWeChatComponent(object): + API_BASE_URL = "https://api.weixin.qq.com/cgi-bin" + + def __init__( + self, + component_appid, + component_appsecret, + component_token, + encoding_aes_key, + session=None, + auto_retry=True, + ): """ :param component_appid: 第三方平台appid :param component_appsecret: 第三方平台appsecret @@ -125,8 +137,7 @@ def __init__(self, self.component_appid = component_appid self.component_appsecret = component_appsecret self.expires_at = None - self.crypto = WeChatCrypto( - component_token, encoding_aes_key, component_appid) + self.crypto = WeChatCrypto(component_token, encoding_aes_key, component_appid) self.session = session or MemoryStorage() self.auto_retry = auto_retry @@ -135,7 +146,7 @@ def __init__(self, from exts.wechatpy.session.shovestorage import ShoveStorage querystring = get_querystring(session) - prefix = querystring.get('prefix', ['wechatpy'])[0] + prefix = querystring.get("prefix", ["wechatpy"])[0] shove = Shove(session) storage = ShoveStorage(shove, prefix) @@ -143,32 +154,26 @@ def __init__(self, @property def component_verify_ticket(self): - return self.session.get('component_verify_ticket') + return self.session.get("component_verify_ticket") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if 'params' not in kwargs: - kwargs['params'] = {} - if isinstance(kwargs['params'], dict) and \ - 'component_access_token' not in kwargs['params']: - kwargs['params'][ - 'component_access_token'] = self.access_token - if isinstance(kwargs['data'], dict): - kwargs['data'] = json.dumps(kwargs['data']) - - res = self._http.request( - method=method, - url=url, - **kwargs - ) + if "params" not in kwargs: + kwargs["params"] = {} + if ( + isinstance(kwargs["params"], dict) + and "component_access_token" not in kwargs["params"] + ): + kwargs["params"]["component_access_token"] = self.access_token + if isinstance(kwargs["data"], dict): + kwargs["data"] = json.dumps(kwargs["data"]) + + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -177,49 +182,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method, url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.fetch_access_token() - kwargs['params']['component_access_token'] = self.session.get( - 'component_access_token' + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + self.fetch_access_token() + kwargs["params"]["component_access_token"] = self.session.get( + "component_access_token" ) + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatClientException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result @@ -231,26 +227,22 @@ def fetch_access_token(self): :return: 返回的 JSON 数据包 """ - url = '{0}{1}'.format( - self.API_BASE_URL, - '/component/api_component_token' - ) + url = "{0}{1}".format(self.API_BASE_URL, "/component/api_component_token") return self._fetch_access_token( url=url, - data=json.dumps({ - 'component_appid': self.component_appid, - 'component_appsecret': self.component_appsecret, - 'component_verify_ticket': self.component_verify_ticket - }) + data=json.dumps( + { + "component_appid": self.component_appid, + "component_appsecret": self.component_appsecret, + "component_verify_ticket": self.component_verify_ticket, + } + ), ) def _fetch_access_token(self, url, data): - """ The real fetch access token """ - logger.info('Fetching component access token') - res = self._http.post( - url=url, - data=data - ) + """The real fetch access token""" + logger.info("Fetching component access token") + res = self._http.post(url=url, data=data) try: res.raise_for_status() except requests.RequestException as reqe: @@ -259,33 +251,31 @@ def _fetch_access_token(self, url, data): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) result = res.json() - if 'errcode' in result and result['errcode'] != 0: + if "errcode" in result and result["errcode"] != 0: raise WeChatClientException( - result['errcode'], - result['errmsg'], + result["errcode"], + result["errmsg"], client=self, request=res.request, - response=res + response=res, ) expires_in = 7200 - if 'expires_in' in result: - expires_in = result['expires_in'] + if "expires_in" in result: + expires_in = result["expires_in"] self.session.set( - 'component_access_token', - result['component_access_token'], - expires_in + "component_access_token", result["component_access_token"], expires_in ) self.expires_at = int(time.time()) + expires_in return result @property def access_token(self): - """ WeChat component access token """ - access_token = self.session.get('component_access_token') + """WeChat component access token""" + access_token = self.session.get("component_access_token") if access_token: if not self.expires_at: # order provided access_token, just return it @@ -296,41 +286,39 @@ def access_token(self): return access_token self.fetch_access_token() - return self.session.get('component_access_token') + return self.session.get("component_access_token") def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) class WeChatComponent(BaseWeChatComponent): - PRE_AUTH_URL = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage' + PRE_AUTH_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage" def get_pre_auth_url(self, redirect_uri): - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") return "{0}?component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - self.PRE_AUTH_URL, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri - ) + self.PRE_AUTH_URL, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, + ) def get_pre_auth_url_m(self, redirect_uri): """ 快速获取pre auth url,可以直接微信中发送该链接,直接授权 """ url = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=3&no_scan=1&" - redirect_uri = quote(redirect_uri, safe='') + redirect_uri = quote(redirect_uri, safe="") return "{0}component_appid={1}&pre_auth_code={2}&redirect_uri={3}".format( - url, self.component_appid, self.create_preauthcode()['pre_auth_code'], redirect_uri + url, + self.component_appid, + self.create_preauthcode()["pre_auth_code"], + redirect_uri, ) def create_preauthcode(self): @@ -338,10 +326,8 @@ def create_preauthcode(self): 获取预授权码 """ return self.post( - '/component/api_create_preauthcode', - data={ - 'component_appid': self.component_appid - } + "/component/api_create_preauthcode", + data={"component_appid": self.component_appid}, ) def _query_auth(self, authorization_code): @@ -351,11 +337,11 @@ def _query_auth(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ return self.post( - '/component/api_query_auth', + "/component/api_query_auth", data={ - 'component_appid': self.component_appid, - 'authorization_code': authorization_code - } + "component_appid": self.component_appid, + "authorization_code": authorization_code, + }, ) def query_auth(self, authorization_code): @@ -366,28 +352,35 @@ def query_auth(self, authorization_code): """ result = self._query_auth(authorization_code) - assert result is not None \ - and 'authorization_info' in result \ - and 'authorizer_appid' in result['authorization_info'] + assert ( + result is not None + and "authorization_info" in result + and "authorizer_appid" in result["authorization_info"] + ) - authorizer_appid = result['authorization_info']['authorizer_appid'] - if 'authorizer_access_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_access_token']: - access_token = result['authorization_info']['authorizer_access_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + authorizer_appid = result["authorization_info"]["authorizer_appid"] + if ( + "authorizer_access_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_access_token"] + ): + access_token = result["authorization_info"]["authorizer_access_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in result['authorization_info']: - expires_in = result['authorization_info']['expires_in'] + if "expires_in" in result["authorization_info"]: + expires_in = result["authorization_info"]["expires_in"] self.session.set(access_token_key, access_token, expires_in) - if 'authorizer_refresh_token' in result['authorization_info'] \ - and result['authorization_info']['authorizer_refresh_token']: - refresh_token = result['authorization_info']['authorizer_refresh_token'] - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) - self.session.set(refresh_token_key, refresh_token) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 + if ( + "authorizer_refresh_token" in result["authorization_info"] + and result["authorization_info"]["authorizer_refresh_token"] + ): + refresh_token = result["authorization_info"]["authorizer_refresh_token"] + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) + self.session.set( + refresh_token_key, refresh_token + ) # refresh_token 需要永久储存,不建议使用内存储存,否则每次重启服务需要重新扫码授权 return result - def refresh_authorizer_token( - self, authorizer_appid, authorizer_refresh_token): + def refresh_authorizer_token(self, authorizer_appid, authorizer_refresh_token): """ 获取(刷新)授权公众号的令牌 @@ -395,12 +388,12 @@ def refresh_authorizer_token( :params authorizer_refresh_token: 授权方的刷新令牌 """ return self.post( - '/component/api_authorizer_token', + "/component/api_authorizer_token", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'authorizer_refresh_token': authorizer_refresh_token - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "authorizer_refresh_token": authorizer_refresh_token, + }, ) def get_authorizer_info(self, authorizer_appid): @@ -410,11 +403,11 @@ def get_authorizer_info(self, authorizer_appid): :params authorizer_appid: 授权方appid """ return self.post( - '/component/api_get_authorizer_info', + "/component/api_get_authorizer_info", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + }, ) def get_authorizer_option(self, authorizer_appid, option_name): @@ -425,16 +418,15 @@ def get_authorizer_option(self, authorizer_appid, option_name): :params option_name: 选项名称 """ return self.post( - '/component/api_get_authorizer_option', + "/component/api_get_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + }, ) - def set_authorizer_option( - self, authorizer_appid, option_name, option_value): + def set_authorizer_option(self, authorizer_appid, option_name, option_value): """ 设置授权方的选项信息 @@ -443,13 +435,13 @@ def set_authorizer_option( :params option_value: 设置的选项值 """ return self.post( - '/component/api_set_authorizer_option', + "/component/api_set_authorizer_option", data={ - 'component_appid': self.component_appid, - 'authorizer_appid': authorizer_appid, - 'option_name': option_name, - 'option_value': option_value - } + "component_appid": self.component_appid, + "authorizer_appid": authorizer_appid, + "option_name": option_name, + "option_value": option_value, + }, ) def get_client_by_authorization_code(self, authorization_code): @@ -458,17 +450,19 @@ def get_client_by_authorization_code(self, authorization_code): :params authorization_code: 授权code,会在授权成功时返回给第三方平台,详见第三方平台授权流程说明 """ - warnings.warn('`get_client_by_authorization_code` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` parse message and ' - 'Use `get_client_by_appid` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_client_by_authorization_code` method of `WeChatComponent` is deprecated," + "Use `parse_message` parse message and " + "Use `get_client_by_appid` instead", + DeprecationWarning, + stacklevel=2, + ) result = self.query_auth(authorization_code) - access_token = result['authorization_info']['authorizer_access_token'] - refresh_token = result['authorization_info']['authorizer_refresh_token'] # NOQA - authorizer_appid = result['authorization_info']['authorizer_appid'] # noqa + access_token = result["authorization_info"]["authorizer_access_token"] + refresh_token = result["authorization_info"]["authorizer_refresh_token"] # NOQA + authorizer_appid = result["authorization_info"]["authorizer_appid"] # noqa return WeChatComponentClient( - authorizer_appid, self, access_token, refresh_token, - session=self.session + authorizer_appid, self, access_token, refresh_token, session=self.session ) def get_client_by_appid(self, authorizer_appid): @@ -477,30 +471,23 @@ def get_client_by_appid(self, authorizer_appid): :params authorizer_appid: 授权公众号appid """ - access_token_key = '{0}_access_token'.format(authorizer_appid) - refresh_token_key = '{0}_refresh_token'.format(authorizer_appid) + access_token_key = "{0}_access_token".format(authorizer_appid) + refresh_token_key = "{0}_refresh_token".format(authorizer_appid) access_token = self.session.get(access_token_key) refresh_token = self.session.get(refresh_token_key) assert refresh_token if not access_token: - ret = self.refresh_authorizer_token( - authorizer_appid, - refresh_token - ) - access_token = ret['authorizer_access_token'] - refresh_token = ret['authorizer_refresh_token'] - access_token_key = '{0}_access_token'.format(authorizer_appid) + ret = self.refresh_authorizer_token(authorizer_appid, refresh_token) + access_token = ret["authorizer_access_token"] + refresh_token = ret["authorizer_refresh_token"] + access_token_key = "{0}_access_token".format(authorizer_appid) expires_in = 7200 - if 'expires_in' in ret: - expires_in = ret['expires_in'] + if "expires_in" in ret: + expires_in = ret["expires_in"] self.session.set(access_token_key, access_token, expires_in) - return WeChatComponentClient( - authorizer_appid, - self, - session=self.session - ) + return WeChatComponentClient(authorizer_appid, self, session=self.session) def parse_message(self, msg, msg_signature, timestamp, nonce): """ @@ -512,13 +499,15 @@ def parse_message(self, msg, msg_signature, timestamp, nonce): :params nonce: 随机数 """ content = self.crypto.decrypt_message(msg, msg_signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] - message_type = message['InfoType'].lower() - message_class = COMPONENT_MESSAGE_TYPES.get(message_type, ComponentUnknownMessage) + message = xmltodict.parse(to_text(content))["xml"] + message_type = message["InfoType"].lower() + message_class = COMPONENT_MESSAGE_TYPES.get( + message_type, ComponentUnknownMessage + ) msg = message_class(message) - if msg.type == 'component_verify_ticket': + if msg.type == "component_verify_ticket": self.session.set(msg.type, msg.verify_ticket) - elif msg.type in ('authorized', 'updateauthorized'): + elif msg.type in ("authorized", "updateauthorized"): msg.query_auth_result = self.query_auth(msg.authorization_code) return msg @@ -531,11 +520,14 @@ def cache_component_verify_ticket(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`cache_component_verify_ticket` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`cache_component_verify_ticket` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] o = ComponentVerifyTicketMessage(message) self.session.set(o.type, o.verify_ticket) @@ -548,11 +540,14 @@ def get_unauthorized(self, msg, signature, timestamp, nonce): :params timestamp: 时间戳 :params nonce: 随机数 """ - warnings.warn('`get_unauthorized` method of `WeChatComponent` is deprecated,' - 'Use `parse_message` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "`get_unauthorized` method of `WeChatComponent` is deprecated," + "Use `parse_message` instead", + DeprecationWarning, + stacklevel=2, + ) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) - message = xmltodict.parse(to_text(content))['xml'] + message = xmltodict.parse(to_text(content))["xml"] return ComponentUnauthorizedMessage(message) def get_component_oauth(self, authorizer_appid): @@ -565,16 +560,25 @@ def get_component_oauth(self, authorizer_appid): class ComponentOAuth(object): - """ 微信开放平台 代公众号 OAuth 网页授权 + """微信开放平台 代公众号 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' - def __init__(self, app_id, component_appid=None, component_access_token=None, - redirect_uri=None, scope='snsapi_base', state='', component=None): + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" + + def __init__( + self, + app_id, + component_appid=None, + component_access_token=None, + redirect_uri=None, + scope="snsapi_base", + state="", + component=None, + ): """ :param app_id: 微信公众号 app_id @@ -584,42 +588,55 @@ def __init__(self, app_id, component_appid=None, component_access_token=None, self.app_id = app_id self.component = component if self.component is None: - warnings.warn('cannot found `component` param of `ComponentOAuth` `__init__` method,' - 'Use `WeChatComponent.get_component_oauth` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "cannot found `component` param of `ComponentOAuth` `__init__` method," + "Use `WeChatComponent.get_component_oauth` instead", + DeprecationWarning, + stacklevel=2, + ) - self.component = ObjectDict({'component_appid': component_appid, 'access_token': component_access_token}) + self.component = ObjectDict( + { + "component_appid": component_appid, + "access_token": component_access_token, + } + ) if redirect_uri is not None: - warnings.warn('found `redirect_uri` param of `ComponentOAuth` `__init__` method,' - 'Use `ComponentOAuth.get_authorize_url` instead', - DeprecationWarning, stacklevel=2) + warnings.warn( + "found `redirect_uri` param of `ComponentOAuth` `__init__` method," + "Use `ComponentOAuth.get_authorize_url` instead", + DeprecationWarning, + stacklevel=2, + ) self.authorize_url = self.get_authorize_url(redirect_uri, scope, state) - def get_authorize_url(self, redirect_uri, scope='snsapi_base', state=''): + def get_authorize_url(self, redirect_uri, scope="snsapi_base", state=""): """ :param redirect_uri: 重定向地址,需要urlencode,这里填写的应是服务开发方的回调地址 :param scope: 可选,微信公众号 OAuth2 scope,默认为 ``snsapi_base`` :param state: 可选,重定向后会带上state参数,开发者可以填写任意参数值,最多128字节 """ - redirect_uri = quote(redirect_uri, safe=b'') + redirect_uri = quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', + "&response_type=code&scope=", scope, ] if state: - url_list.extend(['&state=', state]) - url_list.extend([ - '&component_appid=', - self.component.component_appid, - ]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.extend( + [ + "&component_appid=", + self.component.component_appid, + ] + ) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -628,20 +645,20 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/access_token', + "sns/oauth2/component/access_token", params={ - 'appid': self.app_id, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - 'code': code, - 'grant_type': 'authorization_code', - } + "appid": self.app_id, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res def refresh_access_token(self, refresh_token): @@ -651,24 +668,24 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/component/refresh_token', + "sns/oauth2/component/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token, - 'component_appid': self.component.component_appid, - 'component_access_token': self.component.access_token, - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "component_appid": self.component.component_appid, + "component_access_token": self.component.access_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] - self.scope = res['scope'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] + self.scope = res["scope"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): - """ 获取用户基本信息(需授权作用域为snsapi_userinfo) + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): + """获取用户基本信息(需授权作用域为snsapi_userinfo) 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。 @@ -680,33 +697,24 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -715,53 +723,40 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res, method=method, url=url, **kwargs) def _handle_result(self, res, method=None, url=None, **kwargs): - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) - if 'errcode' in result: - result['errcode'] = int(result['errcode']) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) + if "errcode" in result: + result["errcode"] = int(result["errcode"]) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result.get('errmsg', errcode) + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result.get("errmsg", errcode) if self.component.auto_retry and errcode in ( - WeChatErrorCode.INVALID_CREDENTIAL.value, - WeChatErrorCode.INVALID_ACCESS_TOKEN.value, - WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value): - logger.info('Component access token expired, fetch a new one and retry request') - self.component.fetch_access_token() - kwargs['params']['component_access_token'] = self.component.access_token - return self._request( - method=method, - url_or_endpoint=url, - **kwargs + WeChatErrorCode.INVALID_CREDENTIAL.value, + WeChatErrorCode.INVALID_ACCESS_TOKEN.value, + WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value, + ): + logger.info( + "Component access token expired, fetch a new one and retry request" ) + self.component.fetch_access_token() + kwargs["params"]["component_access_token"] = self.component.access_token + return self._request(method=method, url_or_endpoint=url, **kwargs) elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value: # api freq out of limit raise APILimitedException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) else: raise WeChatComponentOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) diff --git a/chapter14/booking_system/exts/wechatpy/constants.py b/chapter14/booking_system/exts/wechatpy/constants.py index 628476a..967736e 100644 --- a/chapter14/booking_system/exts/wechatpy/constants.py +++ b/chapter14/booking_system/exts/wechatpy/constants.py @@ -6,26 +6,28 @@ @unique class UserFormInfoFlag(Enum): - """ 微信卡券会员卡格式化的选项类型 """ - MOBILE = 'USER_FORM_INFO_FLAG_MOBILE' # 手机号 - SEX = 'USER_FORM_INFO_FLAG_SEX' # 性别 - NAME = 'USER_FORM_INFO_FLAG_NAME' # 姓名 - BIRTHDAY = 'USER_FORM_INFO_FLAG_BIRTHDAY' # 生日 - IDCARD = 'USER_FORM_INFO_FLAG_IDCARD' # 身份证 - EMAIL = 'USER_FORM_INFO_FLAG_EMAIL' # 邮箱 - LOCATION = 'USER_FORM_INFO_FLAG_LOCATION' # 详细地址 - EDUCATION_BACKGRO = 'USER_FORM_INFO_FLAG_EDUCATION_BACKGRO' # 教育背景 - INDUSTRY = 'USER_FORM_INFO_FLAG_INDUSTRY' # 行业 - INCOME = 'USER_FORM_INFO_FLAG_INCOME' # 收入 - HABIT = 'USER_FORM_INFO_FLAG_HABIT' # 兴趣爱好 + """微信卡券会员卡格式化的选项类型""" + + MOBILE = "USER_FORM_INFO_FLAG_MOBILE" # 手机号 + SEX = "USER_FORM_INFO_FLAG_SEX" # 性别 + NAME = "USER_FORM_INFO_FLAG_NAME" # 姓名 + BIRTHDAY = "USER_FORM_INFO_FLAG_BIRTHDAY" # 生日 + IDCARD = "USER_FORM_INFO_FLAG_IDCARD" # 身份证 + EMAIL = "USER_FORM_INFO_FLAG_EMAIL" # 邮箱 + LOCATION = "USER_FORM_INFO_FLAG_LOCATION" # 详细地址 + EDUCATION_BACKGRO = "USER_FORM_INFO_FLAG_EDUCATION_BACKGRO" # 教育背景 + INDUSTRY = "USER_FORM_INFO_FLAG_INDUSTRY" # 行业 + INCOME = "USER_FORM_INFO_FLAG_INCOME" # 收入 + HABIT = "USER_FORM_INFO_FLAG_HABIT" # 兴趣爱好 @unique class ReimburseStatus(Enum): - """ 发票报销状态 """ - INIT = 'INVOICE_REIMBURSE_INIT' # 初始状态,未锁定,可提交报销 - LOCK = 'INVOICE_REIMBURSE_LOCK' # 已锁定,无法重复提交报销 - CLOSURE = 'INVOICE_REIMBURSE_CLOSURE' # 已核销,从用户卡包中移除 + """发票报销状态""" + + INIT = "INVOICE_REIMBURSE_INIT" # 初始状态,未锁定,可提交报销 + LOCK = "INVOICE_REIMBURSE_LOCK" # 已锁定,无法重复提交报销 + CLOSURE = "INVOICE_REIMBURSE_CLOSURE" # 已核销,从用户卡包中移除 @unique @@ -33,6 +35,7 @@ class WeChatErrorCode(IntEnum): """ 微信接口返回码,全局返回码请参考 https://mp.weixin.qq.com/wiki?id=mp1433747234 """ + # 系统错误 SYSTEM_ERROR = -1000 diff --git a/chapter14/booking_system/exts/wechatpy/crypto/__init__.py b/chapter14/booking_system/exts/wechatpy/crypto/__init__.py index 4c93dbd..0df8905 100644 --- a/chapter14/booking_system/exts/wechatpy/crypto/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/crypto/__init__.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.crypto - ~~~~~~~~~~~~~~~~ +wechatpy.crypto +~~~~~~~~~~~~~~~~ - This module provides some crypto tools for WeChat and WeChat enterprise +This module provides some crypto tools for WeChat and WeChat enterprise - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import json @@ -14,10 +14,7 @@ import base64 from exts.wechatpy.utils import to_text, to_binary, WeChatSigner -from exts.wechatpy.exceptions import ( - InvalidAppIdException, - InvalidSignatureException -) +from exts.wechatpy.exceptions import InvalidAppIdException, InvalidSignatureException from exts.wechatpy.crypto.base import BasePrpCrypto, WeChatCipher from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder @@ -40,29 +37,22 @@ def decrypt(self, text, app_id): class BaseWeChatCrypto(object): def __init__(self, token, encoding_aes_key, _id): - encoding_aes_key = to_binary(encoding_aes_key + '=') + encoding_aes_key = to_binary(encoding_aes_key + "=") self.key = base64.b64decode(encoding_aes_key) assert len(self.key) == 32 self.token = token self._id = _id - def _check_signature(self, - signature, - timestamp, - nonce, - echo_str, - crypto_class=None): + def _check_signature( + self, signature, timestamp, nonce, echo_str, crypto_class=None + ): _signature = _get_signature(self.token, timestamp, nonce, echo_str) if _signature != signature: raise InvalidSignatureException() pc = crypto_class(self.key) return pc.decrypt(echo_str, self._id) - def _encrypt_message(self, - msg, - nonce, - timestamp=None, - crypto_class=None): + def _encrypt_message(self, msg, nonce, timestamp=None, crypto_class=None): from exts.wechatpy.replies import BaseReply xml = """ @@ -77,25 +67,19 @@ def _encrypt_message(self, pc = crypto_class(self.key) encrypt = to_text(pc.encrypt(msg, self._id)) signature = _get_signature(self.token, timestamp, nonce, encrypt) - return to_text(xml.format( - encrypt=encrypt, - signature=signature, - timestamp=timestamp, - nonce=nonce - )) - - def _decrypt_message(self, - msg, - signature, - timestamp, - nonce, - crypto_class=None): + return to_text( + xml.format( + encrypt=encrypt, signature=signature, timestamp=timestamp, nonce=nonce + ) + ) + + def _decrypt_message(self, msg, signature, timestamp, nonce, crypto_class=None): if not isinstance(msg, dict): import xmltodict - msg = xmltodict.parse(to_text(msg))['xml'] + msg = xmltodict.parse(to_text(msg))["xml"] - encrypt = msg['Encrypt'] + encrypt = msg["Encrypt"] _signature = _get_signature(self.token, timestamp, nonce, encrypt) if _signature != signature: raise InvalidSignatureException() @@ -113,13 +97,7 @@ def encrypt_message(self, msg, nonce, timestamp=None): return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) class WeChatWxaCrypto(object): @@ -132,6 +110,6 @@ def decrypt_message(self, msg): decrypted = self.cipher.decrypt(raw_data) plaintext = PKCS7Encoder.decode(decrypted) decrypted_msg = json.loads(to_text(plaintext)) - if decrypted_msg['watermark']['appid'] != self.app_id: + if decrypted_msg["watermark"]["appid"] != self.app_id: raise InvalidAppIdException() return decrypted_msg diff --git a/chapter14/booking_system/exts/wechatpy/crypto/base.py b/chapter14/booking_system/exts/wechatpy/crypto/base.py index e12300e..a6f60d3 100644 --- a/chapter14/booking_system/exts/wechatpy/crypto/base.py +++ b/chapter14/booking_system/exts/wechatpy/crypto/base.py @@ -6,13 +6,14 @@ from exts.wechatpy.utils import to_text, to_binary, random_string, byte2int from exts.wechatpy.crypto.pkcs7 import PKCS7Encoder + try: from exts.wechatpy.crypto.cryptography import WeChatCipher except ImportError: try: from exts.wechatpy.crypto.pycrypto import WeChatCipher except ImportError: - raise Exception('You must install either cryptography or pycryptodome!') + raise Exception("You must install either cryptography or pycryptodome!") class BasePrpCrypto(object): @@ -27,12 +28,12 @@ def _encrypt(self, text, _id): text = to_binary(text) tmp_list = [] tmp_list.append(to_binary(self.get_random_string())) - length = struct.pack(b'I', socket.htonl(len(text))) + length = struct.pack(b"I", socket.htonl(len(text))) tmp_list.append(length) tmp_list.append(text) tmp_list.append(to_binary(_id)) - text = b''.join(tmp_list) + text = b"".join(tmp_list) text = PKCS7Encoder.encode(text) ciphertext = to_binary(self.cipher.encrypt(text)) @@ -43,9 +44,9 @@ def _decrypt(self, text, _id, exception=None): plain_text = self.cipher.decrypt(base64.b64decode(text)) padding = byte2int(plain_text[-1]) content = plain_text[16:-padding] - xml_length = socket.ntohl(struct.unpack(b'I', content[:4])[0]) - xml_content = to_text(content[4:xml_length + 4]) - from_id = to_text(content[xml_length + 4:]) + xml_length = socket.ntohl(struct.unpack(b"I", content[:4])[0]) + xml_content = to_text(content[4 : xml_length + 4]) + from_id = to_text(content[xml_length + 4 :]) if from_id != _id: exception = exception or Exception raise exception() diff --git a/chapter14/booking_system/exts/wechatpy/crypto/cryptography.py b/chapter14/booking_system/exts/wechatpy/crypto/cryptography.py index e63917f..944923e 100644 --- a/chapter14/booking_system/exts/wechatpy/crypto/cryptography.py +++ b/chapter14/booking_system/exts/wechatpy/crypto/cryptography.py @@ -9,11 +9,7 @@ class WeChatCipher(object): def __init__(self, key, iv=None): iv = iv or key[:16] backend = default_backend() - self.cipher = Cipher( - algorithms.AES(key), - modes.CBC(iv), - backend=backend - ) + self.cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) def encrypt(self, plaintext): encryptor = self.cipher.encryptor() diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/__init__.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/__init__.py index 89b19c6..94d6b23 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/__init__.py @@ -6,7 +6,7 @@ class WeChatClient(BaseWeChatClient): - API_BASE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/' + API_BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin/" agent = api.WeChatAgent() appchat = api.WeChatAppChat() @@ -25,8 +25,15 @@ class WeChatClient(BaseWeChatClient): tag = api.WeChatTag() user = api.WeChatUser() - def __init__(self, corp_id, secret, access_token=None, - session=None, timeout=None, auto_retry=True): + def __init__( + self, + corp_id, + secret, + access_token=None, + session=None, + timeout=None, + auto_retry=True, + ): super(WeChatClient, self).__init__( corp_id, access_token, session, timeout, auto_retry ) @@ -35,14 +42,11 @@ def __init__(self, corp_id, secret, access_token=None, @property def access_token_key(self): - return '{0}_{1}_access_token'.format(self.corp_id, self.secret[:10]) + return "{0}_{1}_access_token".format(self.corp_id, self.secret[:10]) def fetch_access_token(self): - """ Fetch access token""" + """Fetch access token""" return self._fetch_access_token( - url='https://qyapi.weixin.qq.com/cgi-bin/gettoken', - params={ - 'corpid': self.corp_id, - 'corpsecret': self.secret - } + url="https://qyapi.weixin.qq.com/cgi-bin/gettoken", + params={"corpid": self.corp_id, "corpsecret": self.secret}, ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/agent.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/agent.py index 2ba1d4c..d969d72 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/agent.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/agent.py @@ -19,12 +19,7 @@ def get(self, agent_id): :param agent_id: 应用id :return: 返回的 JSON 数据包 """ - return self._get( - 'agent/get', - params={ - 'agentid': agent_id - } - ) + return self._get("agent/get", params={"agentid": agent_id}) def list(self): """ @@ -33,18 +28,20 @@ def list(self): :return: 应用概况列表 """ - res = self._get('agent/list') - return res['agentlist'] + res = self._get("agent/list") + return res["agentlist"] - def set(self, - agent_id, - name=None, - description=None, - redirect_domain=None, - logo_media_id=None, - report_location_flag=0, - is_report_user=True, - is_report_enter=True): + def set( + self, + agent_id, + name=None, + description=None, + redirect_domain=None, + logo_media_id=None, + report_location_flag=0, + is_report_user=True, + is_report_enter=True, + ): """ 设置应用 https://work.weixin.qq.com/api/doc#90000/90135/90228 @@ -60,15 +57,12 @@ def set(self, :return: 返回的 JSON 数据包 """ agent_data = optionaldict() - agent_data['agentid'] = agent_id - agent_data['name'] = name - agent_data['description'] = description - agent_data['redirect_domain'] = redirect_domain - agent_data['logo_mediaid'] = logo_media_id - agent_data['report_location_flag'] = report_location_flag - agent_data['isreportenter'] = 1 if is_report_enter else 0 - agent_data['isreportuser'] = 1 if is_report_user else 0 - return self._post( - 'agent/set', - data=agent_data - ) + agent_data["agentid"] = agent_id + agent_data["name"] = name + agent_data["description"] = description + agent_data["redirect_domain"] = redirect_domain + agent_data["logo_mediaid"] = logo_media_id + agent_data["report_location_flag"] = report_location_flag + agent_data["isreportenter"] = 1 if is_report_enter else 0 + agent_data["isreportuser"] = 1 if is_report_user else 0 + return self._post("agent/set", data=agent_data) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/appchat.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/appchat.py index e6a5b46..1feb9e6 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/appchat.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/appchat.py @@ -35,7 +35,7 @@ def create(self, chat_id=None, name=None, owner=None, user_list=None): owner=owner, userlist=user_list, ) - return self._post('appchat/create', data=data) + return self._post("appchat/create", data=data) def get(self, chat_id): """ @@ -47,11 +47,12 @@ def get(self, chat_id): :param chat_id: 群聊id :return: 会话信息 """ - res = self._get('appchat/get', params={'chatid': chat_id}) - return res['chat_info'] + res = self._get("appchat/get", params={"chatid": chat_id}) + return res["chat_info"] - def update(self, chat_id, name=None, owner=None, - add_user_list=None, del_user_list=None): + def update( + self, chat_id, name=None, owner=None, add_user_list=None, del_user_list=None + ): """ 修改群聊会话 @@ -72,7 +73,7 @@ def update(self, chat_id, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('appchat/update', data=data) + return self._post("appchat/update", data=data) def send(self, chat_id, msg_type, **kwargs): """ @@ -84,16 +85,13 @@ def send(self, chat_id, msg_type, **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = { - 'chatid': chat_id, - 'safe': kwargs.get('safe') or 0 - } + data = {"chatid": chat_id, "safe": kwargs.get("safe") or 0} data.update(self._build_msg_content(msg_type, **kwargs)) - return self._post('appchat/send', data=data) + return self._post("appchat/send", data=data) def send_msg(self, chat_id, msg_type, **kwargs): - """ deprecated, use `send` instead """ + """deprecated, use `send` instead""" return self.send(chat_id, msg_type, **kwargs) def send_text(self, chat_id, content, safe=0): @@ -107,9 +105,9 @@ def send_text(self, chat_id, content, safe=0): :param safe: 表示是否是保密消息,0表示否,1表示是,默认0 :return: """ - return self.send(chat_id, 'text', safe=safe, content=content) + return self.send(chat_id, "text", safe=safe, content=content) - def _build_msg_content(self, msgtype='text', **kwargs): + def _build_msg_content(self, msgtype="text", **kwargs): """ 构造消息内容 @@ -118,25 +116,25 @@ def _build_msg_content(self, msgtype='text', **kwargs): :param kwargs: 具体消息类型的扩展参数 :return: """ - data = {'msgtype': msgtype} - if msgtype == 'text': - data[msgtype] = {'content': kwargs.get('content')} - elif msgtype == 'image' or msgtype == 'voice' or msgtype == 'file': - data[msgtype] = {'media_id': kwargs.get('media_id')} - elif msgtype == 'video': + data = {"msgtype": msgtype} + if msgtype == "text": + data[msgtype] = {"content": kwargs.get("content")} + elif msgtype == "image" or msgtype == "voice" or msgtype == "file": + data[msgtype] = {"media_id": kwargs.get("media_id")} + elif msgtype == "video": data[msgtype] = { - 'media_id': kwargs.get('media_id'), - 'title': kwargs.get('title'), - 'description': kwargs.get('description') + "media_id": kwargs.get("media_id"), + "title": kwargs.get("title"), + "description": kwargs.get("description"), } - elif msgtype == 'textcard': + elif msgtype == "textcard": data[msgtype] = { - 'title': kwargs.get('title'), - 'description': kwargs.get('description'), - 'url': kwargs.get('url'), - 'btntxt': kwargs.get('btntxt'), + "title": kwargs.get("title"), + "description": kwargs.get("description"), + "url": kwargs.get("url"), + "btntxt": kwargs.get("btntxt"), } - elif msgtype == 'news': + elif msgtype == "news": # { # "articles" : # [ @@ -149,7 +147,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'mpnews': + elif msgtype == "mpnews": # { # "articles":[ # { @@ -163,7 +161,7 @@ def _build_msg_content(self, msgtype='text', **kwargs): # ] # } data[msgtype] = kwargs - elif msgtype == 'markdown': + elif msgtype == "markdown": # { # "content": "您的会议室已经预定,稍后会同步到`邮箱` # >**事项详情** @@ -181,5 +179,5 @@ def _build_msg_content(self, msgtype='text', **kwargs): # } data[msgtype] = kwargs else: - raise TypeError('不能识别的msgtype: %s' % msgtype) + raise TypeError("不能识别的msgtype: %s" % msgtype) return data diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/batch.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/batch.py index 8ed88d5..268ebf3 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/batch.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/batch.py @@ -30,16 +30,16 @@ def sync_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/syncuser', + "batch/syncuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): @@ -56,16 +56,16 @@ def replace_user(self, url, token, encoding_aes_key, media_id, to_invite=True): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceuser', + "batch/replaceuser", data={ - 'media_id': media_id, - 'to_invite': to_invite, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "to_invite": to_invite, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def replace_party(self, url, token, encoding_aes_key, media_id): @@ -81,15 +81,15 @@ def replace_party(self, url, token, encoding_aes_key, media_id): :return: 返回的 JSON 数据包 """ return self._post( - 'batch/replaceparty', + "batch/replaceparty", data={ - 'media_id': media_id, - 'callback': { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key - } - } + "media_id": media_id, + "callback": { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, + }, + }, ) def get_result(self, job_id): @@ -101,7 +101,7 @@ def get_result(self, job_id): :param job_id: 异步任务id,最大长度为64字符 :return: 返回的 JSON 数据包 """ - return self._get('batch/getresult', params={'jobid': job_id}) + return self._get("batch/getresult", params={"jobid": job_id}) def invite(self, user=None, party=None, tag=None): """ @@ -117,10 +117,18 @@ def invite(self, user=None, party=None, tag=None): :return: 返回的 JSON 数据包 """ data = optionaldict(user=user, party=party, tag=tag) - return self._post('batch/invite', data=data) - - def invite_user(self, url, token, encoding_aes_key, user_ids=None, - party_ids=None, tag_ids=None, invite_tips=None): + return self._post("batch/invite", data=data) + + def invite_user( + self, + url, + token, + encoding_aes_key, + user_ids=None, + party_ids=None, + tag_ids=None, + invite_tips=None, + ): """ 邀请成员关注(deprecated) https://qydev.weixin.qq.com/wiki/index.php?title=异步任务接口 @@ -135,19 +143,19 @@ def invite_user(self, url, token, encoding_aes_key, user_ids=None, :return: 返回的 JSON 数据包 """ data = optionaldict() - data['callback'] = { - 'url': url, - 'token': token, - 'encodingaeskey': encoding_aes_key + data["callback"] = { + "url": url, + "token": token, + "encodingaeskey": encoding_aes_key, } if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(map(to_text, user_ids)) + user_ids = "|".join(map(to_text, user_ids)) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(map(to_text, party_ids)) + party_ids = "|".join(map(to_text, party_ids)) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(map(to_text, tag_ids)) - data['touser'] = user_ids - data['toparty'] = party_ids - data['totag'] = tag_ids - data['invite_tips'] = invite_tips - return self._post('batch/inviteuser', data=data) + tag_ids = "|".join(map(to_text, tag_ids)) + data["touser"] = user_ids + data["toparty"] = party_ids + data["totag"] = tag_ids + data["invite_tips"] = invite_tips + return self._post("batch/inviteuser", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/chat.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/chat.py index da16e5c..a71f53c 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/chat.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/chat.py @@ -27,13 +27,13 @@ def create(self, chat_id, name, owner, user_list): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/create', + "chat/create", data={ - 'chatid': chat_id, - 'name': name, - 'owner': owner, - 'userlist': user_list, - } + "chatid": chat_id, + "name": name, + "owner": owner, + "userlist": user_list, + }, ) def get(self, chat_id): @@ -46,11 +46,18 @@ def get(self, chat_id): :param chat_id: 会话 ID :return: 会话信息 """ - res = self._get('chat/get', params={'chatid': chat_id}) - return res['chat_info'] - - def update(self, chat_id, op_user, name=None, owner=None, - add_user_list=None, del_user_list=None): + res = self._get("chat/get", params={"chatid": chat_id}) + return res["chat_info"] + + def update( + self, + chat_id, + op_user, + name=None, + owner=None, + add_user_list=None, + del_user_list=None, + ): """ 修改会话 @@ -73,7 +80,7 @@ def update(self, chat_id, op_user, name=None, owner=None, add_user_list=add_user_list, del_user_list=del_user_list, ) - return self._post('chat/update', data=data) + return self._post("chat/update", data=data) def quit(self, chat_id, op_user): """ @@ -87,11 +94,11 @@ def quit(self, chat_id, op_user): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/quit', + "chat/quit", data={ - 'chatid': chat_id, - 'op_user': op_user, - } + "chatid": chat_id, + "op_user": op_user, + }, ) def clear_notify(self, op_user, type, id): @@ -107,14 +114,14 @@ def clear_notify(self, op_user, type, id): :return: 返回的 JSON 数据包 """ return self._post( - 'chat/clearnotify', + "chat/clearnotify", data={ - 'op_user': op_user, - 'chat': { - 'type': type, - 'id': id, - } - } + "op_user": op_user, + "chat": { + "type": type, + "id": id, + }, + }, ) def set_mute(self, user_mute_list): @@ -127,10 +134,7 @@ def set_mute(self, user_mute_list): :param user_mute_list: 成员新消息免打扰参数,数组,最大支持10000个成员 :return: 返回的 JSON 数据包 """ - return self._post( - 'chat/setmute', - data={'user_mute_list': user_mute_list} - ) + return self._post("chat/setmute", data={"user_mute_list": user_mute_list}) def send_text(self, sender, receiver_type, receiver_id, content): """ @@ -146,17 +150,17 @@ def send_text(self, sender, receiver_type, receiver_id, content): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "text", + "text": { + "content": content, }, - 'sender': sender, - 'msgtype': 'text', - 'text': { - 'content': content, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_text(self, sender, receiver, content): """ @@ -167,7 +171,7 @@ def send_single_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'single', receiver, content) + return self.send_text(sender, "single", receiver, content) def send_group_text(self, sender, receiver, content): """ @@ -178,7 +182,7 @@ def send_group_text(self, sender, receiver, content): :param content: 消息内容 :return: 返回的 JSON 数据包 """ - return self.send_text(sender, 'group', receiver, content) + return self.send_text(sender, "group", receiver, content) def send_image(self, sender, receiver_type, receiver_id, media_id): """ @@ -194,17 +198,17 @@ def send_image(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "image", + "image": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'image', - 'image': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_image(self, sender, receiver, media_id): """ @@ -215,7 +219,7 @@ def send_single_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'single', receiver, media_id) + return self.send_image(sender, "single", receiver, media_id) def send_group_image(self, sender, receiver, media_id): """ @@ -226,7 +230,7 @@ def send_group_image(self, sender, receiver, media_id): :param media_id: 图片媒体文件id,可以调用上传素材文件接口获取 :return: 返回的 JSON 数据包 """ - return self.send_image(sender, 'group', receiver, media_id) + return self.send_image(sender, "group", receiver, media_id) def send_file(self, sender, receiver_type, receiver_id, media_id): """ @@ -242,17 +246,17 @@ def send_file(self, sender, receiver_type, receiver_id, media_id): :return: 返回的 JSON 数据包 """ data = { - 'receiver': { - 'type': receiver_type, - 'id': receiver_id, + "receiver": { + "type": receiver_type, + "id": receiver_id, + }, + "sender": sender, + "msgtype": "file", + "file": { + "media_id": media_id, }, - 'sender': sender, - 'msgtype': 'file', - 'file': { - 'media_id': media_id, - } } - return self._post('chat/send', data=data) + return self._post("chat/send", data=data) def send_single_file(self, sender, receiver, media_id): """ @@ -263,7 +267,7 @@ def send_single_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'single', receiver, media_id) + return self.send_file(sender, "single", receiver, media_id) def send_group_file(self, sender, receiver, media_id): """ @@ -274,4 +278,4 @@ def send_group_file(self, sender, receiver, media_id): :param media_id: 文件id,可以调用上传素材文件接口获取, 文件须大于4字节 :return: 返回的 JSON 数据包 """ - return self.send_file(sender, 'group', receiver, media_id) + return self.send_file(sender, "group", receiver, media_id) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/department.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/department.py index d36893c..603c2ae 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/department.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/department.py @@ -23,13 +23,8 @@ def create(self, name, parent_id=1, order=None, id=None): :param id: 部门id,32位整型,指定时必须大于1。若不填该参数,将自动生成id :return: 返回的 JSON 数据包 """ - data = optionaldict( - name=name, - parentid=parent_id, - order=order, - id=id - ) - return self._post('department/create', data=data) + data = optionaldict(name=name, parentid=parent_id, order=order, id=id) + return self._post("department/create", data=data) def update(self, id, name=None, parent_id=None, order=None): """ @@ -43,13 +38,8 @@ def update(self, id, name=None, parent_id=None, order=None): :param order: 在父部门中的次序值。order值大的排序靠前。有效的值范围是[0, 2^32) :return: 返回的 JSON 数据包 """ - data = optionaldict( - id=id, - name=name, - parentid=parent_id, - order=order - ) - return self._post('department/update', data=data) + data = optionaldict(id=id, name=name, parentid=parent_id, order=order) + return self._post("department/update", data=data) def delete(self, id): """ @@ -60,7 +50,7 @@ def delete(self, id): :param id: 部门id。(注:不能删除根部门;不能删除含有子部门、成员的部门) :return: 返回的 JSON 数据包 """ - return self._get('department/delete', params={'id': id}) + return self._get("department/delete", params={"id": id}) def get(self, id=None): """ @@ -75,10 +65,10 @@ def get(self, id=None): :return: 部门列表 """ if id is None: - res = self._get('department/list') + res = self._get("department/list") else: - res = self._get('department/list', params={'id': id}) - return res['department'] + res = self._get("department/list", params={"id": id}) + return res["department"] def get_users(self, id, status=0, fetch_child=0, simple=True): """ @@ -92,13 +82,13 @@ def get_users(self, id, status=0, fetch_child=0, simple=True): :param simple: True 获取部门成员,False 获取部门成员详情 :return: 部门成员列表 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': id, - 'status': status, - 'fetch_child': 1 if fetch_child else 0 - } + "department_id": id, + "status": status, + "fetch_child": 1 if fetch_child else 0, + }, ) - return res['userlist'] + return res["userlist"] diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py index 59571df..d0b7be6 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/jsapi.py @@ -20,7 +20,7 @@ def get_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('get_jsapi_ticket') + return self._get("get_jsapi_ticket") def get_jsapi_signature(self, noncestr, ticket, timestamp, url): """ @@ -35,12 +35,12 @@ def get_jsapi_signature(self, noncestr, ticket, timestamp, url): :return: 签名 """ data = [ - 'noncestr={noncestr}'.format(noncestr=noncestr), - 'jsapi_ticket={ticket}'.format(ticket=ticket), - 'timestamp={timestamp}'.format(timestamp=timestamp), - 'url={url}'.format(url=url), + "noncestr={noncestr}".format(noncestr=noncestr), + "jsapi_ticket={ticket}".format(ticket=ticket), + "timestamp={timestamp}".format(timestamp=timestamp), + "url={url}".format(url=url), ] - signer = WeChatSigner(delimiter=b'&') + signer = WeChatSigner(delimiter=b"&") signer.add_data(*data) return signer.signature @@ -52,7 +52,7 @@ def get_agent_ticket(self): :return: 返回的 JSON 数据包 """ - return self._get('ticket/get', params={'type': 'agent_config'}) + return self._get("ticket/get", params={"type": "agent_config"}) def get_jsapi_ticket(self): """ @@ -62,14 +62,14 @@ def get_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket @@ -82,14 +82,14 @@ def get_agent_jsapi_ticket(self): :return: ticket """ - ticket_key = '{}_agent_jsapi_ticket'.format(self._client.corp_id) - expires_at_key = '{}_agent_jsapi_ticket_expires_at'.format(self._client.corp_id) + ticket_key = "{}_agent_jsapi_ticket".format(self._client.corp_id) + expires_at_key = "{}_agent_jsapi_ticket_expires_at".format(self._client.corp_id) ticket = self.session.get(ticket_key) expires_at = self.session.get(expires_at_key, 0) if not ticket or expires_at < int(time.time()): jsapi_ticket = self.get_agent_ticket() - ticket = jsapi_ticket['ticket'] - expires_at = int(time.time()) + int(jsapi_ticket['expires_in']) + ticket = jsapi_ticket["ticket"] + expires_at = int(time.time()) + int(jsapi_ticket["expires_in"]) self.session.set(ticket_key, ticket) self.session.set(expires_at_key, expires_at) return ticket diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/material.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/material.py index 9de5fef..2c23f37 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/material.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/material.py @@ -19,22 +19,19 @@ def add_articles(self, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) - return self._post( - 'material/add_mpnews', - data={ - "mpnews": { - "articles": articles_data + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), } - } + ) + return self._post( + "material/add_mpnews", data={"mpnews": {"articles": articles_data}} ) def add(self, agent_id, media_type, media_file): @@ -49,15 +46,11 @@ def add(self, agent_id, media_type, media_file): :return: 返回的 JSON 数据包 """ params = { - 'agentid': agent_id, - 'type': media_type, + "agentid": agent_id, + "type": media_type, } return self._post( - url='material/add_material', - params=params, - files={ - 'media': media_file - } + url="material/add_material", params=params, files={"media": media_file} ) def get_url(self, agent_id, media_id): @@ -71,15 +64,15 @@ def get_url(self, agent_id, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/material/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/material/get", + "?access_token=", self.access_token, - '&media_id=', + "&media_id=", media_id, - '&agentid=', + "&agentid=", agent_id, ) - return ''.join(parts) + return "".join(parts) def get(self, agent_id, media_id): """ @@ -104,11 +97,11 @@ def get_articles(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get', + "material/get", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def delete(self, agent_id, media_id): @@ -122,11 +115,11 @@ def delete(self, agent_id, media_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/del', + "material/del", params={ - 'agentid': agent_id, - 'media_id': media_id, - } + "agentid": agent_id, + "media_id": media_id, + }, ) def update_articles(self, agent_id, media_id, articles): @@ -142,22 +135,20 @@ def update_articles(self, agent_id, media_id, articles): """ articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'title': article['title'], - 'content': article['content'], - 'author': article.get('author', ''), - 'content_source_url': article.get('content_source_url', ''), - 'digest': article.get('digest', ''), - 'show_cover_pic': article.get('show_cover_pic', 0) - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "title": article["title"], + "content": article["content"], + "author": article.get("author", ""), + "content_source_url": article.get("content_source_url", ""), + "digest": article.get("digest", ""), + "show_cover_pic": article.get("show_cover_pic", 0), + } + ) return self._post( - 'material/update_news', - data={ - 'agentid': agent_id, - 'media_id': media_id, - 'articles': articles_data - } + "material/update_news", + data={"agentid": agent_id, "media_id": media_id, "articles": articles_data}, ) def get_count(self, agent_id): @@ -170,10 +161,10 @@ def get_count(self, agent_id): :return: 返回的 JSON 数据包 """ return self._get( - 'material/get_count', + "material/get_count", params={ - 'agent_id': agent_id, - } + "agent_id": agent_id, + }, ) def batchget(self, agent_id, media_type, offset=0, count=20): @@ -190,11 +181,11 @@ def batchget(self, agent_id, media_type, offset=0, count=20): :return: 返回的 JSON 数据包 """ return self._post( - 'material/batchget', + "material/batchget", data={ - 'agent_id': agent_id, - 'type': media_type, - 'offset': offset, - 'count': count - } + "agent_id": agent_id, + "type": media_type, + "offset": offset, + "count": count, + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/media.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/media.py index 15762f3..4705bbf 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/media.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/media.py @@ -23,7 +23,9 @@ def upload(self, media_type, media_file): :param media_file: 要上传的文件,一个 File-object :return: 返回的 JSON 数据包 """ - return self._post('media/upload', params={'type': media_type}, files={'media': media_file}) + return self._post( + "media/upload", params={"type": media_type}, files={"media": media_file} + ) def upload_img(self, image_file): """ @@ -38,7 +40,7 @@ def upload_img(self, image_file): :return: 返回的 JSON 数据包 """ - return self._post('media/uploadimg', files={'media': image_file}) + return self._post("media/uploadimg", files={"media": image_file}) def get_url(self, media_id): """ @@ -50,13 +52,13 @@ def get_url(self, media_id): :return: 临时素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def get_jssdk_url(self, media_id): """ @@ -68,13 +70,13 @@ def get_jssdk_url(self, media_id): :return: 高清语音素材下载地址 """ parts = ( - 'https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk', - '?access_token=', + "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk", + "?access_token=", self.access_token, - '&media_id=', - media_id + "&media_id=", + media_id, ) - return ''.join(parts) + return "".join(parts) def download(self, media_id): """ diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/menu.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/menu.py index 612fb25..41aabd2 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/menu.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/menu.py @@ -19,13 +19,7 @@ def create(self, agent_id, menu_data): :param agent_id: 应用id """ - return self._post( - 'menu/create', - params={ - 'agentid': agent_id - }, - data=menu_data - ) + return self._post("menu/create", params={"agentid": agent_id}, data=menu_data) def get(self, agent_id): """ @@ -35,12 +29,7 @@ def get(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/get', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/get", params={"agentid": agent_id}) def delete(self, agent_id): """ @@ -50,12 +39,7 @@ def delete(self, agent_id): :param agent_id: 应用id """ - return self._get( - 'menu/delete', - params={ - 'agentid': agent_id - } - ) + return self._get("menu/delete", params={"agentid": agent_id}) def update(self, agent_id, menu_data): self.delete(agent_id) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/message.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/message.py index 21b2988..9952ebc 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/message.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/message.py @@ -25,8 +25,7 @@ class WeChatMessage(BaseWeChatAPI): * 小程序通知消息 """ - def send(self, agent_id, user_ids, party_ids='', - tag_ids='', msg=None): + def send(self, agent_id, user_ids, party_ids="", tag_ids="", msg=None): """ 通用的消息发送接口。msg 内需要指定 msgtype 和对应类型消息必须的字段。 如果部分接收人无权限或不存在,发送仍然执行,但会返回无效的部分(即invaliduser或invalidparty或invalidtag),常见的原因是接收人不在应用的可见范围内。 @@ -42,38 +41,42 @@ def send(self, agent_id, user_ids, party_ids='', """ msg = msg or {} if isinstance(user_ids, (tuple, list)): - user_ids = '|'.join(user_ids) + user_ids = "|".join(user_ids) if isinstance(party_ids, (tuple, list)): - party_ids = '|'.join(party_ids) + party_ids = "|".join(party_ids) if isinstance(tag_ids, (tuple, list)): - tag_ids = '|'.join(tag_ids) + tag_ids = "|".join(tag_ids) data = { - 'touser': user_ids, - 'toparty': party_ids, - 'totag': tag_ids, - 'agentid': agent_id + "touser": user_ids, + "toparty": party_ids, + "totag": tag_ids, + "agentid": agent_id, } data.update(msg) - return self._post('message/send', data=data) + return self._post("message/send", data=data) - def send_text(self, agent_id, user_ids, content, - party_ids='', tag_ids='', safe=0): + def send_text(self, agent_id, user_ids, content, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'text', - 'text': {'content': content}, - 'safe': safe - } + msg={"msgtype": "text", "text": {"content": content}, "safe": safe}, ) - def send_text_card(self, agent_id, user_ids, title, description, url, btntxt='详情', - party_ids='', tag_ids=''): - """ 文本卡片消息 + def send_text_card( + self, + agent_id, + user_ids, + title, + description, + url, + btntxt="详情", + party_ids="", + tag_ids="", + ): + """文本卡片消息 https://work.weixin.qq.com/api/doc#90000/90135/90236/文本卡片消息 @@ -113,129 +116,114 @@ def send_text_card(self, agent_id, user_ids, title, description, url, btntxt=' party_ids, tag_ids, msg={ - 'msgtype': 'textcard', - 'textcard': { - 'title': title, - 'description': description, - 'url': url, - 'btntxt': btntxt, + "msgtype": "textcard", + "textcard": { + "title": title, + "description": description, + "url": url, + "btntxt": btntxt, }, - } + }, ) - def send_image(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_image( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'image', - 'image': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "image", "image": {"media_id": media_id}, "safe": safe}, ) - def send_voice(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_voice( + self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0 + ): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'voice', - 'voice': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "voice", "voice": {"media_id": media_id}, "safe": safe}, ) - def send_video(self, agent_id, user_ids, media_id, title=None, - description=None, party_ids='', tag_ids='', safe=0): + def send_video( + self, + agent_id, + user_ids, + media_id, + title=None, + description=None, + party_ids="", + tag_ids="", + safe=0, + ): video_data = optionaldict() - video_data['media_id'] = media_id - video_data['title'] = title - video_data['description'] = description + video_data["media_id"] = media_id + video_data["title"] = title + video_data["description"] = description return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'video', - 'video': dict(video_data), - 'safe': safe - } + msg={"msgtype": "video", "video": dict(video_data), "safe": safe}, ) - def send_file(self, agent_id, user_ids, media_id, - party_ids='', tag_ids='', safe=0): + def send_file(self, agent_id, user_ids, media_id, party_ids="", tag_ids="", safe=0): return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'file', - 'file': { - 'media_id': media_id - }, - 'safe': safe - } + msg={"msgtype": "file", "file": {"media_id": media_id}, "safe": safe}, ) - def send_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids=''): + def send_articles(self, agent_id, user_ids, articles, party_ids="", tag_ids=""): articles_data = [] for article in articles: - articles_data.append({ - 'title': article['title'], - 'description': article['description'], - 'url': article['url'], - 'picurl': article['image'] - }) + articles_data.append( + { + "title": article["title"], + "description": article["description"], + "url": article["url"], + "picurl": article["image"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, - msg={ - 'msgtype': 'news', - 'news': { - 'articles': articles_data - } - } + msg={"msgtype": "news", "news": {"articles": articles_data}}, ) - def send_mp_articles(self, agent_id, user_ids, articles, - party_ids='', tag_ids='', safe=0): + def send_mp_articles( + self, agent_id, user_ids, articles, party_ids="", tag_ids="", safe=0 + ): articles_data = [] for article in articles: - articles_data.append({ - 'thumb_media_id': article['thumb_media_id'], - 'author': article['author'], - 'title': article['title'], - 'content': article['content'], - 'content_source_url': article['content_source_url'], - 'digest': article['digest'], - 'show_cover_pic': article['show_cover_pic'] - }) + articles_data.append( + { + "thumb_media_id": article["thumb_media_id"], + "author": article["author"], + "title": article["title"], + "content": article["content"], + "content_source_url": article["content_source_url"], + "digest": article["digest"], + "show_cover_pic": article["show_cover_pic"], + } + ) return self.send( agent_id, user_ids, party_ids, tag_ids, msg={ - 'msgtype': 'mpnews', - 'mpnews': { - 'articles': articles_data - }, - 'safe': safe - } + "msgtype": "mpnews", + "mpnews": {"articles": articles_data}, + "safe": safe, + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/misc.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/misc.py index 54c356c..34c9e2f 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/misc.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/misc.py @@ -14,5 +14,5 @@ def get_wechat_ips(self): :return: 企业微信回调的IP段 """ - res = self._get('getcallbackip') - return res['ip_list'] + res = self._get("getcallbackip") + return res["ip_list"] diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/oauth.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/oauth.py index cffe7ca..9bb913a 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/oauth.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/oauth.py @@ -7,7 +7,7 @@ class WeChatOAuth(BaseWeChatAPI): - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize' + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" def authorize_url(self, redirect_uri, state=None): """ @@ -19,19 +19,19 @@ def authorize_url(self, redirect_uri, state=None): :param state: 重定向后会带上 state 参数 :return: 返回的 JSON 数据包 """ - redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b'') + redirect_uri = six.moves.urllib.parse.quote(redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - '?appid=', + "?appid=", self._client.corp_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=snsapi_base', + "&response_type=code&scope=snsapi_base", ] if state: - url_list.extend(['&state=', state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def get_user_info(self, code): """ @@ -44,8 +44,8 @@ def get_user_info(self, code): """ return self._get( - 'order/getuserinfo', + "order/getuserinfo", params={ - 'code': code, - } + "code": code, + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/service.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/service.py index 75ba8ee..2b4d083 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/service.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/service.py @@ -23,11 +23,11 @@ def get_provider_token(self, provider_secret): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_provider_token', + "service/get_provider_token", data={ - 'corpid': self._client.corp_id, - 'provider_secret': provider_secret, - } + "corpid": self._client.corp_id, + "provider_secret": provider_secret, + }, ) def get_suite_token(self, suite_id, suite_secret, suite_ticket): @@ -42,12 +42,12 @@ def get_suite_token(self, suite_id, suite_secret, suite_ticket): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_suite_token', + "service/get_suite_token", data={ - 'suite_id': suite_id, - 'suite_secret': suite_secret, - 'suite_ticket': suite_ticket - } + "suite_id": suite_id, + "suite_secret": suite_secret, + "suite_ticket": suite_ticket, + }, ) def get_login_info(self, auth_code, provider_access_token=None): @@ -62,16 +62,18 @@ def get_login_info(self, auth_code, provider_access_token=None): :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_info', + "service/get_login_info", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'auth_code': auth_code, - } + "auth_code": auth_code, + }, ) - def get_login_url(self, login_ticket, target, agentid=None, provider_access_token=None): + def get_login_url( + self, login_ticket, target, agentid=None, provider_access_token=None + ): """ 获取登录企业号官网的url @@ -85,13 +87,13 @@ def get_login_url(self, login_ticket, target, agentid=None, provider_access_toke :return: 返回的 JSON 数据包 """ return self._post( - 'service/get_login_url', + "service/get_login_url", params={ - 'provider_access_token': provider_access_token, + "provider_access_token": provider_access_token, }, data={ - 'login_ticket': login_ticket, - 'target': target, - 'agentid': agentid, - } + "login_ticket": login_ticket, + "target": target, + "agentid": agentid, + }, ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py index 0155576..047ebbc 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py @@ -15,10 +15,5 @@ def get_shake_info(self, ticket): :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 :return: 设备及用户信息 """ - res = self._post( - 'shakearound/getshakeinfo', - data={ - 'ticket': ticket - } - ) - return res['data'] + res = self._post("shakearound/getshakeinfo", data={"ticket": ticket}) + return res["data"] diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/tag.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/tag.py index dce5dd5..8db6f66 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/tag.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/tag.py @@ -12,56 +12,27 @@ class WeChatTag(BaseWeChatAPI): """ def create(self, name): - return self._post( - 'tag/create', - data={ - 'tagname': name - } - ) + return self._post("tag/create", data={"tagname": name}) def update(self, tag_id, name): - return self._post( - 'tag/update', - data={ - 'tagid': tag_id, - 'tagname': name - } - ) + return self._post("tag/update", data={"tagid": tag_id, "tagname": name}) def delete(self, tag_id): - return self._get( - 'tag/delete', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/delete", params={"tagid": tag_id}) def get_users(self, tag_id): - return self._get( - 'tag/get', - params={ - 'tagid': tag_id - } - ) + return self._get("tag/get", params={"tagid": tag_id}) def add_users(self, tag_id, user_ids): return self._post( - 'tag/addtagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/addtagusers", data={"tagid": tag_id, "userlist": user_ids} ) def delete_users(self, tag_id, user_ids): return self._post( - 'tag/deltagusers', - data={ - 'tagid': tag_id, - 'userlist': user_ids - } + "tag/deltagusers", data={"tagid": tag_id, "userlist": user_ids} ) def list(self): - res = self._get('tag/list') - return res['taglist'] + res = self._get("tag/list") + return res["taglist"] diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/user.py b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/user.py index bd5e367..e94404c 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/client/api/user.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/client/api/user.py @@ -15,30 +15,37 @@ class WeChatUser(BaseWeChatAPI): 邀请成员接口位于 `WeChatBatch.invite` """ - def create(self, user_id, name, department=None, position=None, - mobile=None, gender=0, tel=None, email=None, - weixin_id=None, extattr=None): + def create( + self, + user_id, + name, + department=None, + position=None, + mobile=None, + gender=0, + tel=None, + email=None, + weixin_id=None, + extattr=None, + ): """ 创建成员 https://work.weixin.qq.com/api/doc#90000/90135/90195 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - - return self._post( - 'order/create', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + + return self._post("order/create", data=user_data) def get(self, user_id): """ @@ -46,38 +53,41 @@ def get(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90196 """ - return self._get( - 'order/get', - params={ - 'userid': user_id - } - ) - - def update(self, user_id, name=None, department=None, position=None, - mobile=None, gender=None, tel=None, email=None, - weixin_id=None, enable=None, extattr=None): + return self._get("order/get", params={"userid": user_id}) + + def update( + self, + user_id, + name=None, + department=None, + position=None, + mobile=None, + gender=None, + tel=None, + email=None, + weixin_id=None, + enable=None, + extattr=None, + ): """ 更新成员 https://work.weixin.qq.com/api/doc#90000/90135/90197 """ user_data = optionaldict() - user_data['userid'] = user_id - user_data['name'] = name - user_data['gender'] = gender - user_data['department'] = department - user_data['position'] = position - user_data['mobile'] = mobile - user_data['tel'] = tel - user_data['email'] = email - user_data['weixinid'] = weixin_id - user_data['extattr'] = extattr - user_data['enable'] = enable - - return self._post( - 'order/update', - data=user_data - ) + user_data["userid"] = user_id + user_data["name"] = name + user_data["gender"] = gender + user_data["department"] = department + user_data["position"] = position + user_data["mobile"] = mobile + user_data["tel"] = tel + user_data["email"] = email + user_data["weixinid"] = weixin_id + user_data["extattr"] = extattr + user_data["enable"] = enable + + return self._post("order/update", data=user_data) def delete(self, user_id): """ @@ -85,12 +95,7 @@ def delete(self, user_id): https://work.weixin.qq.com/api/doc#90000/90135/90198 """ - return self._get( - 'order/delete', - params={ - 'userid': user_id - } - ) + return self._get("order/delete", params={"userid": user_id}) def batch_delete(self, user_ids): """ @@ -98,12 +103,7 @@ def batch_delete(self, user_ids): https://work.weixin.qq.com/api/doc#90000/90135/90199 """ - return self._post( - 'order/batchdelete', - data={ - 'useridlist': user_ids - } - ) + return self._post("order/batchdelete", data={"useridlist": user_ids}) def list(self, department_id, fetch_child=False, status=0, simple=False): """ @@ -114,16 +114,16 @@ def list(self, department_id, fetch_child=False, status=0, simple=False): 此接口和 `WeChatDepartment.get_users` 是同一个接口,区别为 simple 的默认值不同。 """ - url = 'order/simplelist' if simple else 'order/list' + url = "order/simplelist" if simple else "order/list" res = self._get( url, params={ - 'department_id': department_id, - 'fetch_child': 1 if fetch_child else 0, - 'status': status - } + "department_id": department_id, + "fetch_child": 1 if fetch_child else 0, + "status": status, + }, ) - return res['userlist'] + return res["userlist"] def convert_to_openid(self, user_id, agent_id=None): """ @@ -135,11 +135,8 @@ def convert_to_openid(self, user_id, agent_id=None): :param agent_id: 可选,需要发送红包的应用ID,若只是使用微信支付和企业转账,则无需该参数 :return: 返回的 JSON 数据包 """ - data = optionaldict( - userid=user_id, - agentid=agent_id - ) - return self._post('order/convert_to_openid', data=data) + data = optionaldict(userid=user_id, agentid=agent_id) + return self._post("order/convert_to_openid", data=data) def convert_to_user_id(self, openid): """ @@ -150,8 +147,8 @@ def convert_to_user_id(self, openid): :param openid: 在使用微信支付、微信红包和企业转账之后,返回结果的openid :return: 该 openid 在企业微信中对应的成员 user_id """ - res = self._post('order/convert_to_userid', data={'openid': openid}) - return res['userid'] + res = self._post("order/convert_to_userid", data={"openid": openid}) + return res["userid"] def verify(self, user_id): """ @@ -161,18 +158,9 @@ def verify(self, user_id): :param user_id: 成员UserID。对应管理端的帐号 """ - return self._get( - 'order/authsucc', - params={ - 'userid': user_id - } - ) + return self._get("order/authsucc", params={"userid": user_id}) def get_info(self, agent_id, code): return self._get( - 'order/getuserinfo', - params={ - 'agentid': agent_id, - 'code': code - } + "order/getuserinfo", params={"agentid": agent_id, "code": code} ) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/crypto.py b/chapter14/booking_system/exts/wechatpy/enterprise/crypto.py index 9b14bd6..90e6f4a 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/crypto.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/crypto.py @@ -20,27 +20,10 @@ def __init__(self, token, encoding_aes_key, corp_id): self.corp_id = corp_id def check_signature(self, signature, timestamp, nonce, echo_str): - return self._check_signature( - signature, - timestamp, - nonce, - echo_str, - PrpCrypto - ) + return self._check_signature(signature, timestamp, nonce, echo_str, PrpCrypto) def encrypt_message(self, msg, nonce, timestamp=None): - return self._encrypt_message( - msg, - nonce, - timestamp, - PrpCrypto - ) + return self._encrypt_message(msg, nonce, timestamp, PrpCrypto) def decrypt_message(self, msg, signature, timestamp, nonce): - return self._decrypt_message( - msg, - signature, - timestamp, - nonce, - PrpCrypto - ) + return self._decrypt_message(msg, signature, timestamp, nonce, PrpCrypto) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/exceptions.py b/chapter14/booking_system/exts/wechatpy/enterprise/exceptions.py index a4ac5ee..13cd7f5 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/exceptions.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/exceptions.py @@ -6,5 +6,5 @@ class InvalidCorpIdException(WeChatException): - def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): + def __init__(self, errcode=-40005, errmsg="Invalid corp_id"): super(InvalidCorpIdException, self).__init__(errcode, errmsg) diff --git a/chapter14/booking_system/exts/wechatpy/enterprise/parser.py b/chapter14/booking_system/exts/wechatpy/enterprise/parser.py index 31fa199..7d1040d 100644 --- a/chapter14/booking_system/exts/wechatpy/enterprise/parser.py +++ b/chapter14/booking_system/exts/wechatpy/enterprise/parser.py @@ -12,10 +12,10 @@ def parse_message(xml): if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() - if message_type == 'event': - event_type = message['Event'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() + if message_type == "event": + event_type = message["Event"].lower() message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter14/booking_system/exts/wechatpy/events.py b/chapter14/booking_system/exts/wechatpy/events.py index eeb03db..a1ba320 100644 --- a/chapter14/booking_system/exts/wechatpy/events.py +++ b/chapter14/booking_system/exts/wechatpy/events.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.events - ~~~~~~~~~~~~~~~~ +wechatpy.events +~~~~~~~~~~~~~~~~ - This module contains all the events WeChat callback uses. +This module contains all the events WeChat callback uses. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -16,7 +16,7 @@ IntegerField, BaseField, Base64DecodeField, - DateTimeField + DateTimeField, ) from exts.wechatpy.messages import BaseMessage @@ -30,19 +30,22 @@ def register_event(event_type): :param event_type: Event type """ + def register(cls): EVENT_TYPES[event_type] = cls return cls + return register class BaseEvent(BaseMessage): """Base class for all events""" - type = 'event' - event = '' + + type = "event" + event = "" -@register_event('subscribe') +@register_event("subscribe") class SubscribeEvent(BaseEvent): """ 用户关注事件 @@ -50,11 +53,12 @@ class SubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe' - key = StringField('EventKey', '') + event = "subscribe" + key = StringField("EventKey", "") -@register_event('unsubscribe') + +@register_event("unsubscribe") class UnsubscribeEvent(BaseEvent): """ 用户取消关注事件 @@ -62,10 +66,11 @@ class UnsubscribeEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'unsubscribe' + + event = "unsubscribe" -@register_event('subscribe_scan') +@register_event("subscribe_scan") class SubscribeScanEvent(BaseEvent): """ 用户扫描二维码关注事件 @@ -73,12 +78,13 @@ class SubscribeScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'subscribe_scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + event = "subscribe_scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('scan') + +@register_event("scan") class ScanEvent(BaseEvent): """ 用户扫描二维码事件 @@ -86,12 +92,13 @@ class ScanEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'scan' - scene_id = StringField('EventKey') - ticket = StringField('Ticket') + + event = "scan" + scene_id = StringField("EventKey") + ticket = StringField("Ticket") -@register_event('location') +@register_event("location") class LocationEvent(BaseEvent): """ 上报地理位置事件 @@ -99,13 +106,14 @@ class LocationEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'location' - latitude = FloatField('Latitude', 0.0) - longitude = FloatField('Longitude', 0.0) - precision = FloatField('Precision', 0.0) + + event = "location" + latitude = FloatField("Latitude", 0.0) + longitude = FloatField("Longitude", 0.0) + precision = FloatField("Precision", 0.0) -@register_event('click') +@register_event("click") class ClickEvent(BaseEvent): """ 点击菜单拉取消息事件 @@ -113,11 +121,12 @@ class ClickEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'click' - key = StringField('EventKey') + event = "click" + key = StringField("EventKey") -@register_event('view') + +@register_event("view") class ViewEvent(BaseEvent): """ 点击菜单跳转链接事件 @@ -125,11 +134,12 @@ class ViewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421140454 """ - event = 'view' - url = StringField('EventKey') + + event = "view" + url = StringField("EventKey") -@register_event('masssendjobfinish') +@register_event("masssendjobfinish") class MassSendJobFinishEvent(BaseEvent): """ 群发消息任务完成事件 @@ -137,16 +147,17 @@ class MassSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1481187827_i0l21 """ - id = IntegerField('MsgID', 0) - event = 'masssendjobfinish' - status = StringField('Status') - total_count = IntegerField('TotalCount', 0) - filter_count = IntegerField('FilterCount', 0) - sent_count = IntegerField('SentCount', 0) - error_count = IntegerField('ErrorCount', 0) + id = IntegerField("MsgID", 0) + event = "masssendjobfinish" + status = StringField("Status") + total_count = IntegerField("TotalCount", 0) + filter_count = IntegerField("FilterCount", 0) + sent_count = IntegerField("SentCount", 0) + error_count = IntegerField("ErrorCount", 0) -@register_event('templatesendjobfinish') + +@register_event("templatesendjobfinish") class TemplateSendJobFinishEvent(BaseEvent): """ 模板消息任务完成事件 @@ -154,25 +165,26 @@ class TemplateSendJobFinishEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1433751277 """ - id = IntegerField('MsgID') - event = 'templatesendjobfinish' - status = StringField('Status') + + id = IntegerField("MsgID") + event = "templatesendjobfinish" + status = StringField("Status") class BaseScanCodeEvent(BaseEvent): - key = StringField('EventKey') - scan_code_info = BaseField('ScanCodeInfo', {}) + key = StringField("EventKey") + scan_code_info = BaseField("ScanCodeInfo", {}) @property def scan_type(self): - return self.scan_code_info['ScanType'] + return self.scan_code_info["ScanType"] @property def scan_result(self): - return self.scan_code_info['ScanResult'] + return self.scan_code_info["ScanResult"] -@register_event('scancode_push') +@register_event("scancode_push") class ScanCodePushEvent(BaseScanCodeEvent): """ 扫码推事件 @@ -180,10 +192,11 @@ class ScanCodePushEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_push' + + event = "scancode_push" -@register_event('scancode_waitmsg') +@register_event("scancode_waitmsg") class ScanCodeWaitMsgEvent(BaseScanCodeEvent): """ 扫码推事件且弹出“消息接收中”提示框的事件 @@ -191,28 +204,29 @@ class ScanCodeWaitMsgEvent(BaseScanCodeEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'scancode_waitmsg' + + event = "scancode_waitmsg" class BasePictureEvent(BaseEvent): - key = StringField('EventKey') - pictures_info = BaseField('SendPicsInfo', {}) + key = StringField("EventKey") + pictures_info = BaseField("SendPicsInfo", {}) @property def count(self): - return int(self.pictures_info['Count']) + return int(self.pictures_info["Count"]) @property def pictures(self): - if self.pictures_info['PicList']: - items = self.pictures_info['PicList']['item'] + if self.pictures_info["PicList"]: + items = self.pictures_info["PicList"]["item"] if self.count > 1: return items return [items] return [] -@register_event('pic_sysphoto') +@register_event("pic_sysphoto") class PicSysPhotoEvent(BasePictureEvent): """ 弹出系统拍照发图的事件 @@ -220,10 +234,11 @@ class PicSysPhotoEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_sysphoto' + + event = "pic_sysphoto" -@register_event('pic_photo_or_album') +@register_event("pic_photo_or_album") class PicPhotoOrAlbumEvent(BasePictureEvent): """ 弹出拍照或者相册发图的事件 @@ -231,10 +246,11 @@ class PicPhotoOrAlbumEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_photo_or_album' + event = "pic_photo_or_album" -@register_event('pic_weixin') + +@register_event("pic_weixin") class PicWeChatEvent(BasePictureEvent): """ 弹出微信相册发图器的事件 @@ -242,10 +258,11 @@ class PicWeChatEvent(BasePictureEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'pic_weixin' + + event = "pic_weixin" -@register_event('location_select') +@register_event("location_select") class LocationSelectEvent(BaseEvent): """ 弹出地理位置选择器的事件 @@ -253,17 +270,18 @@ class LocationSelectEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1421141016 """ - event = 'location_select' - key = StringField('EventKey') - location_info = BaseField('SendLocationInfo', {}) + + event = "location_select" + key = StringField("EventKey") + location_info = BaseField("SendLocationInfo", {}) @property def location_x(self): - return self.location_info['Location_X'] + return self.location_info["Location_X"] @property def location_y(self): - return self.location_info['Location_Y'] + return self.location_info["Location_Y"] @property def location(self): @@ -271,30 +289,30 @@ def location(self): @property def scale(self): - return self.location_info['Scale'] + return self.location_info["Scale"] @property def label(self): - return self.location_info['Label'] + return self.location_info["Label"] @property def poiname(self): - return self.location_info['Poiname'] + return self.location_info["Poiname"] -@register_event('card_pass_check') +@register_event("card_pass_check") class CardPassCheckEvent(BaseEvent): - event = 'card_pass_check' - card_id = StringField('CardId') + event = "card_pass_check" + card_id = StringField("CardId") -@register_event('card_not_pass_check') +@register_event("card_not_pass_check") class CardNotPassCheckEvent(BaseEvent): - event = 'card_not_pass_check' - card_id = StringField('CardId') + event = "card_not_pass_check" + card_id = StringField("CardId") -@register_event('user_get_card') +@register_event("user_get_card") class UserGetCardEvent(BaseEvent): """ 领取事件推送 @@ -302,16 +320,17 @@ class UserGetCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_get_card' - card_id = StringField('CardId') - is_given_by_friend = IntegerField('IsGiveByFriend') - friend = StringField('FriendUserName') - code = StringField('UserCardCode') - old_code = StringField('OldUserCardCode') - outer_id = StringField('OuterId') + + event = "user_get_card" + card_id = StringField("CardId") + is_given_by_friend = IntegerField("IsGiveByFriend") + friend = StringField("FriendUserName") + code = StringField("UserCardCode") + old_code = StringField("OldUserCardCode") + outer_id = StringField("OuterId") -@register_event('user_del_card') +@register_event("user_del_card") class UserDeleteCardEvent(BaseEvent): """ 卡券删除事件推送 @@ -319,12 +338,13 @@ class UserDeleteCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_del_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') + event = "user_del_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") -@register_event('user_consume_card') + +@register_event("user_consume_card") class UserConsumeCardEvent(BaseEvent): """ 卡券核销事件推送 @@ -332,95 +352,96 @@ class UserConsumeCardEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1451025274 """ - event = 'user_consume_card' - card_id = StringField('CardId') - code = StringField('UserCardCode') - consume_source = StringField('ConsumeSource') - location_id = StringField('LocationId') - staff = StringField('StaffOpenId') + + event = "user_consume_card" + card_id = StringField("CardId") + code = StringField("UserCardCode") + consume_source = StringField("ConsumeSource") + location_id = StringField("LocationId") + staff = StringField("StaffOpenId") -@register_event('merchant_order') +@register_event("merchant_order") class MerchantOrderEvent(BaseEvent): - event = 'merchant_order' - order_id = StringField('OrderId') - order_status = IntegerField('OrderStatus') - product_id = StringField('ProductId') - sku_info = StringField('SkuInfo') + event = "merchant_order" + order_id = StringField("OrderId") + order_status = IntegerField("OrderStatus") + product_id = StringField("ProductId") + sku_info = StringField("SkuInfo") -@register_event('kf_create_session') +@register_event("kf_create_session") class KfCreateSessionEvent(BaseEvent): - event = 'kf_create_session' - account = StringField('KfAccount') + event = "kf_create_session" + account = StringField("KfAccount") -@register_event('kf_close_session') +@register_event("kf_close_session") class KfCloseSessionEvent(BaseEvent): - event = 'kf_close_session' - account = StringField('KfAccount') + event = "kf_close_session" + account = StringField("KfAccount") -@register_event('kf_switch_session') +@register_event("kf_switch_session") class KfSwitchSessionEvent(BaseEvent): - event = 'kf_switch_session' - from_account = StringField('FromKfAccount') - to_account = StringField('ToKfAccount') + event = "kf_switch_session" + from_account = StringField("FromKfAccount") + to_account = StringField("ToKfAccount") -@register_event('device_text') +@register_event("device_text") class DeviceTextEvent(BaseEvent): - event = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_bind') +@register_event("device_bind") class DeviceBindEvent(BaseEvent): - event = 'device_bind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_bind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_unbind') +@register_event("device_unbind") class DeviceUnbindEvent(BaseEvent): - event = 'device_unbind' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64DecodeField('Content') - open_id = StringField('OpenID') + event = "device_unbind" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64DecodeField("Content") + open_id = StringField("OpenID") -@register_event('device_subscribe_status') +@register_event("device_subscribe_status") class DeviceSubscribeStatusEvent(BaseEvent): - event = 'device_subscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_subscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('device_unsubscribe_status') +@register_event("device_unsubscribe_status") class DeviceUnsubscribeStatusEvent(BaseEvent): - event = 'device_unsubscribe_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - open_id = StringField('OpenID') - op_type = IntegerField('OpType') + event = "device_unsubscribe_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + open_id = StringField("OpenID") + op_type = IntegerField("OpType") -@register_event('shakearoundusershake') +@register_event("shakearoundusershake") class ShakearoundUserShakeEvent(BaseEvent): - event = 'shakearound_user_shake' - _chosen_beacon = BaseField('ChosenBeacon', {}) - _around_beacons = BaseField('AroundBeacons', {}) + event = "shakearound_user_shake" + _chosen_beacon = BaseField("ChosenBeacon", {}) + _around_beacons = BaseField("AroundBeacons", {}) @property def chosen_beacon(self): @@ -428,10 +449,10 @@ def chosen_beacon(self): if not beacon: return {} return { - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), } @property @@ -441,39 +462,41 @@ def around_beacons(self): return [] ret = [] - for beacon in beacons['AroundBeacon']: - ret.append({ - 'uuid': beacon['Uuid'], - 'major': beacon['Major'], - 'minor': beacon['Minor'], - 'distance': float(beacon['Distance']), - }) + for beacon in beacons["AroundBeacon"]: + ret.append( + { + "uuid": beacon["Uuid"], + "major": beacon["Major"], + "minor": beacon["Minor"], + "distance": float(beacon["Distance"]), + } + ) return ret -@register_event('poi_check_notify') +@register_event("poi_check_notify") class PoiCheckNotifyEvent(BaseEvent): - event = 'poi_check_notify' - poi_id = StringField('PoiId') - uniq_id = StringField('UniqId') - result = StringField('Result') - message = StringField('Msg') + event = "poi_check_notify" + poi_id = StringField("PoiId") + uniq_id = StringField("UniqId") + result = StringField("Result") + message = StringField("Msg") -@register_event('wificonnected') +@register_event("wificonnected") class WiFiConnectedEvent(BaseEvent): - event = 'wificconnected' - connect_time = IntegerField('ConnectTime') - expire_time = IntegerField('ExpireTime') - vendor_id = StringField('VendorId') - shop_id = StringField('PlaceId') - bssid = StringField('DeviceNo') + event = "wificconnected" + connect_time = IntegerField("ConnectTime") + expire_time = IntegerField("ExpireTime") + vendor_id = StringField("VendorId") + shop_id = StringField("PlaceId") + bssid = StringField("DeviceNo") # ============================================================================ # 微信认证事件推送 # ============================================================================ -@register_event('qualification_verify_success') +@register_event("qualification_verify_success") class QualificationVerifySuccessEvent(BaseEvent): """ 资质认证成功事件 @@ -481,11 +504,12 @@ class QualificationVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "qualification_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('qualification_verify_fail') +@register_event("qualification_verify_fail") class QualificationVerifyFailEvent(BaseEvent): """ 资质认证失败事件 @@ -493,12 +517,13 @@ class QualificationVerifyFailEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'qualification_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "qualification_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('naming_verify_success') + +@register_event("naming_verify_success") class NamingVerifySuccessEvent(BaseEvent): """ 名称认证成功事件 @@ -506,11 +531,12 @@ class NamingVerifySuccessEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_success' - expired_time = DateTimeField('ExpiredTime') + + event = "naming_verify_success" + expired_time = DateTimeField("ExpiredTime") -@register_event('naming_verify_fail') +@register_event("naming_verify_fail") class NamingVerifyFailEvent(BaseEvent): """ 名称认证失败事件 @@ -518,12 +544,13 @@ class NamingVerifyFailEvent(BaseEvent): 客户端不打勾,但仍有接口权限。详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'naming_verify_fail' - fail_time = DateTimeField('FailTime') - fail_reason = StringField('FailReason') + event = "naming_verify_fail" + fail_time = DateTimeField("FailTime") + fail_reason = StringField("FailReason") -@register_event('annual_renew') + +@register_event("annual_renew") class AnnualRenewEvent(BaseEvent): """ 年审通知事件 @@ -531,11 +558,12 @@ class AnnualRenewEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'annual_renew' - expired_time = DateTimeField('ExpiredTime') + + event = "annual_renew" + expired_time = DateTimeField("ExpiredTime") -@register_event('verify_expired') +@register_event("verify_expired") class VerifyExpiredEvent(BaseEvent): """ 认证过期失效通知 @@ -543,11 +571,12 @@ class VerifyExpiredEvent(BaseEvent): 详情请参阅 https://mp.weixin.qq.com/wiki?id=mp1455785130 """ - event = 'verify_expired' - expired_time = DateTimeField('ExpiredTime') + event = "verify_expired" + expired_time = DateTimeField("ExpiredTime") -@register_event('user_scan_product') + +@register_event("user_scan_product") class UserScanProductEvent(BaseEvent): """ 打开商品主页事件 @@ -555,17 +584,18 @@ class UserScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - country = StringField('Country') - province = StringField('Province') - city = StringField('City') - sex = IntegerField('Sex') - scene = IntegerField('Scene') + + event = "user_scan_product" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + country = StringField("Country") + province = StringField("Province") + city = StringField("City") + sex = IntegerField("Sex") + scene = IntegerField("Scene") -@register_event('user_scan_product_enter_session') +@register_event("user_scan_product_enter_session") class UserScanProductEnterSessionEvent(BaseEvent): """ 进入公众号事件 @@ -573,12 +603,13 @@ class UserScanProductEnterSessionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_enter_session' - standard = StringField('KeyStandard') - key = StringField('KeyStr') + event = "user_scan_product_enter_session" + standard = StringField("KeyStandard") + key = StringField("KeyStr") -@register_event('user_scan_product_async') + +@register_event("user_scan_product_async") class UserScanProductAsyncEvent(BaseEvent): """ 地理位置信息异步推送事件 @@ -586,13 +617,14 @@ class UserScanProductAsyncEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_async' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - region_code = StringField('RegionCode') + + event = "user_scan_product_async" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + region_code = StringField("RegionCode") -@register_event('user_scan_product_verify_action') +@register_event("user_scan_product_verify_action") class UserScanProductVerifyActionEvent(BaseEvent): """ 商品审核结果事件 @@ -600,14 +632,15 @@ class UserScanProductVerifyActionEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'user_scan_product_verify_action' - standard = StringField('KeyStandard') - key = StringField('KeyStr') - result = StringField('Result') - reason = StringField('ReasonMsg') + + event = "user_scan_product_verify_action" + standard = StringField("KeyStandard") + key = StringField("KeyStr") + result = StringField("Result") + reason = StringField("ReasonMsg") -@register_event('subscribe_scan_product') +@register_event("subscribe_scan_product") class SubscribeScanProductEvent(BaseEvent): """ 用户在商品主页中关注公众号事件 @@ -615,23 +648,24 @@ class SubscribeScanProductEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1455872179 """ - event = 'subscribe_scan_product' - event_key = StringField('EventKey') + + event = "subscribe_scan_product" + event_key = StringField("EventKey") @property def scene(self): - return self.event_key.split('|', 1)[0] + return self.event_key.split("|", 1)[0] @property def standard(self): - return self.event_key.split('|')[1] + return self.event_key.split("|")[1] @property def key(self): - return self.event_key.split('|')[2] + return self.event_key.split("|")[2] -@register_event('user_authorize_invoice') +@register_event("user_authorize_invoice") class UserAuthorizeInvoiceEvent(BaseEvent): """ 用户授权发票事件 @@ -640,14 +674,15 @@ class UserAuthorizeInvoiceEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'user_authorize_invoice' - success_order_id = StringField('SuccOrderId') # 授权成功的订单号 - fail_order_id = StringField('FailOrderId') # 授权失败的订单号 - app_id = StringField('AppId') # 用于接收事件推送的公众号的AppId - auth_source = StringField('Source') # 授权来源,web表示来自微信内H5,app标识来自app + + event = "user_authorize_invoice" + success_order_id = StringField("SuccOrderId") # 授权成功的订单号 + fail_order_id = StringField("FailOrderId") # 授权失败的订单号 + app_id = StringField("AppId") # 用于接收事件推送的公众号的AppId + auth_source = StringField("Source") # 授权来源,web表示来自微信内H5,app标识来自app -@register_event('update_invoice_status') +@register_event("update_invoice_status") class UpdateInvoiceStatusEvent(BaseEvent): """ 发票状态更新事件 @@ -655,13 +690,14 @@ class UpdateInvoiceStatusEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2 """ - event = 'update_invoice_status' - status = StringField('Status') # 发票报销状态 - card_id = StringField('CardId') # 发票 Card ID - code = StringField('Code') # 发票 Code + event = "update_invoice_status" + status = StringField("Status") # 发票报销状态 + card_id = StringField("CardId") # 发票 Card ID + code = StringField("Code") # 发票 Code -@register_event('submit_invoice_title') + +@register_event("submit_invoice_title") class SubmitInvoiceTitleEvent(BaseEvent): """ 用户提交发票抬头事件 @@ -669,33 +705,38 @@ class SubmitInvoiceTitleEvent(BaseEvent): 详情请参考 https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0 """ - event = 'submit_invoice_title' - title = StringField('title') # 抬头 - phone = StringField('phone') # 联系方式 - tax_no = StringField('tax_no') # 税号 - addr = StringField('addr') # 地址 - bank_type = StringField('bank_type') # 银行类型 - bank_no = StringField('bank_no') # 银行号码 - attach = StringField('attach') # 附加字段 - title_type = StringField('title_type') # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType + + event = "submit_invoice_title" + title = StringField("title") # 抬头 + phone = StringField("phone") # 联系方式 + tax_no = StringField("tax_no") # 税号 + addr = StringField("addr") # 地址 + bank_type = StringField("bank_type") # 银行类型 + bank_no = StringField("bank_no") # 银行号码 + attach = StringField("attach") # 附加字段 + title_type = StringField( + "title_type" + ) # 抬头类型,个人InvoiceUserTitlePersonType, 公司InvoiceUserTitleBusinessType -@register_event('user_enter_tempsession') +@register_event("user_enter_tempsession") class UserEnterTempSessionEvent(BaseEvent): """ 小程序用户进入客服消息 详情请参阅 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/receive.html """ - event = 'user_enter_tempsession' - session_from = StringField('SessionFrom') + event = "user_enter_tempsession" + session_from = StringField("SessionFrom") -@register_event('view_miniprogram') + +@register_event("view_miniprogram") class ViewMiniProgramEvent(BaseEvent): """ 从菜单进入小程序事件 """ - event = 'view_miniprogram' - page_path = StringField('EventKey') # 小程序路径 - menu_id = StringField('MenuId') # 菜单ID + + event = "view_miniprogram" + page_path = StringField("EventKey") # 小程序路径 + menu_id = StringField("MenuId") # 菜单ID diff --git a/chapter14/booking_system/exts/wechatpy/exceptions.py b/chapter14/booking_system/exts/wechatpy/exceptions.py index 683da28..f347485 100644 --- a/chapter14/booking_system/exts/wechatpy/exceptions.py +++ b/chapter14/booking_system/exts/wechatpy/exceptions.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.exceptions - ~~~~~~~~~~~~~~~~~~~~ +wechatpy.exceptions +~~~~~~~~~~~~~~~~~~~~ - Basic exceptions definition. +Basic exceptions definition. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -27,9 +27,8 @@ def __init__(self, errcode, errmsg): self.errmsg = errmsg def __str__(self): - _repr = 'Error code: {code}, message: {msg}'.format( - code=self.errcode, - msg=self.errmsg + _repr = "Error code: {code}, message: {msg}".format( + code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -37,10 +36,8 @@ def __str__(self): return to_text(_repr) def __repr__(self): - _repr = '{klass}({code}, {msg})'.format( - klass=self.__class__.__name__, - code=self.errcode, - msg=self.errmsg + _repr = "{klass}({code}, {msg})".format( + klass=self.__class__.__name__, code=self.errcode, msg=self.errmsg ) if six.PY2: return to_binary(_repr) @@ -51,8 +48,7 @@ def __repr__(self): class WeChatClientException(WeChatException): """WeChat API client exception class""" - def __init__(self, errcode, errmsg, client=None, - request=None, response=None): + def __init__(self, errcode, errmsg, client=None, request=None, response=None): super(WeChatClientException, self).__init__(errcode, errmsg) self.client = client self.request = request @@ -62,38 +58,49 @@ def __init__(self, errcode, errmsg, client=None, class InvalidSignatureException(WeChatException): """Invalid signature exception class""" - def __init__(self, errcode=-40001, errmsg='Invalid signature'): + def __init__(self, errcode=-40001, errmsg="Invalid signature"): super(InvalidSignatureException, self).__init__(errcode, errmsg) class APILimitedException(WeChatClientException): """WeChat API call limited exception class""" + pass class InvalidAppIdException(WeChatException): """Invalid app_id exception class""" - def __init__(self, errcode=-40005, errmsg='Invalid AppId'): + def __init__(self, errcode=-40005, errmsg="Invalid AppId"): super(InvalidAppIdException, self).__init__(errcode, errmsg) class WeChatOAuthException(WeChatClientException): """WeChat OAuth API exception class""" + pass class WeChatComponentOAuthException(WeChatClientException): """WeChat Component OAuth API exception class""" + pass class WeChatPayException(WeChatClientException): """WeChat Pay API exception class""" - def __init__(self, return_code, result_code=None, return_msg=None, - errcode=None, errmsg=None, client=None, - request=None, response=None): + def __init__( + self, + return_code, + result_code=None, + return_msg=None, + errcode=None, + errmsg=None, + client=None, + request=None, + response=None, + ): """ :param return_code: 返回状态码 :param result_code: 业务结果 @@ -102,11 +109,7 @@ def __init__(self, return_code, result_code=None, return_msg=None, :param errmsg: 错误代码描述 """ super(WeChatPayException, self).__init__( - errcode, - errmsg, - client, - request, - response + errcode, errmsg, client, request, response ) self.return_code = return_code self.result_code = result_code @@ -114,27 +117,31 @@ def __init__(self, return_code, result_code=None, return_msg=None, def __str__(self): if six.PY2: - return to_binary('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_binary( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) else: - return to_text('Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( - code=self.return_code, - msg=self.return_msg, - pay_code=self.errcode, - pay_msg=self.errmsg - )) + return to_text( + "Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}".format( + code=self.return_code, + msg=self.return_msg, + pay_code=self.errcode, + pay_msg=self.errmsg, + ) + ) def __repr__(self): - _repr = '{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})'.format( + _repr = "{klass}({code}, {msg}). Pay({pay_code}, {pay_msg})".format( klass=self.__class__.__name__, code=self.return_code, msg=self.return_msg, pay_code=self.errcode, - pay_msg=self.errmsg + pay_msg=self.errmsg, ) if six.PY2: return to_binary(_repr) diff --git a/chapter14/booking_system/exts/wechatpy/fields.py b/chapter14/booking_system/exts/wechatpy/fields.py index 8db6847..9a4bdf9 100644 --- a/chapter14/booking_system/exts/wechatpy/fields.py +++ b/chapter14/booking_system/exts/wechatpy/fields.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.fields - ~~~~~~~~~~~~~~~~ +wechatpy.fields +~~~~~~~~~~~~~~~~ - This module defines some useful field types for parse WeChat messages +This module defines some useful field types for parse WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -19,7 +19,7 @@ from exts.wechatpy.utils import to_text, to_binary, ObjectDict, timezone -default_timezone = timezone('Asia/Shanghai') +default_timezone = timezone("Asia/Shanghai") class FieldDescriptor(object): @@ -36,8 +36,11 @@ def __get__(self, instance, instance_type=None): instance._data[self.attr_name] = value if isinstance(value, dict): value = ObjectDict(value) - if value and not isinstance(value, (dict, list, tuple)) and \ - six.callable(self.field.converter): + if ( + value + and not isinstance(value, (dict, list, tuple)) + and six.callable(self.field.converter) + ): value = self.field.converter(value) return value return self.field @@ -61,9 +64,8 @@ def from_xml(cls, value): raise NotImplementedError() def __repr__(self): - _repr = '{klass}({name})'.format( - klass=self.__class__.__name__, - name=repr(self.name) + _repr = "{klass}({name})".format( + klass=self.__class__.__name__, name=repr(self.name) ) if six.PY2: return to_binary(_repr) @@ -85,7 +87,7 @@ def __to_text(self, value): def to_xml(self, value): value = self.converter(value) - tpl = '<{name}>' + tpl = "<{name}>" return tpl.format(name=self.name, value=value) @classmethod @@ -98,7 +100,7 @@ class IntegerField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -110,12 +112,13 @@ class DateTimeField(BaseField): def __converter(self, value): v = int(value) return datetime.fromtimestamp(v, tz=default_timezone) + converter = __converter def to_xml(self, value): value = time.mktime(datetime.timetuple(value)) value = int(value) - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -128,7 +131,7 @@ class FloatField(BaseField): def to_xml(self, value): value = self.converter(value) if value is not None else self.default - tpl = '<{name}>{value}' + tpl = "<{name}>{value}" return tpl.format(name=self.name, value=value) @classmethod @@ -167,62 +170,66 @@ def from_xml(cls, value): class VideoField(StringField): def to_xml(self, value): - kwargs = dict(media_id=self.converter(value['media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' + kwargs = dict(media_id=self.converter(value["media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" tpl = """""".format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(media_id=value['MediaId']) - if 'Title' in value: - rv["title"] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] + rv = dict(media_id=value["MediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] return rv class MusicField(StringField): def to_xml(self, value): - kwargs = dict(thumb_media_id=self.converter(value['thumb_media_id'])) - content = '' - if 'title' in value: - kwargs['title'] = self.converter(value['title']) - content += '<![CDATA[{title}]]>' - if 'description' in value: - kwargs['description'] = self.converter(value['description']) - content += '' - if 'music_url' in value: - kwargs['music_url'] = self.converter(value['music_url']) - content += '' - if 'hq_music_url' in value: - kwargs['hq_music_url'] = self.converter(value['hq_music_url']) - content += '' + kwargs = dict(thumb_media_id=self.converter(value["thumb_media_id"])) + content = "" + if "title" in value: + kwargs["title"] = self.converter(value["title"]) + content += "<![CDATA[{title}]]>" + if "description" in value: + kwargs["description"] = self.converter(value["description"]) + content += "" + if "music_url" in value: + kwargs["music_url"] = self.converter(value["music_url"]) + content += "" + if "hq_music_url" in value: + kwargs["hq_music_url"] = self.converter(value["hq_music_url"]) + content += "" tpl = """ {content} - """.format(content=content) + """.format( + content=content + ) return tpl.format(**kwargs) @classmethod def from_xml(cls, value): - rv = dict(thumb_media_id=value['ThumbMediaId']) - if 'Title' in value: - rv['title'] = value['Title'] - if 'Description' in value: - rv['description'] = value['Description'] - if 'MusicUrl' in value: - rv['music_url'] = value['MusicUrl'] - if 'HQMusicUrl' in value: - rv['hq_music_url'] = value['HQMusicUrl'] + rv = dict(thumb_media_id=value["ThumbMediaId"]) + if "Title" in value: + rv["title"] = value["Title"] + if "Description" in value: + rv["description"] = value["Description"] + if "MusicUrl" in value: + rv["music_url"] = value["MusicUrl"] + if "HQMusicUrl" in value: + rv["hq_music_url"] = value["HQMusicUrl"] return rv @@ -232,10 +239,10 @@ def to_xml(self, articles): article_count = len(articles) items = [] for article in articles: - title = self.converter(article.get('title', '')) - description = self.converter(article.get('description', '')) - image = self.converter(article.get('image', '')) - url = self.converter(article.get('url', '')) + title = self.converter(article.get("title", "")) + description = self.converter(article.get("description", "")) + image = self.converter(article.get("image", "")) + url = self.converter(article.get("url", "")) item_tpl = """ <![CDATA[{title}]]> @@ -243,28 +250,25 @@ def to_xml(self, articles): """ item = item_tpl.format( - title=title, - description=description, - image=image, - url=url + title=title, description=description, image=image, url=url ) items.append(item) - items_str = '\n'.join(items) + items_str = "\n".join(items) tpl = """{article_count} {items}""" - return tpl.format( - article_count=article_count, - items=items_str - ) + return tpl.format(article_count=article_count, items=items_str) @classmethod def from_xml(cls, value): - return [dict( - title=item["Title"], - description=item["Description"], - image=item["PicUrl"], - url=item["Url"] - ) for item in value["item"]] + return [ + dict( + title=item["Title"], + description=item["Description"], + image=item["PicUrl"], + url=item["Url"], + ) + for item in value["item"] + ] class Base64EncodeField(StringField): @@ -286,13 +290,11 @@ def __base64_decode(self, text): class HardwareField(StringField): def to_xml(self, value=None): - value = value or {'view': 'myrank', 'action': 'ranklist'} + value = value or {"view": "myrank", "action": "ranklist"} tpl = """<{name}> """ return tpl.format( - name=self.name, - view=value.get('view'), - action=value.get('action') + name=self.name, view=value.get("view"), action=value.get("action") ) diff --git a/chapter14/booking_system/exts/wechatpy/messages.py b/chapter14/booking_system/exts/wechatpy/messages.py index 04f4d0c..9e33666 100644 --- a/chapter14/booking_system/exts/wechatpy/messages.py +++ b/chapter14/booking_system/exts/wechatpy/messages.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.messages - ~~~~~~~~~~~~~~~~~~ +wechatpy.messages +~~~~~~~~~~~~~~~~~~ - This module defines all the messages you can get from WeChat server +This module defines all the messages you can get from WeChat server - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import copy @@ -17,7 +17,7 @@ StringField, IntegerField, DateTimeField, - FieldDescriptor + FieldDescriptor, ) from exts.wechatpy.utils import to_text, to_binary @@ -29,14 +29,16 @@ def register_message(msg_type): def register(cls): MESSAGE_TYPES[msg_type] = cls return cls + return register class MessageMetaClass(type): """Metaclass for all messages""" + def __new__(cls, name, bases, attrs): for b in bases: - if not hasattr(b, '_fields'): + if not hasattr(b, "_fields"): continue for k, v in b.__dict__.items(): @@ -56,20 +58,20 @@ def __new__(cls, name, bases, attrs): class BaseMessage(six.with_metaclass(MessageMetaClass)): """Base class for all messages and events""" - type = 'unknown' - id = IntegerField('MsgId', 0) - source = StringField('FromUserName') - target = StringField('ToUserName') - create_time = DateTimeField('CreateTime') - time = IntegerField('CreateTime') + + type = "unknown" + id = IntegerField("MsgId", 0) + source = StringField("FromUserName") + target = StringField("ToUserName") + create_time = DateTimeField("CreateTime") + time = IntegerField("CreateTime") def __init__(self, message): self._data = message def __repr__(self): _repr = "{klass}({msg})".format( - klass=self.__class__.__name__, - msg=repr(self._data) + klass=self.__class__.__name__, msg=repr(self._data) ) if six.PY2: return to_binary(_repr) @@ -77,97 +79,105 @@ def __repr__(self): return to_text(_repr) -@register_message('text') +@register_message("text") class TextMessage(BaseMessage): """ 文本消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_message('image') + +@register_message("image") class ImageMessage(BaseMessage): """ 图片消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'image' - media_id = StringField('MediaId') - image = StringField('PicUrl') + + type = "image" + media_id = StringField("MediaId") + image = StringField("PicUrl") -@register_message('voice') +@register_message("voice") class VoiceMessage(BaseMessage): """ 语音消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'voice' - media_id = StringField('MediaId') - format = StringField('Format') - recognition = StringField('Recognition') + + type = "voice" + media_id = StringField("MediaId") + format = StringField("Format") + recognition = StringField("Recognition") -@register_message('shortvideo') +@register_message("shortvideo") class ShortVideoMessage(BaseMessage): """ 短视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'shortvideo' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + type = "shortvideo" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('video') + +@register_message("video") class VideoMessage(BaseMessage): """ 视频消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'video' - media_id = StringField('MediaId') - thumb_media_id = StringField('ThumbMediaId') + + type = "video" + media_id = StringField("MediaId") + thumb_media_id = StringField("ThumbMediaId") -@register_message('location') +@register_message("location") class LocationMessage(BaseMessage): """ 地理位置消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'location' - location_x = StringField('Location_X') - location_y = StringField('Location_Y') - scale = StringField('Scale') - label = StringField('Label') + + type = "location" + location_x = StringField("Location_X") + location_y = StringField("Location_Y") + scale = StringField("Scale") + label = StringField("Label") @property def location(self): return self.location_x, self.location_y -@register_message('link') +@register_message("link") class LinkMessage(BaseMessage): """ 链接消息 详情请参阅 http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html """ - type = 'link' - title = StringField('Title') - description = StringField('Description') - url = StringField('Url') + + type = "link" + title = StringField("Title") + description = StringField("Description") + url = StringField("Url") class UnknownMessage(BaseMessage): """未知消息类型""" + pass diff --git a/chapter14/booking_system/exts/wechatpy/oauth.py b/chapter14/booking_system/exts/wechatpy/oauth.py index db5743a..984cffa 100644 --- a/chapter14/booking_system/exts/wechatpy/oauth.py +++ b/chapter14/booking_system/exts/wechatpy/oauth.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.oauth - ~~~~~~~~~~~~~~~ +wechatpy.oauth +~~~~~~~~~~~~~~~ - This module provides OAuth2 library for WeChat +This module provides OAuth2 library for WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals @@ -18,16 +18,16 @@ class WeChatOAuth(object): - """ 微信公众平台 OAuth 网页授权 + """微信公众平台 OAuth 网页授权 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505 """ - API_BASE_URL = 'https://api.weixin.qq.com/' - OAUTH_BASE_URL = 'https://open.weixin.qq.com/connect/' + API_BASE_URL = "https://api.weixin.qq.com/" + OAUTH_BASE_URL = "https://open.weixin.qq.com/connect/" - def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): + def __init__(self, app_id, secret, redirect_uri, scope="snsapi_base", state=""): """ :param app_id: 微信公众号 app_id @@ -44,24 +44,19 @@ def __init__(self, app_id, secret, redirect_uri, scope='snsapi_base', state=''): self._http = requests.Session() def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - url = '{base}{endpoint}'.format( - base=self.API_BASE_URL, - endpoint=url_or_endpoint + if not url_or_endpoint.startswith(("http://", "https://")): + url = "{base}{endpoint}".format( + base=self.API_BASE_URL, endpoint=url_or_endpoint ) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - body = json.dumps(kwargs['data'], ensure_ascii=False) - body = body.encode('utf-8') - kwargs['data'] = body + if isinstance(kwargs.get("data", ""), dict): + body = json.dumps(kwargs["data"], ensure_ascii=False) + body = body.encode("utf-8") + kwargs["data"] = body - res = self._http.request( - method=method, - url=url, - **kwargs - ) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -70,29 +65,21 @@ def _request(self, method, url_or_endpoint, **kwargs): errmsg=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) - result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False) + result = json.loads(res.content.decode("utf-8", "ignore"), strict=False) - if 'errcode' in result and result['errcode'] != 0: - errcode = result['errcode'] - errmsg = result['errmsg'] + if "errcode" in result and result["errcode"] != 0: + errcode = result["errcode"] + errmsg = result["errmsg"] raise WeChatOAuthException( - errcode, - errmsg, - client=self, - request=res.request, - response=res + errcode, errmsg, client=self, request=res.request, response=res ) return result def _get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) @property def authorize_url(self): @@ -100,20 +87,20 @@ def authorize_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'oauth2/authorize?appid=', + "oauth2/authorize?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - self.scope + "&response_type=code&scope=", + self.scope, ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) @property def qrconnect_url(self): @@ -121,20 +108,20 @@ def qrconnect_url(self): :return: URL 地址 """ - redirect_uri = quote(self.redirect_uri, safe=b'') + redirect_uri = quote(self.redirect_uri, safe=b"") url_list = [ self.OAUTH_BASE_URL, - 'qrconnect?appid=', + "qrconnect?appid=", self.app_id, - '&redirect_uri=', + "&redirect_uri=", redirect_uri, - '&response_type=code&scope=', - 'snsapi_login' # scope + "&response_type=code&scope=", + "snsapi_login", # scope ] if self.state: - url_list.extend(['&state=', self.state]) - url_list.append('#wechat_redirect') - return ''.join(url_list) + url_list.extend(["&state=", self.state]) + url_list.append("#wechat_redirect") + return "".join(url_list) def fetch_access_token(self, code): """获取 access_token @@ -143,18 +130,18 @@ def fetch_access_token(self, code): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/access_token', + "sns/oauth2/access_token", params={ - 'appid': self.app_id, - 'secret': self.secret, - 'code': code, - 'grant_type': 'authorization_code' - } + "appid": self.app_id, + "secret": self.secret, + "code": code, + "grant_type": "authorization_code", + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res def refresh_access_token(self, refresh_token): @@ -164,20 +151,20 @@ def refresh_access_token(self, refresh_token): :return: JSON 数据包 """ res = self._get( - 'sns/oauth2/refresh_token', + "sns/oauth2/refresh_token", params={ - 'appid': self.app_id, - 'grant_type': 'refresh_token', - 'refresh_token': refresh_token - } + "appid": self.app_id, + "grant_type": "refresh_token", + "refresh_token": refresh_token, + }, ) - self.access_token = res['access_token'] - self.open_id = res['openid'] - self.refresh_token = res['refresh_token'] - self.expires_in = res['expires_in'] + self.access_token = res["access_token"] + self.open_id = res["openid"] + self.refresh_token = res["refresh_token"] + self.expires_in = res["expires_in"] return res - def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): + def get_user_info(self, openid=None, access_token=None, lang="zh_CN"): """获取用户信息 :param openid: 可选,微信 openid,默认获取当前授权用户信息 @@ -188,12 +175,8 @@ def get_user_info(self, openid=None, access_token=None, lang='zh_CN'): openid = openid or self.open_id access_token = access_token or self.access_token return self._get( - 'sns/userinfo', - params={ - 'access_token': access_token, - 'openid': openid, - 'lang': lang - } + "sns/userinfo", + params={"access_token": access_token, "openid": openid, "lang": lang}, ) def check_access_token(self, openid=None, access_token=None): @@ -206,12 +189,8 @@ def check_access_token(self, openid=None, access_token=None): openid = openid or self.open_id access_token = access_token or self.access_token res = self._get( - 'sns/auth', - params={ - 'access_token': access_token, - 'openid': openid - } + "sns/auth", params={"access_token": access_token, "openid": openid} ) - if res['errcode'] == 0: + if res["errcode"] == 0: return True return False diff --git a/chapter14/booking_system/exts/wechatpy/parser.py b/chapter14/booking_system/exts/wechatpy/parser.py index 11f3af7..0706fae 100644 --- a/chapter14/booking_system/exts/wechatpy/parser.py +++ b/chapter14/booking_system/exts/wechatpy/parser.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.parser - ~~~~~~~~~~~~~~~~ - This module provides functions for parsing WeChat messages +wechatpy.parser +~~~~~~~~~~~~~~~~ +This module provides functions for parsing WeChat messages - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import xmltodict @@ -24,28 +24,28 @@ def parse_message(xml): """ if not xml: return - message = xmltodict.parse(to_text(xml))['xml'] - message_type = message['MsgType'].lower() + message = xmltodict.parse(to_text(xml))["xml"] + message_type = message["MsgType"].lower() event_type = None - if message_type == 'event' or message_type.startswith('device_'): - if 'Event' in message: - event_type = message['Event'].lower() + if message_type == "event" or message_type.startswith("device_"): + if "Event" in message: + event_type = message["Event"].lower() # special event type for device_event - if event_type is None and message_type.startswith('device_'): + if event_type is None and message_type.startswith("device_"): event_type = message_type - elif message_type.startswith('device_'): - event_type = 'device_{event}'.format(event=event_type) + elif message_type.startswith("device_"): + event_type = "device_{event}".format(event=event_type) - if event_type == 'subscribe' and message.get('EventKey'): - event_key = message['EventKey'] - if event_key.startswith(('scanbarcode|', 'scanimage|')): - event_type = 'subscribe_scan_product' - message['Event'] = event_type - elif event_key.startswith('qrscene_'): + if event_type == "subscribe" and message.get("EventKey"): + event_key = message["EventKey"] + if event_key.startswith(("scanbarcode|", "scanimage|")): + event_type = "subscribe_scan_product" + message["Event"] = event_type + elif event_key.startswith("qrscene_"): # Scan to subscribe with scene id event - event_type = 'subscribe_scan' - message['Event'] = event_type - message['EventKey'] = event_key[len('qrscene_'):] + event_type = "subscribe_scan" + message["Event"] = event_type + message["EventKey"] = event_key[len("qrscene_") :] message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) diff --git a/chapter14/booking_system/exts/wechatpy/pay/__init__.py b/chapter14/booking_system/exts/wechatpy/pay/__init__.py index ff9dc96..e7ce60d 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/__init__.py +++ b/chapter14/booking_system/exts/wechatpy/pay/__init__.py @@ -11,7 +11,10 @@ from exts.wechatpy.utils import random_string from exts.wechatpy.exceptions import WeChatPayException, InvalidSignatureException from exts.wechatpy.pay.utils import ( - calculate_signature, calculate_signature_hmac, _check_signature, dict_to_xml + calculate_signature, + calculate_signature_hmac, + _check_signature, + dict_to_xml, ) from exts.wechatpy.pay.base import BaseWeChatPayAPI from exts.wechatpy.pay import api @@ -57,7 +60,7 @@ class WeChatPay(object): withhold = api.WeChatWithhold() """代扣接口""" - API_BASE_URL = 'https://api.mch.weixin.qq.com/' + API_BASE_URL = "https://api.mch.weixin.qq.com/" def __new__(cls, *args, **kwargs): self = super(WeChatPay, cls).__new__(cls) @@ -68,8 +71,18 @@ def __new__(cls, *args, **kwargs): setattr(self, name, _api) return self - def __init__(self, appid, api_key, mch_id, sub_mch_id=None, - mch_cert=None, mch_key=None, timeout=None, sandbox=False, sub_appid=None): + def __init__( + self, + appid, + api_key, + mch_id, + sub_mch_id=None, + mch_cert=None, + mch_key=None, + timeout=None, + sandbox=False, + sub_appid=None, + ): self.appid = appid self.sub_appid = sub_appid self.api_key = api_key @@ -84,56 +97,58 @@ def __init__(self, appid, api_key, mch_id, sub_mch_id=None, def _fetch_sandbox_api_key(self): nonce_str = random_string(32) - sign = calculate_signature({'mch_id': self.mch_id, 'nonce_str': nonce_str}, self.api_key) - payload = dict_to_xml({ - 'mch_id': self.mch_id, - 'nonce_str': nonce_str, - }, sign=sign) - headers = {'Content-Type': 'text/xml'} - api_url = '{base}sandboxnew/pay/getsignkey'.format(base=self.API_BASE_URL) + sign = calculate_signature( + {"mch_id": self.mch_id, "nonce_str": nonce_str}, self.api_key + ) + payload = dict_to_xml( + { + "mch_id": self.mch_id, + "nonce_str": nonce_str, + }, + sign=sign, + ) + headers = {"Content-Type": "text/xml"} + api_url = "{base}sandboxnew/pay/getsignkey".format(base=self.API_BASE_URL) response = self._http.post(api_url, data=payload, headers=headers) - return xmltodict.parse(response.text)['xml'].get('sandbox_signkey') + return xmltodict.parse(response.text)["xml"].get("sandbox_signkey") def _request(self, method, url_or_endpoint, **kwargs): - if not url_or_endpoint.startswith(('http://', 'https://')): - api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL) + if not url_or_endpoint.startswith(("http://", "https://")): + api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL) if self.sandbox: - api_base_url = '{url}sandboxnew/'.format(url=api_base_url) - url = '{base}{endpoint}'.format( - base=api_base_url, - endpoint=url_or_endpoint - ) + api_base_url = "{url}sandboxnew/".format(url=api_base_url) + url = "{base}{endpoint}".format(base=api_base_url, endpoint=url_or_endpoint) else: url = url_or_endpoint - if isinstance(kwargs.get('data', ''), dict): - data = kwargs['data'] - if 'mchid' not in data: + if isinstance(kwargs.get("data", ""), dict): + data = kwargs["data"] + if "mchid" not in data: # Fuck Tencent - data.setdefault('mch_id', self.mch_id) - data.setdefault('sub_mch_id', self.sub_mch_id) - data.setdefault('nonce_str', random_string(32)) + data.setdefault("mch_id", self.mch_id) + data.setdefault("sub_mch_id", self.sub_mch_id) + data.setdefault("nonce_str", random_string(32)) data = optionaldict(data) - if data.get('sign_type', 'MD5') == 'HMAC-SHA256': - sign = calculate_signature_hmac(data, self.sandbox_api_key if self.sandbox else self.api_key) + if data.get("sign_type", "MD5") == "HMAC-SHA256": + sign = calculate_signature_hmac( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) else: - sign = calculate_signature(data, self.sandbox_api_key if self.sandbox else self.api_key) + sign = calculate_signature( + data, self.sandbox_api_key if self.sandbox else self.api_key + ) body = dict_to_xml(data, sign) - body = body.encode('utf-8') - kwargs['data'] = body + body = body.encode("utf-8") + kwargs["data"] = body # 商户证书 if self.mch_cert and self.mch_key: - kwargs['cert'] = (self.mch_cert, self.mch_key) - - kwargs['timeout'] = kwargs.get('timeout', self.timeout) - logger.debug('Request to WeChat API: %s %s\n%s', method, url, kwargs) - res = self._http.request( - method=method, - url=url, - **kwargs - ) + kwargs["cert"] = (self.mch_cert, self.mch_key) + + kwargs["timeout"] = kwargs.get("timeout", self.timeout) + logger.debug("Request to WeChat API: %s %s\n%s", method, url, kwargs) + res = self._http.request(method=method, url=url, **kwargs) try: res.raise_for_status() except requests.RequestException as reqe: @@ -141,28 +156,28 @@ def _request(self, method, url_or_endpoint, **kwargs): return_code=None, client=self, request=reqe.request, - response=reqe.response + response=reqe.response, ) return self._handle_result(res) def _handle_result(self, res): - res.encoding = 'utf-8' + res.encoding = "utf-8" xml = res.text - logger.debug('Response from WeChat API \n %s', xml) + logger.debug("Response from WeChat API \n %s", xml) try: - data = xmltodict.parse(xml)['xml'] + data = xmltodict.parse(xml)["xml"] except (xmltodict.ParsingInterrupted, ExpatError): # 解析 XML 失败 - logger.debug('WeChat payment result xml parsing error', exc_info=True) + logger.debug("WeChat payment result xml parsing error", exc_info=True) return xml - return_code = data['return_code'] - return_msg = data.get('return_msg') - result_code = data.get('result_code') - errcode = data.get('err_code') - errmsg = data.get('err_code_des') - if return_code != 'SUCCESS' or result_code != 'SUCCESS': + return_code = data["return_code"] + return_msg = data.get("return_msg") + result_code = data.get("result_code") + errcode = data.get("err_code") + errmsg = data.get("err_code_des") + if return_code != "SUCCESS" or result_code != "SUCCESS": # 返回状态码不为成功 raise WeChatPayException( return_code, @@ -172,26 +187,20 @@ def _handle_result(self, res): errmsg, client=self, request=res.request, - response=res + response=res, ) return data def get(self, url, **kwargs): - return self._request( - method='get', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="get", url_or_endpoint=url, **kwargs) def post(self, url, **kwargs): - return self._request( - method='post', - url_or_endpoint=url, - **kwargs - ) + return self._request(method="post", url_or_endpoint=url, **kwargs) def check_signature(self, params): - return _check_signature(params, self.api_key if not self.sandbox else self.sandbox_api_key) + return _check_signature( + params, self.api_key if not self.sandbox else self.sandbox_api_key + ) def parse_payment_result(self, xml): """解析微信支付结果通知""" @@ -200,22 +209,30 @@ def parse_payment_result(self, xml): except (xmltodict.ParsingInterrupted, ExpatError): raise InvalidSignatureException() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise InvalidSignatureException() - data = data['xml'] - sign = data.pop('sign', None) - if '#text' in data.keys(): + data = data["xml"] + sign = data.pop("sign", None) + if "#text" in data.keys(): pass - del data['#text'] - real_sign = calculate_signature(data, self.api_key if not self.sandbox else self.sandbox_api_key) + del data["#text"] + real_sign = calculate_signature( + data, self.api_key if not self.sandbox else self.sandbox_api_key + ) if sign != real_sign: raise InvalidSignatureException() - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) - data['sign'] = sign + data["sign"] = sign return data @property diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/coupon.py b/chapter14/booking_system/exts/wechatpy/pay/api/coupon.py index 53cd0bc..fe97cfd 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/coupon.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/coupon.py @@ -8,8 +8,9 @@ class WeChatCoupon(BaseWeChatPayAPI): - def send(self, user_id, stock_id, op_user_id=None, device_info=None, - out_trade_no=None): + def send( + self, user_id, stock_id, op_user_id=None, device_info=None, out_trade_no=None + ): """ 发放代金券 @@ -22,23 +23,21 @@ def send(self, user_id, stock_id, op_user_id=None, device_info=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'openid': user_id, - 'openid_count': 1, - 'partner_trade_no': out_trade_no, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "openid": user_id, + "openid_count": 1, + "partner_trade_no": out_trade_no, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/send_coupon', data=data) + return self._post("mmpaymkttransfers/send_coupon", data=data) def query_stock(self, stock_id, op_user_id=None, device_info=None): """ @@ -50,17 +49,16 @@ def query_stock(self, stock_id, op_user_id=None, device_info=None): :return: 返回的结果信息 """ data = { - 'appid': self.appid, - 'coupon_stock_id': stock_id, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "appid": self.appid, + "coupon_stock_id": stock_id, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('mmpaymkttransfers/query_coupon_stock', data=data) + return self._post("mmpaymkttransfers/query_coupon_stock", data=data) - def query_coupon(self, coupon_id, user_id, - op_user_id=None, device_info=None): + def query_coupon(self, coupon_id, user_id, op_user_id=None, device_info=None): """ 查询代金券信息 @@ -71,12 +69,12 @@ def query_coupon(self, coupon_id, user_id, :return: 返回的结果信息 """ data = { - 'coupon_id': coupon_id, - 'openid': user_id, - 'appid': self.appid, - 'op_user_id': op_user_id, - 'device_info': device_info, - 'version': '1.0', - 'type': 'XML', + "coupon_id": coupon_id, + "openid": user_id, + "appid": self.appid, + "op_user_id": op_user_id, + "device_info": device_info, + "version": "1.0", + "type": "XML", } - return self._post('promotion/query_coupon', data=data) + return self._post("promotion/query_coupon", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/jsapi.py b/chapter14/booking_system/exts/wechatpy/pay/api/jsapi.py index 79ed209..a818fe8 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/jsapi.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/jsapi.py @@ -8,6 +8,7 @@ logger = logging.getLogger(__name__) + class WeChatJSAPI(BaseWeChatPayAPI): def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): @@ -20,15 +21,19 @@ def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } return calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=False): @@ -44,18 +49,22 @@ def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=Fals :return: 参数 """ data = { - 'appId': self.sub_appid or self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'signType': 'MD5', - 'package': 'prepay_id={0}'.format(prepay_id), + "appId": self.sub_appid or self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "signType": "MD5", + "package": "prepay_id={0}".format(prepay_id), } sign = calculate_signature( data, - self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key + ( + self._client.api_key + if not self._client.sandbox + else self._client.sandbox_api_key + ), ) - logger.debug('JSAPI payment parameters: data = %s, sign = %s', data, sign) - data['paySign'] = sign + logger.debug("JSAPI payment parameters: data = %s, sign = %s", data, sign) + data["paySign"] = sign if jssdk: - data['timestamp'] = data.pop('timeStamp') + data["timestamp"] = data.pop("timeStamp") return data diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/micropay.py b/chapter14/booking_system/exts/wechatpy/pay/api/micropay.py index 30e8714..439cf19 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/micropay.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/micropay.py @@ -8,8 +8,20 @@ class WeChatMicroPay(BaseWeChatPayAPI): - def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', goods_tag=None, device_info=None, limit_pay=None): + def create( + self, + body, + total_fee, + auth_code, + client_ip=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + device_info=None, + limit_pay=None, + ): """ 刷卡支付接口 :param device_info: 可选,终端设备号(商户自定义,如门店编号) @@ -27,26 +39,24 @@ def create(self, body, total_fee, auth_code, client_ip=None, out_trade_no=None, """ now = datetime.now() if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'appid': self.appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'total_fee': total_fee, - 'fee_type': fee_type, - 'spbill_create_ip': client_ip or get_external_ip(), - 'goods_tag': goods_tag, - 'limit_pay': limit_pay, - 'auth_code': auth_code, + "appid": self.appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "total_fee": total_fee, + "fee_type": fee_type, + "spbill_create_ip": client_ip or get_external_ip(), + "goods_tag": goods_tag, + "limit_pay": limit_pay, + "auth_code": auth_code, } - return self._post('pay/micropay', data=data) + return self._post("pay/micropay", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -57,8 +67,8 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/order.py b/chapter14/booking_system/exts/wechatpy/pay/api/order.py index ebc3549..68005fd 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/order.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/order.py @@ -13,10 +13,27 @@ class WeChatOrder(BaseWeChatPayAPI): - def create(self, trade_type, body, total_fee, notify_url, client_ip=None, - user_id=None, out_trade_no=None, detail=None, attach=None, - fee_type='CNY', time_start=None, time_expire=None, goods_tag=None, - product_id=None, device_info=None, limit_pay=None, scene_info=None, sub_user_id=None): + def create( + self, + trade_type, + body, + total_fee, + notify_url, + client_ip=None, + user_id=None, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + time_start=None, + time_expire=None, + goods_tag=None, + product_id=None, + device_info=None, + limit_pay=None, + scene_info=None, + sub_user_id=None, + ): """ 统一下单接口 @@ -41,43 +58,41 @@ def create(self, trade_type, body, total_fee, notify_url, client_ip=None, :type scene_info: dict :return: 返回的结果数据 """ - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) hours_later = now + timedelta(hours=2) if time_start is None: time_start = now if time_expire is None: time_expire = hours_later if not out_trade_no: - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) if scene_info is not None: scene_info = json.dumps(scene_info, ensure_ascii=False) data = { - 'appid': self.appid, - 'sub_appid': self.sub_appid, - 'device_info': device_info, - 'body': body, - 'detail': detail, - 'attach': attach, - 'out_trade_no': out_trade_no, - 'fee_type': fee_type, - 'total_fee': total_fee, - 'spbill_create_ip': client_ip or get_external_ip(), - 'time_start': time_start.strftime('%Y%m%d%H%M%S'), - 'time_expire': time_expire.strftime('%Y%m%d%H%M%S'), - 'goods_tag': goods_tag, - 'notify_url': notify_url, - 'trade_type': trade_type, - 'limit_pay': limit_pay, - 'product_id': product_id, - 'openid': user_id, - 'sub_openid': sub_user_id, - 'scene_info': scene_info, + "appid": self.appid, + "sub_appid": self.sub_appid, + "device_info": device_info, + "body": body, + "detail": detail, + "attach": attach, + "out_trade_no": out_trade_no, + "fee_type": fee_type, + "total_fee": total_fee, + "spbill_create_ip": client_ip or get_external_ip(), + "time_start": time_start.strftime("%Y%m%d%H%M%S"), + "time_expire": time_expire.strftime("%Y%m%d%H%M%S"), + "goods_tag": goods_tag, + "notify_url": notify_url, + "trade_type": trade_type, + "limit_pay": limit_pay, + "product_id": product_id, + "openid": user_id, + "sub_openid": sub_user_id, + "scene_info": scene_info, } - return self._post('pay/unifiedorder', data=data) + return self._post("pay/unifiedorder", data=data) def query(self, transaction_id=None, out_trade_no=None): """ @@ -88,11 +103,11 @@ def query(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('pay/orderquery', data=data) + return self._post("pay/orderquery", data=data) def close(self, out_trade_no): """ @@ -102,10 +117,10 @@ def close(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "out_trade_no": out_trade_no, } - return self._post('pay/closeorder', data=data) + return self._post("pay/closeorder", data=data) def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): """ @@ -117,15 +132,15 @@ def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appid': self.appid, - 'partnerid': self.mch_id, - 'prepayid': prepay_id, - 'package': 'Sign=WXPay', - 'timestamp': timestamp or to_text(int(time.time())), - 'noncestr': nonce_str or random_string(32) + "appid": self.appid, + "partnerid": self.mch_id, + "prepayid": prepay_id, + "package": "Sign=WXPay", + "timestamp": timestamp or to_text(int(time.time())), + "noncestr": nonce_str or random_string(32), } sign = calculate_signature(data, self._client.api_key) - data['sign'] = sign + data["sign"] = sign return data def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): @@ -138,14 +153,14 @@ def get_appapi_params_xiugai(self, prepay_id, timestamp=None, nonce_str=None): :return: 签名 """ data = { - 'appId': self.appid, - 'timeStamp': timestamp or to_text(int(time.time())), - 'nonceStr': nonce_str or random_string(32), - 'package': 'prepay_id='+prepay_id, - 'signType': 'MD5' + "appId": self.appid, + "timeStamp": timestamp or to_text(int(time.time())), + "nonceStr": nonce_str or random_string(32), + "package": "prepay_id=" + prepay_id, + "signType": "MD5", } sign = calculate_signature(data, self._client.api_key) - data['paySign'] = sign + data["paySign"] = sign return data def reverse(self, transaction_id=None, out_trade_no=None): @@ -159,8 +174,8 @@ def reverse(self, transaction_id=None, out_trade_no=None): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, + "appid": self.appid, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, } - return self._post('secapi/pay/reverse', data=data) + return self._post("secapi/pay/reverse", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/redpack.py b/chapter14/booking_system/exts/wechatpy/pay/api/redpack.py index c888b97..5a779f7 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/redpack.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/redpack.py @@ -9,9 +9,20 @@ class WeChatRedpack(BaseWeChatPayAPI): - def send(self, user_id, total_amount, send_name, act_name, - wishing, remark, total_num=1, client_ip=None, - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num=1, + client_ip=None, + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送现金红包 @@ -30,31 +41,41 @@ def send(self, user_id, total_amount, send_name, act_name, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'client_ip': client_ip or get_external_ip(), - 'total_num': total_num, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "client_ip": client_ip or get_external_ip(), + "total_num": total_num, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendredpack', data=data) + return self._post("mmpaymkttransfers/sendredpack", data=data) - def send_group(self, user_id, total_amount, send_name, act_name, wishing, - remark, total_num, client_ip=None, amt_type="ALL_RAND", - out_trade_no=None, scene_id=None, consume_mch_id=None): + def send_group( + self, + user_id, + total_amount, + send_name, + act_name, + wishing, + remark, + total_num, + client_ip=None, + amt_type="ALL_RAND", + out_trade_no=None, + scene_id=None, + consume_mch_id=None, + ): """ 发送裂变红包 @@ -75,30 +96,30 @@ def send_group(self, user_id, total_amount, send_name, act_name, wishing, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( + out_trade_no = "{0}{1}{2}".format( self._client.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now.strftime("%Y%m%d%H%M%S"), + random.randint(1000, 10000), ) data = { - 'wxappid': self.appid, - 're_openid': user_id, - 'total_amount': total_amount, - 'send_name': send_name, - 'act_name': act_name, - 'wishing': wishing, - 'remark': remark, - 'total_num': total_num, - 'client_ip': client_ip or get_external_ip(), - 'amt_type': amt_type, - 'mch_billno': out_trade_no, - 'scene_id': scene_id, - 'risk_info': None, - 'consume_mch_id': consume_mch_id + "wxappid": self.appid, + "re_openid": user_id, + "total_amount": total_amount, + "send_name": send_name, + "act_name": act_name, + "wishing": wishing, + "remark": remark, + "total_num": total_num, + "client_ip": client_ip or get_external_ip(), + "amt_type": amt_type, + "mch_billno": out_trade_no, + "scene_id": scene_id, + "risk_info": None, + "consume_mch_id": consume_mch_id, } - return self._post('mmpaymkttransfers/sendgroupredpack', data=data) + return self._post("mmpaymkttransfers/sendgroupredpack", data=data) - def query(self, out_trade_no, bill_type='MCHT'): + def query(self, out_trade_no, bill_type="MCHT"): """ 查询红包发放记录 @@ -107,8 +128,8 @@ def query(self, out_trade_no, bill_type='MCHT'): :return: 返回的红包发放记录信息 """ data = { - 'mch_billno': out_trade_no, - 'bill_type': bill_type, - 'appid': self.appid, + "mch_billno": out_trade_no, + "bill_type": bill_type, + "appid": self.appid, } - return self._post('mmpaymkttransfers/gethbinfo', data=data) + return self._post("mmpaymkttransfers/gethbinfo", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/refund.py b/chapter14/booking_system/exts/wechatpy/pay/api/refund.py index 8d9a5d1..9dec65b 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/refund.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/refund.py @@ -6,10 +6,19 @@ class WeChatRefund(BaseWeChatPayAPI): - def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, - out_trade_no=None, fee_type='CNY', op_user_id=None, - device_info=None, refund_account='REFUND_SOURCE_UNSETTLED_FUNDS', - notify_url=None): + def apply( + self, + total_fee, + refund_fee, + out_refund_no, + transaction_id=None, + out_trade_no=None, + fee_type="CNY", + op_user_id=None, + device_info=None, + refund_account="REFUND_SOURCE_UNSETTLED_FUNDS", + notify_url=None, + ): """ 申请退款 @@ -26,22 +35,28 @@ def apply(self, total_fee, refund_fee, out_refund_no, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'total_fee': total_fee, - 'refund_fee': refund_fee, - 'refund_fee_type': fee_type, - 'op_user_id': op_user_id if op_user_id else self.mch_id, - 'refund_account': refund_account, - 'notify_url': notify_url, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "total_fee": total_fee, + "refund_fee": refund_fee, + "refund_fee_type": fee_type, + "op_user_id": op_user_id if op_user_id else self.mch_id, + "refund_account": refund_account, + "notify_url": notify_url, } - return self._post('secapi/pay/refund', data=data) + return self._post("secapi/pay/refund", data=data) - def query(self, refund_id=None, out_refund_no=None, transaction_id=None, - out_trade_no=None, device_info=None): + def query( + self, + refund_id=None, + out_refund_no=None, + transaction_id=None, + out_trade_no=None, + device_info=None, + ): """ 查询退款 @@ -53,11 +68,11 @@ def query(self, refund_id=None, out_refund_no=None, transaction_id=None, :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'device_info': device_info, - 'transaction_id': transaction_id, - 'out_trade_no': out_trade_no, - 'out_refund_no': out_refund_no, - 'refund_id': refund_id, + "appid": self.appid, + "device_info": device_info, + "transaction_id": transaction_id, + "out_trade_no": out_trade_no, + "out_refund_no": out_refund_no, + "refund_id": refund_id, } - return self._post('pay/refundquery', data=data) + return self._post("pay/refundquery", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/tools.py b/chapter14/booking_system/exts/wechatpy/pay/api/tools.py index 75ffc33..1c76797 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/tools.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/tools.py @@ -15,12 +15,12 @@ def short_url(self, long_url): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'long_url': long_url, + "appid": self.appid, + "long_url": long_url, } - return self._post('tools/shorturl', data=data) + return self._post("tools/shorturl", data=data) - def download_bill(self, bill_date, bill_type='ALL', device_info=None): + def download_bill(self, bill_date, bill_type="ALL", device_info=None): """ 下载对账单 @@ -33,18 +33,17 @@ def download_bill(self, bill_date, bill_type='ALL', device_info=None): :return: 返回的结果数据 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'bill_type': bill_type, - 'device_info': device_info, + "appid": self.appid, + "bill_date": bill_date, + "bill_type": bill_type, + "device_info": device_info, } - return self._post('pay/downloadbill', data=data) + return self._post("pay/downloadbill", data=data) - def download_fundflow(self, bill_date, account_type='Basic', - tar_type=None): + def download_fundflow(self, bill_date, account_type="Basic", tar_type=None): """ 下载资金账单 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18&index=7 @@ -58,17 +57,17 @@ def download_fundflow(self, bill_date, account_type='Basic', 不传则默认为数据流形式。 """ if isinstance(bill_date, (datetime, date)): - bill_date = bill_date.strftime('%Y%m%d') + bill_date = bill_date.strftime("%Y%m%d") data = { - 'appid': self.appid, - 'bill_date': bill_date, - 'account_type': account_type, - 'sign_type': 'HMAC-SHA256' + "appid": self.appid, + "bill_date": bill_date, + "account_type": account_type, + "sign_type": "HMAC-SHA256", } if tar_type is not None: - data['tar_type'] = tar_type - return self._post('pay/downloadfundflow', data=data) + data["tar_type"] = tar_type + return self._post("pay/downloadfundflow", data=data) def auto_code_to_openid(self, auth_code): """ @@ -78,7 +77,7 @@ def auto_code_to_openid(self, auth_code): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'auth_code': auth_code, + "appid": self.appid, + "auth_code": auth_code, } - return self._post('tools/authcodetoopenid', data=data) + return self._post("tools/authcodetoopenid", data=data) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/transfer.py b/chapter14/booking_system/exts/wechatpy/pay/api/transfer.py index 0b49951..13701fe 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/transfer.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/transfer.py @@ -9,9 +9,17 @@ class WeChatTransfer(BaseWeChatPayAPI): - def transfer(self, user_id, amount, desc, client_ip=None, - check_name='OPTION_CHECK', real_name=None, - out_trade_no=None, device_info=None): + def transfer( + self, + user_id, + amount, + desc, + client_ip=None, + check_name="OPTION_CHECK", + real_name=None, + out_trade_no=None, + device_info=None, + ): """ 企业付款接口 @@ -32,24 +40,22 @@ def transfer(self, user_id, amount, desc, client_ip=None, """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_appid': self.appid, - 'mchid': self.mch_id, - 'device_info': device_info, - 'partner_trade_no': out_trade_no, - 'openid': user_id, - 'check_name': check_name, - 're_user_name': real_name, - 'amount': amount, - 'desc': desc, - 'spbill_create_ip': client_ip or get_external_ip(), + "mch_appid": self.appid, + "mchid": self.mch_id, + "device_info": device_info, + "partner_trade_no": out_trade_no, + "openid": user_id, + "check_name": check_name, + "re_user_name": real_name, + "amount": amount, + "desc": desc, + "spbill_create_ip": client_ip or get_external_ip(), } - return self._post('mmpaymkttransfers/promotion/transfers', data=data) + return self._post("mmpaymkttransfers/promotion/transfers", data=data) def query(self, out_trade_no): """ @@ -59,12 +65,14 @@ def query(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'appid': self.appid, - 'partner_trade_no': out_trade_no, + "appid": self.appid, + "partner_trade_no": out_trade_no, } - return self._post('mmpaymkttransfers/gettransferinfo', data=data) + return self._post("mmpaymkttransfers/gettransferinfo", data=data) - def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None): + def transfer_bankcard( + self, true_name, bank_card_no, bank_code, amount, desc=None, out_trade_no=None + ): """ 企业付款到银行卡接口 @@ -78,21 +86,19 @@ def transfer_bankcard(self, true_name, bank_card_no, bank_code, amount, desc=Non """ if not out_trade_no: now = datetime.now() - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, - 'amount': amount, - 'desc': desc, - 'enc_bank_no': self._rsa_encrypt(bank_card_no), - 'enc_true_name': self._rsa_encrypt(true_name), - 'bank_code': bank_code, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, + "amount": amount, + "desc": desc, + "enc_bank_no": self._rsa_encrypt(bank_card_no), + "enc_true_name": self._rsa_encrypt(true_name), + "bank_code": bank_code, } - return self._post('mmpaysptrans/pay_bank', data=data) + return self._post("mmpaysptrans/pay_bank", data=data) def query_bankcard(self, out_trade_no): """ @@ -102,19 +108,21 @@ def query_bankcard(self, out_trade_no): :return: 返回的结果数据 """ data = { - 'mch_id': self.mch_id, - 'partner_trade_no': out_trade_no, + "mch_id": self.mch_id, + "partner_trade_no": out_trade_no, } - return self._post('mmpaysptrans/query_bank', data=data) + return self._post("mmpaysptrans/query_bank", data=data) def get_rsa_public_key(self): data = { - 'mch_id': self.mch_id, - 'sign_type': 'MD5', + "mch_id": self.mch_id, + "sign_type": "MD5", } - return self._post('https://fraud.mch.weixin.qq.com/risk/getpublickey', data=data) + return self._post( + "https://fraud.mch.weixin.qq.com/risk/getpublickey", data=data + ) def _rsa_encrypt(self, data): - if not getattr(self, '_rsa_public_key', None): - self._rsa_public_key = self.get_rsa_public_key()['pub_key'] + if not getattr(self, "_rsa_public_key", None): + self._rsa_public_key = self.get_rsa_public_key()["pub_key"] return rsa_encrypt(data, self._rsa_public_key) diff --git a/chapter14/booking_system/exts/wechatpy/pay/api/withhold.py b/chapter14/booking_system/exts/wechatpy/pay/api/withhold.py index 3e9f2e7..e629d80 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/api/withhold.py +++ b/chapter14/booking_system/exts/wechatpy/pay/api/withhold.py @@ -13,9 +13,23 @@ class WeChatWithhold(BaseWeChatPayAPI): - def apply_signing(self, plan_id, contract_code, contract_display_account, notify_url, - version="1.0", clientip=None, deviceid=None, mobile=None, email=None, qq=None, - request_serial=None, openid=None, creid=None, outerid=None): + def apply_signing( + self, + plan_id, + contract_code, + contract_display_account, + notify_url, + version="1.0", + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + request_serial=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请签约 api @@ -65,10 +79,17 @@ def apply_signing(self, plan_id, contract_code, contract_display_account, notify data["sign"] = sign return { "base_url": "{}papay/entrustweb".format(self._client.API_BASE_URL), - "data": data + "data": data, } - def query_signing(self, contract_id=None, plan_id=None, contract_code=None, openid=None, version="1.0"): + def query_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + openid=None, + version="1.0", + ): """ 查询签约关系 api @@ -79,8 +100,14 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open :param version: 版本号 固定值1.0 :return: 返回的结果信息 """ - if not contract_id and not (plan_id and contract_code) and not (plan_id and openid): - raise ValueError("contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice.") + if ( + not contract_id + and not (plan_id and contract_code) + and not (plan_id and openid) + ): + raise ValueError( + "contract_id and (plan_id, contract_code) and (plan_id, openid) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, @@ -91,11 +118,28 @@ def query_signing(self, contract_id=None, plan_id=None, contract_code=None, open "version": version, "nonce_str": None, } - return self._post('papay/querycontract', data=data) - - def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=None, - detail=None, attach=None, fee_type='CNY', goods_tag=None, clientip=None, deviceid=None, - mobile=None, email=None, qq=None, openid=None, creid=None, outerid=None): + return self._post("papay/querycontract", data=data) + + def apply_deduct( + self, + body, + total_fee, + contract_id, + notify_url, + out_trade_no=None, + detail=None, + attach=None, + fee_type="CNY", + goods_tag=None, + clientip=None, + deviceid=None, + mobile=None, + email=None, + qq=None, + openid=None, + creid=None, + outerid=None, + ): """ 申请扣款 api @@ -118,15 +162,13 @@ def apply_deduct(self, body, total_fee, contract_id, notify_url, out_trade_no=No :param outerid: 可选 商户侧用户标识 用户在商户侧的标识 :return: 返回的结果信息 """ - trade_type = 'PAP' # 交易类型 交易类型PAP-微信委托代扣支付 + trade_type = "PAP" # 交易类型 交易类型PAP-微信委托代扣支付 timestamp = int(time.time()) # 10位时间戳 spbill_create_ip = get_external_ip() # 终端IP 调用微信支付API的机器IP if not out_trade_no: - now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai')) - out_trade_no = '{0}{1}{2}'.format( - self.mch_id, - now.strftime('%Y%m%d%H%M%S'), - random.randint(1000, 10000) + now = datetime.fromtimestamp(time.time(), tz=timezone("Asia/Shanghai")) + out_trade_no = "{0}{1}{2}".format( + self.mch_id, now.strftime("%Y%m%d%H%M%S"), random.randint(1000, 10000) ) data = { @@ -173,8 +215,14 @@ def query_order(self, transaction_id=None, out_trade_no=None): } return self._post("pay/paporderquery", data=data) - def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=None, - contract_termination_remark=None, version="1.0"): + def apply_cancel_signing( + self, + contract_id=None, + plan_id=None, + contract_code=None, + contract_termination_remark=None, + version="1.0", + ): """ 申请解约 @@ -188,7 +236,9 @@ def apply_cancel_signing(self, contract_id=None, plan_id=None, contract_code=Non :return: """ if not (contract_id or (plan_id and contract_code)): - raise ValueError("contract_id and (plan_id, contract_code) must be a choice.") + raise ValueError( + "contract_id and (plan_id, contract_code) must be a choice." + ) data = { "appid": self.appid, "mch_id": self.mch_id, diff --git a/chapter14/booking_system/exts/wechatpy/pay/base.py b/chapter14/booking_system/exts/wechatpy/pay/base.py index 6184fa9..25c7830 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/base.py +++ b/chapter14/booking_system/exts/wechatpy/pay/base.py @@ -3,18 +3,19 @@ class BaseWeChatPayAPI(object): - """ WeChat Pay API base class """ + """WeChat Pay API base class""" + def __init__(self, client=None): self._client = client def _get(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.get(url, **kwargs) def _post(self, url, **kwargs): - if getattr(self, 'API_BASE_URL', None): - kwargs['api_base_url'] = self.API_BASE_URL + if getattr(self, "API_BASE_URL", None): + kwargs["api_base_url"] = self.API_BASE_URL return self._client.post(url, **kwargs) @property diff --git a/chapter14/booking_system/exts/wechatpy/pay/utils.py b/chapter14/booking_system/exts/wechatpy/pay/utils.py index 4c1d05d..194be89 100644 --- a/chapter14/booking_system/exts/wechatpy/pay/utils.py +++ b/chapter14/booking_system/exts/wechatpy/pay/utils.py @@ -13,19 +13,22 @@ logger = logging.getLogger(__name__) + def format_url(params, api_key=None): # if '#text' in params: # print(params['#text']) # del params['#text'] # print( params['#text']) - data = [to_binary('{0}={1}'.format(k, params[k])) for k in sorted(params) if params[k]] + data = [ + to_binary("{0}={1}".format(k, params[k])) for k in sorted(params) if params[k] + ] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # 微信支付回调的验证签名的修改!!!!zyxyuanxiao del data[0] # del data[0] if api_key: - data.append(to_binary('key={0}'.format(api_key))) + data.append(to_binary("key={0}".format(api_key))) return b"&".join(data) @@ -37,42 +40,45 @@ def calculate_signature(params, api_key): def calculate_signature_hmac(params, api_key): url = format_url(params, api_key) - sign = to_text(hmac.new(api_key.encode(), msg=url, - digestmod=hashlib.sha256).hexdigest().upper()) + sign = to_text( + hmac.new(api_key.encode(), msg=url, digestmod=hashlib.sha256) + .hexdigest() + .upper() + ) return sign def _check_signature(params, api_key): _params = copy.deepcopy(params) - sign = _params.pop('sign', '') + sign = _params.pop("sign", "") return sign == calculate_signature(_params, api_key) def dict_to_xml(d, sign): - xml = ['\n'] + xml = ["\n"] for k in sorted(d): # use sorted to avoid test error on Py3k v = d[k] - if isinstance(v, six.integer_types) or (isinstance(v, six.string_types) and v.isdigit()): - xml.append('<{0}>{1}\n'.format(to_text(k), to_text(v))) + if isinstance(v, six.integer_types) or ( + isinstance(v, six.string_types) and v.isdigit() + ): + xml.append("<{0}>{1}\n".format(to_text(k), to_text(v))) else: - xml.append( - '<{0}>\n'.format(to_text(k), to_text(v)) - ) - xml.append('\n'.format(to_text(sign))) - return ''.join(xml) + xml.append("<{0}>\n".format(to_text(k), to_text(v))) + xml.append("\n".format(to_text(sign))) + return "".join(xml) def get_external_ip(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: - wechat_ip = socket.gethostbyname('api.mch.weixin.qq.com') + wechat_ip = socket.gethostbyname("api.mch.weixin.qq.com") sock.connect((wechat_ip, 80)) addr, port = sock.getsockname() sock.close() return addr except socket.error: - return '127.0.0.1' + return "127.0.0.1" def rsa_encrypt(data, pem, b64_encode=True): @@ -87,6 +93,7 @@ def rsa_encrypt(data, pem, b64_encode=True): from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding + encoded_data = to_binary(data) pem = to_binary(pem) public_key = serialization.load_pem_public_key(pem, backend=default_backend()) @@ -96,10 +103,10 @@ def rsa_encrypt(data, pem, b64_encode=True): mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) if b64_encode: - encrypted_data = base64.b64encode(encrypted_data).decode('utf-8') + encrypted_data = base64.b64encode(encrypted_data).decode("utf-8") return encrypted_data @@ -118,13 +125,15 @@ def rsa_decrypt(encrypted_data, pem, password=None): encrypted_data = to_binary(encrypted_data) pem = to_binary(pem) - private_key = serialization.load_pem_private_key(pem, password, backend=default_backend()) + private_key = serialization.load_pem_private_key( + pem, password, backend=default_backend() + ) data = private_key.decrypt( encrypted_data, padding=padding.OAEP( mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None, - ) + ), ) return data diff --git a/chapter14/booking_system/exts/wechatpy/replies.py b/chapter14/booking_system/exts/wechatpy/replies.py index 9a48d71..3365edc 100644 --- a/chapter14/booking_system/exts/wechatpy/replies.py +++ b/chapter14/booking_system/exts/wechatpy/replies.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ - wechatpy.replies - ~~~~~~~~~~~~~~~~~~ - This module defines all kinds of replies you can send to WeChat +wechatpy.replies +~~~~~~~~~~~~~~~~~~ +This module defines all kinds of replies you can send to WeChat - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import time @@ -34,28 +34,30 @@ def register_reply(reply_type): def register(cls): REPLY_TYPES[reply_type] = cls return cls + return register class BaseReply(six.with_metaclass(MessageMetaClass)): """Base class for all replies""" - source = StringField('FromUserName') - target = StringField('ToUserName') - time = IntegerField('CreateTime', time.time()) - type = 'unknown' + + source = StringField("FromUserName") + target = StringField("ToUserName") + time = IntegerField("CreateTime", time.time()) + type = "unknown" def __init__(self, **kwargs): self._data = {} - message = kwargs.pop('message', None) + message = kwargs.pop("message", None) if message and isinstance(message, BaseMessage): - if 'source' not in kwargs: - kwargs['source'] = message.target - if 'target' not in kwargs: - kwargs['target'] = message.source - if hasattr(message, 'agent') and 'agent' not in kwargs: - kwargs['agent'] = message.agent - if 'time' not in kwargs: - kwargs['time'] = time.time() + if "source" not in kwargs: + kwargs["source"] = message.target + if "target" not in kwargs: + kwargs["target"] = message.source + if hasattr(message, "agent") and "agent" not in kwargs: + kwargs["agent"] = message.agent + if "time" not in kwargs: + kwargs["time"] = time.time() for name, value in kwargs.items(): field = self._fields.get(name) if field: @@ -65,9 +67,9 @@ def __init__(self, **kwargs): def render(self): """Render reply from Python object to XML string""" - tpl = '\n{data}\n' + tpl = "\n{data}\n" nodes = [] - msg_type = ''.format( + msg_type = "".format( msg_type=self.type ) nodes.append(msg_type) @@ -75,7 +77,7 @@ def render(self): value = getattr(self, name, field.default) node_xml = field.to_xml(value) nodes.append(node_xml) - data = '\n'.join(nodes) + data = "\n".join(nodes) return tpl.format(data=data) def __str__(self): @@ -85,39 +87,42 @@ def __str__(self): return to_text(self.render()) -@register_reply('empty') +@register_reply("empty") class EmptyReply(BaseReply): """ 回复空串 微信服务器不会对此作任何处理,并且不会发起重试 """ + def __init__(self): pass def render(self): - return '' + return "" -@register_reply('text') +@register_reply("text") class TextReply(BaseReply): """ 文本回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'text' - content = StringField('Content') + type = "text" + content = StringField("Content") -@register_reply('image') + +@register_reply("image") class ImageReply(BaseReply): """ 图片回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'image' - image = ImageField('Image') + + type = "image" + image = ImageField("Image") @property def media_id(self): @@ -128,15 +133,16 @@ def media_id(self, value): self.image = value -@register_reply('voice') +@register_reply("voice") class VoiceReply(BaseReply): """ 语音回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'voice' - voice = VoiceField('Voice') + + type = "voice" + voice = VoiceField("Voice") @property def media_id(self): @@ -147,169 +153,174 @@ def media_id(self, value): self.voice = value -@register_reply('video') +@register_reply("video") class VideoReply(BaseReply): """ 视频回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'video' - video = VideoField('Video', {}) + + type = "video" + video = VideoField("Video", {}) @property def media_id(self): - return self.video.get('media_id') + return self.video.get("media_id") @media_id.setter def media_id(self, value): video = self.video - video['media_id'] = value + video["media_id"] = value self.video = video @property def title(self): - return self.video.get('title') + return self.video.get("title") @title.setter def title(self, value): video = self.video - video['title'] = value + video["title"] = value self.video = video @property def description(self): - return self.video.get('description') + return self.video.get("description") @description.setter def description(self, value): video = self.video - video['description'] = value + video["description"] = value self.video = video -@register_reply('music') +@register_reply("music") class MusicReply(BaseReply): """ 音乐回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'music' - music = MusicField('Music', {}) + + type = "music" + music = MusicField("Music", {}) @property def thumb_media_id(self): - return self.music.get('thumb_media_id') + return self.music.get("thumb_media_id") @thumb_media_id.setter def thumb_media_id(self, value): music = self.music - music['thumb_media_id'] = value + music["thumb_media_id"] = value self.music = music @property def title(self): - return self.music.get('title') + return self.music.get("title") @title.setter def title(self, value): music = self.music - music['title'] = value + music["title"] = value self.music = music @property def description(self): - return self.music.get('description') + return self.music.get("description") @description.setter def description(self, value): music = self.music - music['description'] = value + music["description"] = value self.music = music @property def music_url(self): - return self.music.get('music_url') + return self.music.get("music_url") @music_url.setter def music_url(self, value): music = self.music - music['music_url'] = value + music["music_url"] = value self.music = music @property def hq_music_url(self): - return self.music.get('hq_music_url') + return self.music.get("hq_music_url") @hq_music_url.setter def hq_music_url(self, value): music = self.music - music['hq_music_url'] = value + music["hq_music_url"] = value self.music = music -@register_reply('news') +@register_reply("news") class ArticlesReply(BaseReply): """ 图文回复 详情请参阅 http://mp.weixin.qq.com/wiki/9/2c15b20a16019ae613d413e30cac8ea1.html """ - type = 'news' - articles = ArticlesField('Articles', []) + + type = "news" + articles = ArticlesField("Articles", []) def add_article(self, article): if len(self.articles) == 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) articles = self.articles articles.append(article) self.articles = articles -@register_reply('transfer_customer_service') +@register_reply("transfer_customer_service") class TransferCustomerServiceReply(BaseReply): """ 将消息转发到多客服 详情请参阅 http://mp.weixin.qq.com/wiki/5/ae230189c9bd07a6b221f48619aeef35.html """ - type = 'transfer_customer_service' + type = "transfer_customer_service" -@register_reply('device_text') + +@register_reply("device_text") class DeviceTextReply(BaseReply): - type = 'device_text' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_text" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_event') +@register_reply("device_event") class DeviceEventReply(BaseReply): - type = 'device_event' - event = StringField('Event') - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - session_id = StringField('SessionID') - content = Base64EncodeField('Content') + type = "device_event" + event = StringField("Event") + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + session_id = StringField("SessionID") + content = Base64EncodeField("Content") -@register_reply('device_status') +@register_reply("device_status") class DeviceStatusReply(BaseReply): - type = 'device_status' - device_type = StringField('DeviceType') - device_id = StringField('DeviceID') - status = IntegerField('DeviceStatus') + type = "device_status" + device_type = StringField("DeviceType") + device_id = StringField("DeviceID") + status = IntegerField("DeviceStatus") -@register_reply('hardware') +@register_reply("hardware") class HardwareReply(BaseReply): - type = 'hardware' - func_flag = IntegerField('FuncFlag', 0) - hardware = HardwareField('HardWare') + type = "hardware" + func_flag = IntegerField("FuncFlag", 0) + hardware = HardwareField("HardWare") def create_reply(reply, message=None, render=False): @@ -325,18 +336,13 @@ def create_reply(reply, message=None, render=False): r.source = message.target r.target = message.source elif isinstance(reply, six.string_types): - r = TextReply( - message=message, - content=reply - ) + r = TextReply(message=message, content=reply) elif isinstance(reply, (tuple, list)): if len(reply) > 10: - raise AttributeError("Can't add more than 10 articles" - " in an ArticlesReply") - r = ArticlesReply( - message=message, - articles=reply - ) + raise AttributeError( + "Can't add more than 10 articles" " in an ArticlesReply" + ) + r = ArticlesReply(message=message, articles=reply) if r and render: return r.render() return r diff --git a/chapter14/booking_system/exts/wechatpy/session/memcachedstorage.py b/chapter14/booking_system/exts/wechatpy/session/memcachedstorage.py index e9d7b33..15bd06d 100644 --- a/chapter14/booking_system/exts/wechatpy/session/memcachedstorage.py +++ b/chapter14/booking_system/exts/wechatpy/session/memcachedstorage.py @@ -8,14 +8,14 @@ class MemcachedStorage(SessionStorage): - def __init__(self, mc, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, mc, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(mc, method_name) self.mc = mc self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter14/booking_system/exts/wechatpy/session/redisstorage.py b/chapter14/booking_system/exts/wechatpy/session/redisstorage.py index 7412929..c931e64 100644 --- a/chapter14/booking_system/exts/wechatpy/session/redisstorage.py +++ b/chapter14/booking_system/exts/wechatpy/session/redisstorage.py @@ -7,14 +7,14 @@ class RedisStorage(SessionStorage): - def __init__(self, redis, prefix='wechatpy'): - for method_name in ('get', 'set', 'delete'): + def __init__(self, redis, prefix="wechatpy"): + for method_name in ("get", "set", "delete"): assert hasattr(redis, method_name) self.redis = redis self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter14/booking_system/exts/wechatpy/session/shovestorage.py b/chapter14/booking_system/exts/wechatpy/session/shovestorage.py index 2e0ffbf..1efda82 100644 --- a/chapter14/booking_system/exts/wechatpy/session/shovestorage.py +++ b/chapter14/booking_system/exts/wechatpy/session/shovestorage.py @@ -5,12 +5,12 @@ class ShoveStorage(SessionStorage): - def __init__(self, shove, prefix='wechatpy'): + def __init__(self, shove, prefix="wechatpy"): self.shove = shove self.prefix = prefix def key_name(self, key): - return '{0}:{1}'.format(self.prefix, key) + return "{0}:{1}".format(self.prefix, key) def get(self, key, default=None): key = self.key_name(key) diff --git a/chapter14/booking_system/exts/wechatpy/utils.py b/chapter14/booking_system/exts/wechatpy/utils.py index 74480ed..ee02ada 100644 --- a/chapter14/booking_system/exts/wechatpy/utils.py +++ b/chapter14/booking_system/exts/wechatpy/utils.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - wechatpy.utils - ~~~~~~~~~~~~~~~ +wechatpy.utils +~~~~~~~~~~~~~~~ - This module provides some useful utilities. +This module provides some useful utilities. - :copyright: (c) 2014 by messense. - :license: MIT, see LICENSE for more details. +:copyright: (c) 2014 by messense. +:license: MIT, see LICENSE for more details. """ from __future__ import absolute_import, unicode_literals import string @@ -14,7 +14,7 @@ import hashlib try: - '''Use simplejson if we can, fallback to json otherwise.''' + """Use simplejson if we can, fallback to json otherwise.""" import simplejson as json except ImportError: import json # NOQA @@ -24,8 +24,7 @@ class ObjectDict(dict): - """Makes a dictionary behave like an object, with attribute-style access. - """ + """Makes a dictionary behave like an object, with attribute-style access.""" def __getattr__(self, key): if key in self: @@ -39,7 +38,7 @@ def __setattr__(self, key, value): class WeChatSigner(object): """WeChat data signer""" - def __init__(self, delimiter=b''): + def __init__(self, delimiter=b""): self._data = [] self._delimiter = to_binary(delimiter) @@ -73,14 +72,14 @@ def check_signature(token, signature, timestamp, nonce): raise InvalidSignatureException() -def to_text(value, encoding='utf-8'): +def to_text(value, encoding="utf-8"): """Convert value to unicode, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return '' + return "" if isinstance(value, six.text_type): return value if isinstance(value, six.binary_type): @@ -88,14 +87,14 @@ def to_text(value, encoding='utf-8'): return six.text_type(value) -def to_binary(value, encoding='utf-8'): +def to_binary(value, encoding="utf-8"): """Convert value to binary string, default encoding is utf-8 :param value: Value to be converted :param encoding: Desired encoding """ if not value: - return b'' + return b"" if isinstance(value, six.binary_type): return value if isinstance(value, six.text_type): @@ -111,11 +110,13 @@ def timezone(zone): """ try: import pytz + return pytz.timezone(zone) except ImportError: pass try: from dateutil.tz import gettz + return gettz(zone) except ImportError: return None @@ -124,7 +125,7 @@ def timezone(zone): def random_string(length=16): rule = string.ascii_letters + string.digits rand_list = random.sample(rule, length) - return ''.join(rand_list) + return "".join(rand_list) def get_querystring(uri): diff --git a/chapter14/booking_system/main.py b/chapter14/booking_system/main.py index ec3f1e1..b0c5d55 100644 --- a/chapter14/booking_system/main.py +++ b/chapter14/booking_system/main.py @@ -1,12 +1,14 @@ from app import creat_app -app =creat_app() + +app = creat_app() if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) # tree -I "node_modules|cache|test_*" -# tree -I "__pycache__" \ No newline at end of file +# tree -I "__pycache__" diff --git a/chapter14/booking_system/middlewares/loger/middleware.py b/chapter14/booking_system/middlewares/loger/middleware.py index dca0ac5..e74aaef 100644 --- a/chapter14/booking_system/middlewares/loger/middleware.py +++ b/chapter14/booking_system/middlewares/loger/middleware.py @@ -15,87 +15,107 @@ request: Request = bind_contextvar(request_var) - - def setup_ext_loguru(log_pro_path: str = None): - ''' + """ :param pro_path: 当前需要生产的日志文件的存在路径 :return: - ''' + """ import os + if not log_pro_path: log_pro_path = os.path.split(os.path.realpath(__file__))[0] # 定义info_log文件名称 - log_file_path = os.path.join(log_pro_path, 'log/info_{time:YYYYMMDD}.log') + log_file_path = os.path.join(log_pro_path, "log/info_{time:YYYYMMDD}.log") # 定义err_log文件名称 - err_log_file_path = os.path.join(log_pro_path, 'log/error_{time:YYYYMMDD}.log') + err_log_file_path = os.path.join(log_pro_path, "log/error_{time:YYYYMMDD}.log") from sys import stdout - LOGURU_FORMAT: str = '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}' + + LOGURU_FORMAT: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <16} | {message}" + ) # 这句话很关键避免多次的写入我们的日志 - logger.configure(handlers=[{'sink': stdout, 'format': LOGURU_FORMAT}]) + logger.configure(handlers=[{"sink": stdout, "format": LOGURU_FORMAT}]) # 这个也可以启动避免多次的写入的作用,但是我们的 app:register_logger:40 -无法输出 # logger.remove() # 错误日志不需要压缩 format = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} |\n {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(err_log_file_path, format=format, rotation='00:00', encoding='utf-8', level='ERROR', enqueue=True) # Automatically rotate too big file + logger.add( + err_log_file_path, + format=format, + rotation="00:00", + encoding="utf-8", + level="ERROR", + enqueue=True, + ) # Automatically rotate too big file # 对应不同的格式 format2 = " {time:YYYY-MM-DD HH:mm:ss:SSS} | thread_id:{thread.id} thread_name:{thread.name} | {level} | {message}" # 使用 rotation 参数实现定时创建 log 文件,可以实现每天 0 点新创建一个 log 文件输出了 enqueue=True表示 开启异步写入 - logger.add(log_file_path, format=format2, rotation='00:00', encoding='utf-8', level='INFO', enqueue=True) # Automatically rotate too big file - + logger.add( + log_file_path, + format=format2, + rotation="00:00", + encoding="utf-8", + level="INFO", + enqueue=True, + ) # Automatically rotate too big file -async def async_trace_add_log_record(event_type='', msg={}, remarks=''): - ''' +async def async_trace_add_log_record(event_type="", msg={}, remarks=""): + """ :param event_type: 日志记录事件描述 :param msg: 日志记录信息字典 :param remarks: 日志备注信息 :return: - ''' + """ # 如果没有这个标记的属性的,说明这个接口的不需要记录啦! - if request and hasattr(request.state, 'traceid'): + if request and hasattr(request.state, "traceid"): # 自增编号索引序 - trace_links_index = request.state.trace_links_index = getattr(request.state, 'trace_links_index') + 1 + trace_links_index = request.state.trace_links_index = ( + getattr(request.state, "trace_links_index") + 1 + ) log = { # 自定义一个新的参数复制到我们的请求上下文的对象中 - 'traceid': getattr(request.state, 'traceid'), + "traceid": getattr(request.state, "traceid"), # 定义链路所以序号 - 'trace_index': trace_links_index, + "trace_index": trace_links_index, # 时间类型描述描述 - 'event_type': event_type, + "event_type": event_type, # 日志内容详情 - 'msg': msg, + "msg": msg, # 日志备注信息 - 'remarks': remarks, - + "remarks": remarks, } # 为少少相关记录,删除不必要的为空的日志内容信息, if not remarks: - log.pop('remarks') + log.pop("remarks") if not msg: - log.pop('msg') + log.pop("msg") try: log_msg = json_helper.dict_to_json_ensure_ascii(log) # 返回文本 logger.info(log_msg) except: - logger.info(getattr(request.state, 'traceid') + ':索引:' + str(getattr(request.state, 'trace_links_index')) + ':日志信息写入异常') - + logger.info( + getattr(request.state, "traceid") + + ":索引:" + + str(getattr(request.state, "trace_links_index")) + + ":日志信息写入异常" + ) class LogerMiddleware: def __init__( - self, - *, - app: ASGIApp, - log_pro_path: str, - is_record_useragent=False, - is_record_headers=False, - nesss_access_heads_keys=[], - ignore_url: typing.List = ['/favicon.ico', 'websocket'], + self, + *, + app: ASGIApp, + log_pro_path: str, + is_record_useragent=False, + is_record_headers=False, + nesss_access_heads_keys=[], + ignore_url: typing.List = ["/favicon.ico", "websocket"], ) -> None: self.app = app self.is_record_useragent = is_record_useragent @@ -105,11 +125,11 @@ def __init__( setup_ext_loguru(log_pro_path) def make_traceid(self, request) -> None: - ''' + """ 生成追踪链路ID :param request: :return: - ''' + """ request.state.traceid = shortuuid.uuid() # 追踪索引序号 request.state.trace_links_index = 0 @@ -119,36 +139,35 @@ def make_traceid(self, request) -> None: request.state.start_time = perf_counter() def make_token_request(self, request): - ''' + """ 生成当前请求上下文对象request :param request: :return: - ''' + """ return request_var.set(request) def reset_token_request(self, token_request): - ''' + """ 重置当前请求上下文对象request :param request: :return: - ''' + """ request_var.reset(token_request) - async def get_request_body(self, request) -> typing.AnyStr: body = None try: body_bytes = await request.body() if body_bytes: try: - body = await request.json() + body = await request.json() except: pass if body_bytes: try: - body = body_bytes.decode('utf-8') + body = body_bytes.decode("utf-8") except: - body = body_bytes.decode('gb2312') + body = body_bytes.decode("gb2312") except: pass request.state.body = body @@ -189,77 +208,102 @@ async def make_request_log_msg(self, request) -> typing.Dict: os_major, os_minor = 0, 0 log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), # 记录请求URL信息 - "useragent": None if not self.is_record_useragent else - { - "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string), - 'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string), - "device": { - "family": user_agent.device.family, - "brand": user_agent.device.brand, - "model": user_agent.device.model, + "useragent": ( + None + if not self.is_record_useragent + else { + "os": "{} {}".format( + user_agent.os.family, user_agent.os.version_string + ), + "browser": "{} {}".format( + user_agent.browser.family, user_agent.browser.version_string + ), + "device": { + "family": user_agent.device.family, + "brand": user_agent.device.brand, + "model": user_agent.device.model, + }, } - }, - 'url': url, + ), + "url": url, # 记录请求方法 - 'method': method, + "method": method, # 记录请求来源IP - 'ip': ip, + "ip": ip, # 'path': gziprequest.path, # 记录请求提交的参数信息 - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } # 对于没有的数据清除 - if not log_msg['headers']: - log_msg.pop('headers') - if not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - if not log_msg['params']['from']: - log_msg['params'].pop('from') - if not log_msg['params']['body']: - log_msg['params'].pop('body') + if not log_msg["headers"]: + log_msg.pop("headers") + if not log_msg["params"]["query_params"]: + log_msg["params"].pop("query_params") + if not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if not log_msg["params"]["body"]: + log_msg["params"].pop("body") except: log_msg = { - 'headers': None if not self.is_record_headers else - [request.headers.get(i, '') for i in - self.nesss_access_heads_keys] if self.nesss_access_heads_keys else None, - 'url': url, - 'method': method, - 'ip': ip, - 'params': { - 'query_params': parse_qs(str(request.query_params)), - 'from': body_form, - 'body': body + "headers": ( + None + if not self.is_record_headers + else ( + [ + request.headers.get(i, "") + for i in self.nesss_access_heads_keys + ] + if self.nesss_access_heads_keys + else None + ) + ), + "url": url, + "method": method, + "ip": ip, + "params": { + "query_params": parse_qs(str(request.query_params)), + "from": body_form, + "body": body, }, - "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}' + "ts": f"{datetime.now():%Y-%m-%d %H:%M:%S%z}", } - print('log_msg', log_msg) + print("log_msg", log_msg) # 对于没有的数据清除 - if 'headers' in log_msg and not log_msg['headers']: - log_msg.pop('headers') - if log_msg['params']: - if 'query_params' in log_msg['params'] and not log_msg['params']['query_params']: - log_msg['params'].pop('query_params') - print(log_msg['params']) - if 'from' in log_msg['params'] and not log_msg['params']['from']: - log_msg['params'].pop('from') - if 'body' in log_msg['params'] and not log_msg['params']['body']: - log_msg['params'].pop('body') + if "headers" in log_msg and not log_msg["headers"]: + log_msg.pop("headers") + if log_msg["params"]: + if ( + "query_params" in log_msg["params"] + and not log_msg["params"]["query_params"] + ): + log_msg["params"].pop("query_params") + print(log_msg["params"]) + if "from" in log_msg["params"] and not log_msg["params"]["from"]: + log_msg["params"].pop("from") + if "body" in log_msg["params"] and not log_msg["params"]["body"]: + log_msg["params"].pop("body") return log_msg - - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] != "http": # pragma: no cover await self.app(scope, receive, send) @@ -284,9 +328,9 @@ async def receive(): # 生成日志记录 log_msg = await self.make_request_log_msg(request) # 开始写日志信息到文件中 - await async_trace_add_log_record(event_type='request', msg=log_msg) + await async_trace_add_log_record(event_type="request", msg=log_msg) try: response = await self.app(scope, receive, send) return response finally: - self.reset_token_request(token_request) + self.reset_token_request(token_request) diff --git a/chapter14/booking_system/order_consumer.py b/chapter14/booking_system/order_consumer.py index d417a2f..88d332f 100644 --- a/chapter14/booking_system/order_consumer.py +++ b/chapter14/booking_system/order_consumer.py @@ -7,7 +7,7 @@ 创建人 : 小钟同学 创建时间 : 2021/10/19 ------------------------------------------------- - 修改描述-2021/10/19: + 修改描述-2021/10/19: ------------------------------------------------- """ import pika @@ -21,24 +21,33 @@ credentials = pika.PlainCredentials("guest", "guest") # 创建连接http://47.99.189.42:30100/ connection = pika.BlockingConnection( - pika.ConnectionParameters(host='localhost', port=5672, virtual_host='yuyueguahao', credentials=credentials)) + pika.ConnectionParameters( + host="localhost", port=5672, virtual_host="yuyueguahao", credentials=credentials + ) +) # 通过连接创建信道 channel = connection.channel() # 通过信道创建我们的队列 其中名称是task_queue,并且这个队列的消息是需要持久化的!PS:持久化存储存到磁盘会占空间, # 队列不能由持久化变为普通队列,反过来也是!否则会报错!所以队列类型创建的开始必须确定的! -order_dead_letter_exchange_name = 'xz-dead-letter-exchange' -order_dead_letter_exchange_type = 'fanout' -order_dead_letter_queue_name = 'xz-dead-letter-queue' -order_dead_letter_routing_key = 'xz-dead-letter-queue' +order_dead_letter_exchange_name = "xz-dead-letter-exchange" +order_dead_letter_exchange_type = "fanout" +order_dead_letter_queue_name = "xz-dead-letter-queue" +order_dead_letter_routing_key = "xz-dead-letter-queue" # 相对比只要交换机名称即可接收到消息的广播模式(fanout),direct模式在其基础上,多加了一层密码限制(routingKey) -channel.exchange_declare(exchange=order_dead_letter_exchange_name, durable=True, - exchange_type=order_dead_letter_exchange_type) +channel.exchange_declare( + exchange=order_dead_letter_exchange_name, + durable=True, + exchange_type=order_dead_letter_exchange_type, +) channel.queue_declare(queue=order_dead_letter_queue_name, durable=True) -channel.queue_bind(exchange=order_dead_letter_exchange_name, queue=order_dead_letter_queue_name, - routing_key=order_dead_letter_routing_key) +channel.queue_bind( + exchange=order_dead_letter_exchange_name, + queue=order_dead_letter_queue_name, + routing_key=order_dead_letter_routing_key, +) -print(' [*] 死信队列里面的死信消息的消费. To exit press CTRL+C') +print(" [*] 死信队列里面的死信消息的消费. To exit press CTRL+C") # 初始化数据库的链接处理 @@ -50,11 +59,17 @@ def callback(ch, method, properties, body): # 获取当前的订单支付状态信息,如果当前处于没支付的状态的话,则需要回滚我们的库存 with sync_context_get_db() as session: - _result = session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'), - DoctorSubscribeinfo.visit_uopenid == mesgg.get( - 'visit_uopenid'), - DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).one_or_none() + _result = ( + session.query(DoctorSubscribeinfo) + .filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.visit_uopenid == mesgg.get("visit_uopenid"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ) + .one_or_none() + ) if _result: @@ -65,9 +80,12 @@ def callback(ch, method, properties, body): pass # 更新订单状态 print("更新状态!!!!!!!!!!!!!") - session.query(DoctorSubscribeinfo).filter(and_(DoctorSubscribeinfo.dno == mesgg.get('dno'),DoctorSubscribeinfo.orderid == mesgg.get( - 'orderid'))).update({DoctorSubscribeinfo.statue: 4}, - synchronize_session=False) + session.query(DoctorSubscribeinfo).filter( + and_( + DoctorSubscribeinfo.dno == mesgg.get("dno"), + DoctorSubscribeinfo.orderid == mesgg.get("orderid"), + ) + ).update({DoctorSubscribeinfo.statue: 4}, synchronize_session=False) elif _result.statue == 3: pass elif _result.statue == 5: @@ -84,7 +102,7 @@ def callback(ch, method, properties, body): channel.basic_qos(prefetch_count=1) # await channel.set_qos(prefetch_count=1) # 开始进行订阅消费 -ack = channel.basic_consume(queue='xz-dead-letter-queue', on_message_callback=callback) -print('s', ack) +ack = channel.basic_consume(queue="xz-dead-letter-queue", on_message_callback=callback) +print("s", ack) # 消费者会阻塞在这里,一直等待消息,队列中有消息了,就会执行消息的回调函数 channel.start_consuming() diff --git a/chapter14/booking_system/plugins/base.py b/chapter14/booking_system/plugins/base.py index 847db87..72827ca 100644 --- a/chapter14/booking_system/plugins/base.py +++ b/chapter14/booking_system/plugins/base.py @@ -3,12 +3,21 @@ import typing import abc + class PluginBase(abc.ABC): - def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): + def __init__( + self, app: fastapi.FastAPI = None, config: pydantic.BaseSettings = None + ): if app is not None: self.init_app(app) @abc.abstractmethod - def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: - raise NotImplementedError('需要实现初始化') + def init_app( + self, + app: fastapi.FastAPI, + config: pydantic.BaseSettings = None, + *args, + **kwargs + ) -> None: + raise NotImplementedError("需要实现初始化") diff --git a/chapter14/booking_system/plugins/request_hook.py b/chapter14/booking_system/plugins/request_hook.py index 5cc23e7..c43f5ee 100644 --- a/chapter14/booking_system/plugins/request_hook.py +++ b/chapter14/booking_system/plugins/request_hook.py @@ -1,4 +1,3 @@ - from plugins.base import PluginBase from fastapi import FastAPI from pydantic import BaseSettings @@ -10,15 +9,24 @@ class HookPluginClient(PluginBase): # 设置插件默认的参数信息 - def __init__(self, - on_before_request: typing.Sequence[typing.Callable] = None, - on_after_request: typing.Sequence[typing.Callable] = None, - on_teardown_appcontext: typing.Sequence[typing.Callable] = None, - *args, **kwargs): + def __init__( + self, + on_before_request: typing.Sequence[typing.Callable] = None, + on_after_request: typing.Sequence[typing.Callable] = None, + on_teardown_appcontext: typing.Sequence[typing.Callable] = None, + *args, + **kwargs + ): super().__init__(*args, **kwargs) - self.on_before_request = [] if on_before_request is None else list(on_before_request) - self.on_after_request = [] if on_after_request is None else list(on_after_request) - self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + self.on_before_request = ( + [] if on_before_request is None else list(on_before_request) + ) + self.on_after_request = ( + [] if on_after_request is None else list(on_after_request) + ) + self.on_teardown_appcontext = ( + [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + ) def init_app(self, app: FastAPI, *args, **kwargs): pass @@ -50,6 +58,7 @@ def on_event(self, event_type: str) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_event_handler(event_type, func) return func + return decorator async def before_request(self, request) -> None: @@ -72,4 +81,4 @@ async def teardown_appcontext(self, request, response) -> None: if asyncio.iscoroutinefunction(handler): await handler(request, response) else: - handler(request, response) \ No newline at end of file + handler(request, response) diff --git a/chapter14/booking_system/testcase/conftest.py b/chapter14/booking_system/testcase/conftest.py index 4dbe611..e18c976 100644 --- a/chapter14/booking_system/testcase/conftest.py +++ b/chapter14/booking_system/testcase/conftest.py @@ -4,9 +4,10 @@ import asyncio import sys from db.async_database import async_engine + # 需要加载当前项目目录。sys.path.append('E://yuanxiao//code//booking_system//booking_system'), # 不然在项目根目录执行pytest会出现ModuleNotFoundError: No module named 'app' -sys.path.append('E://yuanxiao//code//booking_system//booking_system') +sys.path.append("E://yuanxiao//code//booking_system//booking_system") from app import app # ===========================================同步使用 @@ -14,6 +15,8 @@ from typing import Dict, Generator import pytest from fastapi.testclient import TestClient + + @pytest.fixture(scope="module") def client() -> Generator: with TestClient(app) as c: @@ -25,6 +28,7 @@ def client() -> Generator: # 修改设置优先循环事件 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + # 配置使用哪一种模式的异步 @pytest.fixture( params=[ @@ -34,15 +38,21 @@ def client() -> Generator: def anyio_backend(request): return request.param + # 解决当接口中涉及到依赖注入的数据库使用 async def start_db(): async with async_engine.begin() as conn: pass await async_engine.dispose() + @pytest_asyncio.fixture async def async_client() -> AsyncClient: - async with AsyncClient(app=app,base_url="http://test", headers={"Content-Type": "application/json"},) as async_client: + async with AsyncClient( + app=app, + base_url="http://test", + headers={"Content-Type": "application/json"}, + ) as async_client: await start_db() yield async_client - await async_engine.dispose() \ No newline at end of file + await async_engine.dispose() diff --git a/chapter14/booking_system/testcase/test_async_api_v1.py b/chapter14/booking_system/testcase/test_async_api_v1.py index 0464845..83a728f 100644 --- a/chapter14/booking_system/testcase/test_async_api_v1.py +++ b/chapter14/booking_system/testcase/test_async_api_v1.py @@ -16,8 +16,9 @@ import pytest + @pytest.mark.anyio -@pytest.mark.parametrize('anyio_backend', ['asyncio']) +@pytest.mark.parametrize("anyio_backend", ["asyncio"]) async def test_doctor_list(async_client): res = await async_client.get("/api/v1/doctor_list") assert res.status_code == 200 @@ -25,7 +26,7 @@ async def test_doctor_list(async_client): @pytest.mark.anyio -@pytest.mark.parametrize('anyio_backend', ['asyncio']) +@pytest.mark.parametrize("anyio_backend", ["asyncio"]) async def test_hospital_info(async_client): res = await async_client.get("/api/v1/hospital_info") assert res.status_code == 200 diff --git a/chapter14/booking_system/testcase/test_async_api_v2.py b/chapter14/booking_system/testcase/test_async_api_v2.py index 2c9c53a..a65f873 100644 --- a/chapter14/booking_system/testcase/test_async_api_v2.py +++ b/chapter14/booking_system/testcase/test_async_api_v2.py @@ -2,15 +2,17 @@ # import pytest from httpx import AsyncClient + pytestmark = pytest.mark.anyio + async def test_hospital_info(async_client: AsyncClient): response = await async_client.get("/api/v1/hospital_info") - print('response', response.text) + print("response", response.text) assert response.status_code == 200 async def test_doctor_list(async_client: AsyncClient): response = await async_client.get("/api/v1/doctor_list") - print('response', response.text) - assert response.status_code == 200 \ No newline at end of file + print("response", response.text) + assert response.status_code == 200 diff --git a/chapter14/booking_system/testcase/test_sync_api.py b/chapter14/booking_system/testcase/test_sync_api.py index e6ec0fd..dc18420 100644 --- a/chapter14/booking_system/testcase/test_sync_api.py +++ b/chapter14/booking_system/testcase/test_sync_api.py @@ -34,15 +34,15 @@ from fastapi.testclient import TestClient - -def test_hospitalinfo(client:TestClient): - res = client.get('/api/v1/hospital_info') - print('sdsd',res.text) +def test_hospitalinfo(client: TestClient): + res = client.get("/api/v1/hospital_info") + print("sdsd", res.text) assert res.status_code == 200 assert type(res.status_code) == int -def test_doctorlist(client:TestClient): - res = client.get('/api/v1/doctor_list') - print('dsasd',res.text) + +def test_doctorlist(client: TestClient): + res = client.get("/api/v1/doctor_list") + print("dsasd", res.text) assert res.status_code == 200 - assert type(res.status_code) == int \ No newline at end of file + assert type(res.status_code) == int diff --git a/chapter14/booking_system/utils/cast_helper.py b/chapter14/booking_system/utils/cast_helper.py index c0803c1..4693ad3 100644 --- a/chapter14/booking_system/utils/cast_helper.py +++ b/chapter14/booking_system/utils/cast_helper.py @@ -1,2 +1,2 @@ -def add(a,b): - return a+b; \ No newline at end of file +def add(a, b): + return a + b diff --git a/chapter14/booking_system/utils/datatime_helper.py b/chapter14/booking_system/utils/datatime_helper.py index ab77882..c6e1e6c 100644 --- a/chapter14/booking_system/utils/datatime_helper.py +++ b/chapter14/booking_system/utils/datatime_helper.py @@ -5,48 +5,58 @@ def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False return True - def get_timestamp10(): """获取当前时间长度为10位长度的时间戳""" return int(time.time()) def str_to_datatime(srr_time, strftime="%Y-%m-%d"): - print('strftimestrftimestrftime',strftime) + print("strftimestrftimestrftime", strftime) return datetime.datetime.strptime(srr_time, strftime) -str_to_datatime('2021-12-27 10:00:00',strftime='%Y-%m-%d %H:%M:%S') + +str_to_datatime("2021-12-27 10:00:00", strftime="%Y-%m-%d %H:%M:%S") + def datatime_to_str(data_time: datetime.datetime, strftime="%Y-%m-%d"): return data_time.strftime(strftime) def diff_days_for_now_time(srr_time): - ''' + """ 对比当前的传入日期和当前系统时间的相差的天数 :param srr_time: :return: - ''' - return (datetime.datetime.strptime(srr_time, "%Y-%m-%d") - datetime.datetime.combine(datetime.datetime.now().date(), - datetime.time())).days + """ + return ( + datetime.datetime.strptime(srr_time, "%Y-%m-%d") + - datetime.datetime.combine(datetime.datetime.now().date(), datetime.time()) + ).days # 获取当前日期 # today=time.strftime('%Y-%m-%d',time.localtime(time.time())) + def currday_time_info(): - return time.strftime('%Y-%m-%d', time.localtime(time.time())) + return time.strftime("%Y-%m-%d", time.localtime(time.time())) def currday_time_info_tochane_datetime(today): @@ -55,11 +65,17 @@ def currday_time_info_tochane_datetime(today): def effectiveness_tiempm(tiempm): - today = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time())).replace("-", "") - todaydate = datetime.datetime.strptime(today, "%Y%m%d %H:%M") # 字符串转化为date形式 + today = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())).replace( + "-", "" + ) + todaydate = datetime.datetime.strptime( + today, "%Y%m%d %H:%M" + ) # 字符串转化为date形式 # 预约时段的时间 yuyue_day = tiempm.replace("-", "") - yuyue_daydate = datetime.datetime.strptime(yuyue_day, "%Y%m%d %H:%M:%S") # 字符串转化为date形式 + yuyue_daydate = datetime.datetime.strptime( + yuyue_day, "%Y%m%d %H:%M:%S" + ) # 字符串转化为date形式 # 超出预约时间范围 if todaydate >= yuyue_daydate: return False @@ -68,9 +84,9 @@ def effectiveness_tiempm(tiempm): # 根据给定的日期,获取前n天或后n天的日期,n为正数则是以后的n天,n为负数则是以前的n天,不包括当天 def get_day_of_day(str2date, n=0): - if (n < 0): + if n < 0: n = abs(n) - return (str2date - timedelta(days=n)) + return str2date - timedelta(days=n) else: return str2date + timedelta(days=n) @@ -83,7 +99,7 @@ def num_to_string(num): 3: "周三", 4: "周四", 5: "周五", - 6: "周六" + 6: "周六", } return numbers.get(num, None) @@ -93,9 +109,9 @@ def get_7day_info_list(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = { - 'weekday': num_to_string(datatime.isoweekday()), - 'datetimeday': datatime.strftime('%Y-%m-%d') + ditcs[datatime.strftime("%Y-%m-%d")] = { + "weekday": num_to_string(datatime.isoweekday()), + "datetimeday": datatime.strftime("%Y-%m-%d"), } return ditcs @@ -105,6 +121,5 @@ def get_7day_info_list_only_data(num=6): ditcs = dict() for i in range(num + 1): datatime = get_day_of_day(currday_time_info_tochane_datetime(today), i) - ditcs[datatime.strftime('%Y-%m-%d')] = {} + ditcs[datatime.strftime("%Y-%m-%d")] = {} return ditcs - diff --git a/chapter14/booking_system/utils/json_helper.py b/chapter14/booking_system/utils/json_helper.py index f8a3fd2..6a1de21 100644 --- a/chapter14/booking_system/utils/json_helper.py +++ b/chapter14/booking_system/utils/json_helper.py @@ -8,16 +8,16 @@ class CJsonEncoder(json.JSONEncoder): def default(self, obj): - if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'): + if hasattr(obj, "keys") and hasattr(obj, "__getitem__"): return dict(obj) if isinstance(obj, datetime.datetime): - return obj.strftime('%Y-%m-%d %H:%M:%S') + return obj.strftime("%Y-%m-%d %H:%M:%S") if isinstance(obj, datetime.date): - return obj.strftime('%Y-%m-%d') + return obj.strftime("%Y-%m-%d") if isinstance(obj, decimal.Decimal): return float(obj) if isinstance(obj, bytes): - return str(obj, encoding='utf-8') + return str(obj, encoding="utf-8") return json.JSONEncoder.default(self, obj) @@ -61,7 +61,7 @@ def class_to_dict(obj): else: dict = {} dict.update(obj.__dict__) - return dict.get('__data__') + return dict.get("__data__") import base64 @@ -125,4 +125,4 @@ def dumps( default=default, sort_keys=sort_keys, **kw - ) \ No newline at end of file + ) diff --git a/chapter14/booking_system/utils/ordernum_helper.py b/chapter14/booking_system/utils/ordernum_helper.py index 6723543..80ec95c 100644 --- a/chapter14/booking_system/utils/ordernum_helper.py +++ b/chapter14/booking_system/utils/ordernum_helper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -37,27 +37,42 @@ def order_num_1(package_id=12345, user_num=56789): # 商品id后1位+下单时间的年月日12+用户2后四位+随机数3位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(100, 999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(100, 999)) + ) return result def order_num_2(package_id=12345, user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result = str(package_id)[-2:] + local_time + str(user_num)[-2:] + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(package_id)[-2:] + + local_time + + str(user_num)[-2:] + + str(random.randint(1000, 9999)) + ) return result def order_num_3(user_num=56789): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =f'{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}' + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = f"{local_time}{str(user_num)[-2:] }{random.randint(10000, 99999)}" return result -def order_num_srt(user_num='56789'): +def order_num_srt(user_num="56789"): # 商品id后2位+下单时间的年月日12+用户2后四位+随机数4位 - local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))[2:] - result =str(user_num)[-2:] + str(random.randint(100, 999)) + local_time + str(random.randint(1000, 9999)) + local_time = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))[2:] + result = ( + str(user_num)[-2:] + + str(random.randint(100, 999)) + + local_time + + str(random.randint(1000, 9999)) + ) return result diff --git a/chapter14/booking_system/utils/run_with_asyncio.py b/chapter14/booking_system/utils/run_with_asyncio.py index 0d845ba..edf6416 100644 --- a/chapter14/booking_system/utils/run_with_asyncio.py +++ b/chapter14/booking_system/utils/run_with_asyncio.py @@ -2,11 +2,15 @@ import asyncio from functools import wraps from typing import Any, Awaitable, Callable, TypeVar + T = TypeVar("T") __all__ = ["run_with_asyncio"] + + def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> T: print("pajinlail") return asyncio.run(f(*args, **kwargs)) - return wrapper \ No newline at end of file + + return wrapper diff --git a/chapter14/booking_system/utils/xmlhelper.py b/chapter14/booking_system/utils/xmlhelper.py index a831fd9..883bb15 100644 --- a/chapter14/booking_system/utils/xmlhelper.py +++ b/chapter14/booking_system/utils/xmlhelper.py @@ -3,19 +3,19 @@ # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + # ┏┓   ┏┓+ + #    ┏┛┻━━━┛┻┓ + + -#    ┃       ┃   +#    ┃       ┃ #    ┃   ━   ┃ ++ + + + #    ████━████ ┃+ #    ┃       ┃ + #    ┃   ┻   ┃ #    ┃       ┃ + + #    ┗━┓   ┏━┛ -#      ┃   ┃            +#      ┃   ┃ #      ┃   ┃ + + + + -#      ┃   ┃    Codes are far away from bugs with the animal protecting    -#      ┃   ┃ +     神兽保佑,代码无bug   +#      ┃   ┃    Codes are far away from bugs with the animal protecting +#      ┃   ┃ +     神兽保佑,代码无bug #      ┃   ┃ -#      ┃   ┃  +          +#      ┃   ┃  + #      ┃    ┗━━━┓ + + #      ┃        ┣┓ #      ┃        ┏┛ @@ -43,10 +43,16 @@ def parse_xml_data(xml): except (xmltodict.ParsingInterrupted, ExpatError): raise Exception() - if not data or 'xml' not in data: + if not data or "xml" not in data: raise Exception() - data = data['xml'] - for key in ('total_fee', 'settlement_total_fee', 'cash_fee', 'coupon_fee', 'coupon_count'): + data = data["xml"] + for key in ( + "total_fee", + "settlement_total_fee", + "cash_fee", + "coupon_fee", + "coupon_count", + ): if key in data: data[key] = int(data[key]) return data diff --git a/chapter15/Fastapi_cProfile/main.py b/chapter15/Fastapi_cProfile/main.py index 3fc79e7..650464c 100644 --- a/chapter15/Fastapi_cProfile/main.py +++ b/chapter15/Fastapi_cProfile/main.py @@ -8,8 +8,17 @@ # app.add_middleware(CProfileMiddleware) # app.add_middleware(CProfileMiddleware, enable=True, print_each_request = True, strip_dirs = False, sort_by='cumulative') -app.add_middleware(CProfileMiddleware, enable=True, server_app = app, filename='.prof', strip_dirs = False, sort_by='cumulative') +app.add_middleware( + CProfileMiddleware, + enable=True, + server_app=app, + filename=".prof", + strip_dirs=False, + sort_by="cumulative", +) import asyncio + + @app.get("/") async def main(): def randomlist(n): @@ -25,11 +34,10 @@ def randomlist(n): return {"message": "Hello World"} - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/Jaeger/test_jaeger_client/main.py b/chapter15/Jaeger/test_jaeger_client/main.py index aa342ce..afe8d36 100644 --- a/chapter15/Jaeger/test_jaeger_client/main.py +++ b/chapter15/Jaeger/test_jaeger_client/main.py @@ -5,26 +5,30 @@ def construct_span(tracer): # 定义span的名称为TestSpan - with tracer.start_span('TestSpan') as span: + with tracer.start_span("TestSpan") as span: # 设置这个span传递的日志信息 - span.log_kv({'event': '父Span', 'other': "我是第一个父的Span"}) + span.log_kv({"event": "父Span", "other": "我是第一个父的Span"}) time.sleep(1) # 定义AliyunTestSpan的子Span,类似第一个追踪的数据的子层级 - with tracer.start_span('TestSpan-ChildSpan-01', child_of=span) as child_span: + with tracer.start_span("TestSpan-ChildSpan-01", child_of=span) as child_span: time.sleep(2) # 设置父的span键值对日志信息 - span.log_kv({'event': '我是父Span--日志1'}) + span.log_kv({"event": "我是父Span--日志1"}) # 设置子child_span的日志 - child_span.log_kv({'event': '父Span--第一层子Span-01'}) - with tracer.start_span('TestSpan-ChildSpan-01', child_of=span) as child_span: + child_span.log_kv({"event": "父Span--第一层子Span-01"}) + with tracer.start_span("TestSpan-ChildSpan-01", child_of=span) as child_span: time.sleep(3) - span.log_kv({'event': '我是父Span--日志2'}) - child_span.log_kv({'event': '父Span--第一层子Span-02'}) + span.log_kv({"event": "我是父Span--日志2"}) + child_span.log_kv({"event": "父Span--第一层子Span-02"}) - with tracer.start_span('TestSpanC-hildSpan-01-01', child_of=child_span) as Span3_child_span: + with tracer.start_span( + "TestSpanC-hildSpan-01-01", child_of=child_span + ) as Span3_child_span: time.sleep(4) - span.log_kv({'event': '我是父Span--日志3'}) - Span3_child_span.log_kv({'event': '父Span--第一层子Span-的下一个子Span'}) + span.log_kv({"event": "我是父Span--日志3"}) + Span3_child_span.log_kv( + {"event": "父Span--第一层子Span-的下一个子Span"} + ) return span @@ -32,30 +36,30 @@ def construct_span(tracer): if __name__ == "__main__": # 定义日志输出的登记 log_level = logging.DEBUG - logging.getLogger('').handlers = [] + logging.getLogger("").handlers = [] # 配置日志默认输出格式 - logging.basicConfig(format='%(asctime)s %(message)s', level=log_level) + logging.basicConfig(format="%(asctime)s %(message)s", level=log_level) # Jaeger配置信息 config = Config( # 服务信息配置 config={ # sampler 采样 - 'sampler': { - 'type': 'const', # 采样类型 - 'param': 1, # 采样开关 1:开启全部采样 0:关闭全部 + "sampler": { + "type": "const", # 采样类型 + "param": 1, # 采样开关 1:开启全部采样 0:关闭全部 }, # 配置链接到我们的本地的agent,通过agent来上报 - 'local_agent': { + "local_agent": { # 注意这里是指定了JaegerAgent的host和port。 # 根据官方建议为了保证数据可靠性,JaegerClient和JaegerAgent运行在同一台主机内,因此reporting_host填写为127.0.0.1。 - 'reporting_host': '192.168.126.130', - 'reporting_port': 6831, + "reporting_host": "192.168.126.130", + "reporting_port": 6831, }, - 'logging': True, + "logging": True, }, # 这里填写应用名称---服务的名称 service_name="MyFirstSpan", - validate=True + validate=True, ) # this call also sets opentracing.tracer diff --git a/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py b/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py index be84349..c8b27c8 100644 --- a/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py +++ b/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py @@ -1,4 +1,3 @@ - from typing import List, Any from fastapi import Request from jaeger_client import Config @@ -9,18 +8,16 @@ from fastapi import FastAPI - - class OpentracingJaegerMiddleware(BaseHTTPMiddleware): - def __init__(self,fastapiapp: FastAPI,*args,**kwargs) -> None: - super().__init__(*args,**kwargs) + def __init__(self, fastapiapp: FastAPI, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) self.fastapiapp = fastapiapp - self.fastapiapp.add_event_handler('startup', self.setup_opentracing) + self.fastapiapp.add_event_handler("startup", self.setup_opentracing) def setup_opentracing(self): # 配置连接信息 - jaeger_host = '192.168.126.130' + jaeger_host = "192.168.126.130" jaeger_port = 6831 service_name = "测试2" trace_id_header = "X-TRACE-ID" @@ -31,28 +28,28 @@ def setup_opentracing(self): config={ "local_agent": { "reporting_host": jaeger_host, - "reporting_port": jaeger_port + "reporting_port": jaeger_port, }, "sampler": { "type": jaeger_sampler_type, "param": jaeger_sampler_rate, }, - "trace_id_header": trace_id_header + "trace_id_header": trace_id_header, }, service_name=service_name, validate=True, - scope_manager=AsyncioScopeManager() + scope_manager=AsyncioScopeManager(), ) self.fastapiapp.state.tracer = _tracer_config.initialize_tracer() - - async def dispatch(self, request: Request, call_next: Any) -> Response: # 获取tracer对象 tracer = request.app.state.tracer # 开始解析上下文(Extract函数): # 该函数主要用于在跨服务进程中,进行解析还原上一个传入Span 信息,通常是通过获取请求的headers进行参数信息提取; - span_context = tracer.extract(format=Format.HTTP_HEADERS, carrier=request.headers) + span_context = tracer.extract( + format=Format.HTTP_HEADERS, carrier=request.headers + ) # 开始创建span对象通过span_context,来决定是否存在层级span span = tracer.start_span( operation_name=f"{request.method} {request.url.path}", @@ -71,15 +68,12 @@ async def dispatch(self, request: Request, call_next: Any) -> Response: # 设置client请求来源端口的标签 span.set_tag(tags.PEER_PORT, request.client.port or "") # #Component(字符串)ia模块、库或正在生成跨区的包。 - span.set_tag(tags.COMPONENT, 'Fastapi') + span.set_tag(tags.COMPONENT, "Fastapi") # 标记表示RPC或其他远程调用的服务器端的范围 span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_SERVER) # (字符串)是请求的HTTP方法。 span.set_tag(tags.HTTP_METHOD, request.method) - - - # Scope 对象 主要是管理Active Span的容器 # Scope 代表着当前活跃的Span; 是对当前活跃Span的一个抽象 # ScopeManager 包含一个 Scope, Scope 又包含了 当前Span @@ -99,5 +93,3 @@ async def dispatch(self, request: Request, call_next: Any) -> Response: # inject之后,实际 headers = {'uber-trace-id': '6997ed0a6a74f050:bf49be2de63d86e7:e02975aab05fd358:1'} print(headers) return response - - diff --git a/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/main.py b/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/main.py index afd7e50..b6ffb19 100644 --- a/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/main.py +++ b/chapter15/Jaeger/test_jaeger_client_fastapi/middeware/main.py @@ -8,23 +8,28 @@ @app.get("/tracing") -def tracing(request: Request, x_trace_id: Optional[str] = Header(None, convert_underscores=True)): +def tracing( + request: Request, x_trace_id: Optional[str] = Header(None, convert_underscores=True) +): # 拿到当前生效的tracer tracer = request.app.state.tracer # 判断是否存在对应的上一个层级的span span = request.state.opentracing_span # 创建新的span - with tracer.start_span('new—span-test', child_of=span) as child_span_1: - span.log_kv({'event': '父类的span事件信息1'}) - span.log_kv({'event': '父类的span事件信息2', - 'request.args': request.query_params, }) + with tracer.start_span("new—span-test", child_of=span) as child_span_1: + span.log_kv({"event": "父类的span事件信息1"}) + span.log_kv( + { + "event": "父类的span事件信息2", + "request.args": request.query_params, + } + ) # child_span_1.log_kv({'event': 'child_span-down below'}) # with tracer.start_span('new—span-test-childspan', child_of=child_span_1) as child_span_2: # child_span_2.log_kv({'event': 'new—span-test-childspan-childspan'}) - return "ok" @@ -34,4 +39,4 @@ def tracing(request: Request, x_trace_id: Optional[str] = Header(None, convert_u app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/async_sync_change/main_asgiref_async_to_sync.py b/chapter15/async_sync_change/main_asgiref_async_to_sync.py index a71535e..c323aac 100644 --- a/chapter15/async_sync_change/main_asgiref_async_to_sync.py +++ b/chapter15/async_sync_change/main_asgiref_async_to_sync.py @@ -1,6 +1,6 @@ from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request from fastapi.responses import PlainTextResponse from fastapi.params import Body @@ -9,14 +9,16 @@ @app.post("/get/access_token") -def access_token(request:Request,name=Body(...)): +def access_token(request: Request, name=Body(...)): # print(reques.body()) from asgiref.sync import async_to_sync + body = async_to_sync(request.body)() print(body) - return PlainTextResponse(body.decode(encoding='utf-8')) + return PlainTextResponse(body.decode(encoding="utf-8")) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) \ No newline at end of file + + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter15/async_sync_change/main_asgiref_sync_to_async.py b/chapter15/async_sync_change/main_asgiref_sync_to_async.py index 4bab1e5..13f4d1c 100644 --- a/chapter15/async_sync_change/main_asgiref_sync_to_async.py +++ b/chapter15/async_sync_change/main_asgiref_sync_to_async.py @@ -1,22 +1,22 @@ from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi.responses import PlainTextResponse, HTMLResponse from asgiref.sync import sync_to_async import requests + # 定义我们的APP服务对象 app = FastAPI() -def getdata(): - return requests.get('http://www.baidu.com').text - +def getdata(): + return requests.get("http://www.baidu.com").text @app.get("/get/access_token") async def access_token(): - asds= await sync_to_async(func=getdata)() + asds = await sync_to_async(func=getdata)() return HTMLResponse(asds) @@ -26,6 +26,4 @@ async def access_token(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) - - + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/async_sync_change/main_asyncer_asyncify.py b/chapter15/async_sync_change/main_asyncer_asyncify.py index 44d1cf9..81e3d0c 100644 --- a/chapter15/async_sync_change/main_asyncer_asyncify.py +++ b/chapter15/async_sync_change/main_asyncer_asyncify.py @@ -1,19 +1,23 @@ -from fastapi import FastAPI,Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi import FastAPI, Request +from fastapi.responses import PlainTextResponse, HTMLResponse from asyncer import asyncify import requests + # 定义我们的APP服务对象 app = FastAPI() + def do_sync_work(name): - return requests.get(f'http://www.baidu.com?name={name}').text + return requests.get(f"http://www.baidu.com?name={name}").text + @app.get("/get/access_token") -async def access_token(request:Request): +async def access_token(request: Request): message = await asyncify(do_sync_work)(name="World") return HTMLResponse(message) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) + + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter15/async_sync_change/main_asyncer_syncify.py b/chapter15/async_sync_change/main_asyncer_syncify.py index 1cd5b55..53bb120 100644 --- a/chapter15/async_sync_change/main_asyncer_syncify.py +++ b/chapter15/async_sync_change/main_asyncer_syncify.py @@ -1,18 +1,20 @@ -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request from fastapi.responses import PlainTextResponse from fastapi.params import Body -from fastapi.background import BackgroundTasks -from asyncer import asyncify,syncify +from fastapi.background import BackgroundTasks +from asyncer import asyncify, syncify app = FastAPI() + @app.post("/get/access_token") -def access_token(request:Request,name=Body(...)): +def access_token(request: Request, name=Body(...)): body = syncify(request.body)() print(body) - return PlainTextResponse(body.decode(encoding='utf-8')) + return PlainTextResponse(body.decode(encoding="utf-8")) + -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter15/async_wrapper/main_asgiref_sync_to_async.py b/chapter15/async_wrapper/main_asgiref_sync_to_async.py index e9dc0df..4b566ac 100644 --- a/chapter15/async_wrapper/main_asgiref_sync_to_async.py +++ b/chapter15/async_wrapper/main_asgiref_sync_to_async.py @@ -1,18 +1,18 @@ import cProfile from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi.responses import PlainTextResponse, HTMLResponse from asgiref.sync import sync_to_async import requests + # 定义我们的APP服务对象 app = FastAPI() -def getdata(): - return requests.get('http://www.baidu.com').text - +def getdata(): + return requests.get("http://www.baidu.com").text def async_decorator_with_argument(time_to_eat): @@ -25,23 +25,20 @@ def actual_decorator(func): @wraps(func) async def wrapper(*args, **kwargs): - - - print(time_to_eat) print(args) print(kwargs) return await func(*args, **kwargs) - print("输出结果") return wrapper return actual_decorator + @app.get("/get/access_token") # @async_decorator_with_argument(time_to_eat='555555') -def access_token(request:Request,dsa:str): +def access_token(request: Request, dsa: str): pr = cProfile.Profile() pr.enable() # 开始收集性能分析数据 # asds= await sync_to_async(func=getdata)() @@ -56,6 +53,4 @@ def access_token(request:Request,dsa:str): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1',port=5667, reload=True) - - + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", port=5667, reload=True) diff --git a/chapter15/body/main_01.py b/chapter15/body/main_01.py index 382209d..11202f6 100644 --- a/chapter15/body/main_01.py +++ b/chapter15/body/main_01.py @@ -42,4 +42,4 @@ async def index(request: Request): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/body/main_02.py b/chapter15/body/main_02.py index a5c33bf..7c9d3a8 100644 --- a/chapter15/body/main_02.py +++ b/chapter15/body/main_02.py @@ -31,10 +31,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取:消费request.body()",_body) + print("Loger中间件解析读取:消费request.body()", _body) response = await call_next(request) return response + app.add_middleware(LogerMiddleware) @@ -45,12 +46,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/body/main_03.py b/chapter15/body/main_03.py index 9e3b7fb..86493a0 100644 --- a/chapter15/body/main_03.py +++ b/chapter15/body/main_03.py @@ -31,12 +31,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取11111111:消费request.body()",_body) + print("Loger中间件解析读取11111111:消费request.body()", _body) response = await call_next(request) return response - class LogerMiddleware2(BaseHTTPMiddleware): async def set_body(self, request): @@ -51,10 +50,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取22222222:消费request.body()",_body) + print("Loger中间件解析读取22222222:消费request.body()", _body) response = await call_next(request) return response + app.add_middleware(LogerMiddleware) app.add_middleware(LogerMiddleware2) @@ -66,12 +66,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/body/main_04.py b/chapter15/body/main_04.py index 330c301..b505a3c 100644 --- a/chapter15/body/main_04.py +++ b/chapter15/body/main_04.py @@ -20,9 +20,8 @@ class LogerMiddleware1: def __init__( - self, - app: ASGIApp, - + self, + app: ASGIApp, ) -> None: self.app = app @@ -45,9 +44,8 @@ async def receive(): class LogerMiddleware2: def __init__( - self, - app: ASGIApp, - + self, + app: ASGIApp, ) -> None: self.app = app @@ -57,6 +55,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: return # 接收一次 receive_ = await receive() + async def receive(): return receive_ @@ -71,6 +70,7 @@ async def receive(): app.add_middleware(LogerMiddleware1) app.add_middleware(LogerMiddleware2) + @app.get("/") async def index(request: Request): _body = await request.body() @@ -78,12 +78,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/cProfile/c_profile_text_run.py b/chapter15/cProfile/c_profile_text_run.py index 6e8e70d..d32c72d 100644 --- a/chapter15/cProfile/c_profile_text_run.py +++ b/chapter15/cProfile/c_profile_text_run.py @@ -10,7 +10,5 @@ def randomlist(n): return lists - - if __name__ == "__main__": - randomlist(20) \ No newline at end of file + randomlist(20) diff --git a/chapter15/cProfile/runtest_profile_stats_run.py b/chapter15/cProfile/runtest_profile_stats_run.py index ead0756..3e2df66 100644 --- a/chapter15/cProfile/runtest_profile_stats_run.py +++ b/chapter15/cProfile/runtest_profile_stats_run.py @@ -1,4 +1,5 @@ import pstats + p = pstats.Stats("runtest_profile.stats") p.sort_stats("cumulative") # 和显示明细一样 # p.print_stats() diff --git a/chapter15/contextvar_request/bind_.py b/chapter15/contextvar_request/bind_.py index d3d8f64..1aea75c 100644 --- a/chapter15/contextvar_request/bind_.py +++ b/chapter15/contextvar_request/bind_.py @@ -20,4 +20,4 @@ def __setitem__(self, index, value): def __delitem__(self, index): del contextvar.get()[index] - return ContextVarBind() \ No newline at end of file + return ContextVarBind() diff --git a/chapter15/contextvar_request/main_class.py b/chapter15/contextvar_request/main_class.py index e8f4ac9..b70ab09 100644 --- a/chapter15/contextvar_request/main_class.py +++ b/chapter15/contextvar_request/main_class.py @@ -19,20 +19,17 @@ async def add_process_time_header(request: Request, call_next): request_var.reset(token) - - -@app.post('/index') +@app.post("/index") async def index(): # 这里应该使用事务处理 print(request.headers) - return JSONResponse({ - "code": 200, - "msg": "成功" - }) + return JSONResponse({"code": 200, "msg": "成功"}) + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/contextvar_request/request.py b/chapter15/contextvar_request/request.py index 4762281..e854dc5 100644 --- a/chapter15/contextvar_request/request.py +++ b/chapter15/contextvar_request/request.py @@ -3,4 +3,4 @@ from chapter15.contextvar_request.bind_ import bind_contextvar request_var: ContextVar[Request] = ContextVar("request") -request:Request = bind_contextvar(request_var) \ No newline at end of file +request: Request = bind_contextvar(request_var) diff --git a/chapter15/depends/main_class.py b/chapter15/depends/main_class.py index a011a70..bf6a6bc 100644 --- a/chapter15/depends/main_class.py +++ b/chapter15/depends/main_class.py @@ -10,13 +10,16 @@ class AuthCheck: def __init__(self, role: str): self.role = role + @app.get("/auth_check") def auth_check(role: dict = Depends(AuthCheck)): return role + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/depends/main_class_call.py b/chapter15/depends/main_class_call.py index 7ff35dd..1064bf8 100644 --- a/chapter15/depends/main_class_call.py +++ b/chapter15/depends/main_class_call.py @@ -10,19 +10,24 @@ class AuthCheck: def __init__(self, role_name: str): self.role_name = role_name - def __call__(self,): - print("当前角色是:",self.role_name) - if self.role_name =='admin': + def __call__( + self, + ): + print("当前角色是:", self.role_name) + if self.role_name == "admin": return "管理员" return "普通用户" + @app.get("/auth_check") def auth_check(role: str = Depends(AuthCheck(role_name="admin"))): return role + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/depends/main_class_security_scopes.py b/chapter15/depends/main_class_security_scopes.py index 19c056b..2947089 100644 --- a/chapter15/depends/main_class_security_scopes.py +++ b/chapter15/depends/main_class_security_scopes.py @@ -22,4 +22,4 @@ def auth_check(role: str = Security(AuthCheck, scopes=["admin"])): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/depends/main_fun.py b/chapter15/depends/main_fun.py index 798a12a..71ad825 100644 --- a/chapter15/depends/main_fun.py +++ b/chapter15/depends/main_fun.py @@ -6,15 +6,19 @@ app = FastAPI() -def auth_check(role:str): +def auth_check(role: str): return role + @app.get("/auth_check") def auth_check(role: str = Depends(auth_check)): return role + + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/depends/main_fun_security_scopes.py b/chapter15/depends/main_fun_security_scopes.py index 554c051..827d2b3 100644 --- a/chapter15/depends/main_fun_security_scopes.py +++ b/chapter15/depends/main_fun_security_scopes.py @@ -7,7 +7,7 @@ def auth_check(security_scopes: SecurityScopes): print("传入的参数:", security_scopes.scopes) - if security_scopes.scopes[0] == 'admin': + if security_scopes.scopes[0] == "admin": return "管理者" return "普通用户" @@ -23,4 +23,4 @@ def auth_check(role: str = Security(auth_check, scopes=["admin"])): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/fastapi_cache/main.py b/chapter15/fastapi_cache/main.py index 123ef9e..55f852f 100644 --- a/chapter15/fastapi_cache/main.py +++ b/chapter15/fastapi_cache/main.py @@ -8,13 +8,16 @@ from fastapi_cache.decorator import cache from fastapi_cache.coder import JsonCoder from typing import Optional + app = FastAPI() @app.on_event("startup") async def startup(): # 开始初始化缓存对象 - redis = aioredis.from_url("redis://localhost", encoding="utf8", decode_responses=True) + redis = aioredis.from_url( + "redis://localhost", encoding="utf8", decode_responses=True + ) # 缓存库的插件实例化,传入的是要的是RedisBackend后端实例 FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache") @@ -22,26 +25,39 @@ async def startup(): @app.get("/cache1") @cache(expire=60) async def index(): - return dict(code=200,message="响应成功") + return dict(code=200, message="响应成功") + @app.get("/cache2") -@cache(namespace='test',expire=60) +@cache(namespace="test", expire=60) async def index(): - return JSONResponse(content={"code":200,"message":"设置命名空间"}) + return JSONResponse(content={"code": 200, "message": "设置命名空间"}) + @app.get("/cache_jsoncode") -@cache(expire=60,coder=JsonCoder) +@cache(expire=60, coder=JsonCoder) async def cache_jsoncode(): return dict(code=200, message="自定义编码器") + # 自定义生成缓存的KEY的方法 -def my_key_builder(func,namespace: Optional[str] = "",request: Request = None,response: Response = None,*args,**kwargs,): +def my_key_builder( + func, + namespace: Optional[str] = "", + request: Request = None, + response: Response = None, + *args, + **kwargs, +): prefix = FastAPICache.get_prefix() - cache_key = f"{prefix}:{namespace}:{func.__module__}:{func.__name__}:{args}:{kwargs}" + cache_key = ( + f"{prefix}:{namespace}:{func.__module__}:{func.__name__}:{args}:{kwargs}" + ) return cache_key + @app.get("/customer_key") -@cache(expire=60,coder=JsonCoder,key_builder=my_key_builder) +@cache(expire=60, coder=JsonCoder, key_builder=my_key_builder) async def index(): return dict(code=200, message="自定义生成缓存KEY示例") @@ -49,6 +65,7 @@ async def index(): if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/fastapi_cache/uu.py b/chapter15/fastapi_cache/uu.py index cce9207..7566d9e 100644 --- a/chapter15/fastapi_cache/uu.py +++ b/chapter15/fastapi_cache/uu.py @@ -1,17 +1,19 @@ -x=3 +x = 3 print(x) -y=2 -k=x+y +y = 2 +k = x + y print(k) -x=5 -y=7 -print(x*y) +x = 5 +y = 7 +print(x * y) -def jiafa(x,y): - return x+ y -print(jiafa(2,4)) +def jiafa(x, y): + return x + y -print(jiafa(2,4333)) +print(jiafa(2, 4)) + + +print(jiafa(2, 4333)) diff --git a/chapter15/model_sort/main_asyncer_syncify.py b/chapter15/model_sort/main_asyncer_syncify.py index 395043c..4628def 100644 --- a/chapter15/model_sort/main_asyncer_syncify.py +++ b/chapter15/model_sort/main_asyncer_syncify.py @@ -11,7 +11,9 @@ class Item(BaseModel): def __new__(cls, *args, **kwargs): instance = super().__new__(cls) # 对当前__fields__重新进行排序 - cls.__fields__ = {key: cls.__fields__[key] for key in sorted(cls.__fields__.keys())} + cls.__fields__ = { + key: cls.__fields__[key] for key in sorted(cls.__fields__.keys()) + } return instance desc: Optional[str] = None @@ -20,7 +22,7 @@ def __new__(cls, *args, **kwargs): aname: str -@app.post('/items/', response_model=Item) +@app.post("/items/", response_model=Item) async def getitem(item: Item): return item diff --git a/chapter15/plugins/base.py b/chapter15/plugins/base.py index 3a3b740..915ee87 100644 --- a/chapter15/plugins/base.py +++ b/chapter15/plugins/base.py @@ -10,27 +10,43 @@ class PluginBase(abc.ABC): - def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): + def __init__( + self, app: fastapi.FastAPI = None, config: pydantic.BaseSettings = None + ): if app is not None: self.init_app(app) @abc.abstractmethod - def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: - raise NotImplementedError('需要实现初始化') - + def init_app( + self, + app: fastapi.FastAPI, + config: pydantic.BaseSettings = None, + *args, + **kwargs + ) -> None: + raise NotImplementedError("需要实现初始化") class HookPluginClient(PluginBase): # 设置插件默认的参数信息 - def __init__(self, - on_before_request: typing.Sequence[typing.Callable] = None, - on_after_request: typing.Sequence[typing.Callable] = None, - on_teardown_appcontext: typing.Sequence[typing.Callable] = None, - *args, **kwargs): + def __init__( + self, + on_before_request: typing.Sequence[typing.Callable] = None, + on_after_request: typing.Sequence[typing.Callable] = None, + on_teardown_appcontext: typing.Sequence[typing.Callable] = None, + *args, + **kwargs + ): super().__init__(*args, **kwargs) - self.on_before_request = [] if on_before_request is None else list(on_before_request) - self.on_after_request = [] if on_after_request is None else list(on_after_request) - self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + self.on_before_request = ( + [] if on_before_request is None else list(on_before_request) + ) + self.on_after_request = ( + [] if on_after_request is None else list(on_after_request) + ) + self.on_teardown_appcontext = ( + [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + ) def init_app(self, app: FastAPI, *args, **kwargs): @app.middleware("http") @@ -83,4 +99,4 @@ async def teardown_appcontext(self, request, response) -> None: if asyncio.iscoroutinefunction(handler): await handler(request, response) else: - handler(request, response) \ No newline at end of file + handler(request, response) diff --git a/chapter15/plugins/main.py b/chapter15/plugins/main.py index b0a21c8..2e3af86 100644 --- a/chapter15/plugins/main.py +++ b/chapter15/plugins/main.py @@ -6,34 +6,40 @@ app = FastAPI() # 导入插件类 from plugins.request_hook import HookPluginClient -rehook:HookPluginClient = HookPluginClient() + +rehook: HookPluginClient = HookPluginClient() rehook.init_app(app) -@rehook.on_event(event_type='before_request') + +@rehook.on_event(event_type="before_request") def before_request(reqest): print("before_request", reqest) -@rehook.on_event(event_type='after_request') -def after_request(reqest,response): - print("after_request", reqest,response) +@rehook.on_event(event_type="after_request") +def after_request(reqest, response): + print("after_request", reqest, response) -@rehook.on_event(event_type='teardown_appcontext') +@rehook.on_event(event_type="teardown_appcontext") def teardown_appcontext(request, response): - print("teardown_appcontext", request,response) + print("teardown_appcontext", request, response) + class AuthCheck: def __init__(self, role: str): self.role = role + @app.get("/index") def index(): - return 'index' + return "index" + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter15/sentry/main.py b/chapter15/sentry/main.py index 6ac7108..803eab6 100644 --- a/chapter15/sentry/main.py +++ b/chapter15/sentry/main.py @@ -14,6 +14,7 @@ app = FastAPI() + @app.get("/sentry-debug") async def trigger_error(): division_by_zero = 1 / 0 @@ -25,4 +26,4 @@ async def trigger_error(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", reload=True) \ No newline at end of file + uvicorn.run(f"{app_modeel_name}:app", reload=True) diff --git a/chapter15/smtplib/main_aiosmtplib.py b/chapter15/smtplib/main_aiosmtplib.py index 07f2c93..cc46680 100644 --- a/chapter15/smtplib/main_aiosmtplib.py +++ b/chapter15/smtplib/main_aiosmtplib.py @@ -2,23 +2,26 @@ import asyncio import aiosmtplib + # email 用于构建邮件内容 from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -#构建邮件头 +# 构建邮件头 from email.header import Header + # 发信服务器 -smtp_server = 'smtp.qq.com' +smtp_server = "smtp.qq.com" # 发信方的信息:发信邮箱账号 -from_addr = '308711822@qq.com' +from_addr = "308711822@qq.com" # 发信方的信息:QQ 邮箱授权码 -password = 'xxxxxxxxxx' +password = "xxxxxxxxxx" + -async def send_email(send_to_addr:str,contest_msg:str): +async def send_email(send_to_addr: str, contest_msg: str): # 连接发信服务器 - server = aiosmtplib.SMTP(hostname=smtp_server, port=465,use_tls=True) + server = aiosmtplib.SMTP(hostname=smtp_server, port=465, use_tls=True) # 建立连接--qq邮箱服务和端口号 await server.connect() # 登入邮箱 @@ -26,31 +29,35 @@ async def send_email(send_to_addr:str,contest_msg:str): # 配置邮件正文内容 msg = MIMEMultipart() - msg['From'] = Header('小钟同学') # 设置来自于邮件的发送者信息 - msg['To'] = Header('其他人同学') # 设置来自于邮件的接收人信息 - msg['Subject'] = Header("用户注册通知", 'utf-8') # 设置邮件主题 + msg["From"] = Header("小钟同学") # 设置来自于邮件的发送者信息 + msg["To"] = Header("其他人同学") # 设置来自于邮件的接收人信息 + msg["Subject"] = Header("用户注册通知", "utf-8") # 设置邮件主题 # 邮件正文内容 - msg.attach(MIMEText(contest_msg, 'html', 'utf-8')) + msg.attach(MIMEText(contest_msg, "html", "utf-8")) # 构造附件1,传送文本附件 - file_name = 'test1.txt' - test_file_att = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file_att["Content-Type"] = 'application/octet-stream' + file_name = "test1.txt" + test_file_att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file_att["Content-Type"] = "application/octet-stream" test_file_att["Content-Disposition"] = f'attachment; filename="{file_name}"' msg.attach(test_file_att) # 构造附件1,传送文本附件 - file_name = 'test2.txt' - test_file = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file.add_header('Content-Type','application/octet-stream') - test_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', file_name)) + file_name = "test2.txt" + test_file = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file.add_header("Content-Type", "application/octet-stream") + test_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", file_name) + ) msg.attach(test_file) # 构造附件2,文件附件 - image_file_name = 'test.jpg' - image_file = MIMEImage(open(image_file_name, 'rb').read()) - image_file.add_header('Content-Type', 'application/octet-stream') - image_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', image_file_name)) + image_file_name = "test.jpg" + image_file = MIMEImage(open(image_file_name, "rb").read()) + image_file.add_header("Content-Type", "application/octet-stream") + image_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", image_file_name) + ) msg.attach(image_file) await server.sendmail(from_addr, send_to_addr, msg.as_string()) @@ -64,7 +71,9 @@ async def send_email(send_to_addr:str,contest_msg:str): """ -if __name__ == '__main__': +if __name__ == "__main__": loop = asyncio.get_event_loop() - loop.run_until_complete(send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg)) + loop.run_until_complete( + send_email(send_to_addr="3022600790@qq.com", contest_msg=html_msg) + ) # asyncio.run(send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg)) diff --git a/chapter15/smtplib/main_smtplib.py b/chapter15/smtplib/main_smtplib.py index d2b6eeb..49b6649 100644 --- a/chapter15/smtplib/main_smtplib.py +++ b/chapter15/smtplib/main_smtplib.py @@ -1,18 +1,22 @@ # smtplib 用于邮件的发信动作 import smtplib + # email 用于构建邮件内容 from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -#构建邮件头 + +# 构建邮件头 from email.header import Header + # 发信服务器 -smtp_server = 'smtp.qq.com' +smtp_server = "smtp.qq.com" # 发信方的信息:发信邮箱,QQ 邮箱授权码 -from_addr = '308711822@qq.com' -password = 'xxxxxxxxxxxxxx' +from_addr = "308711822@qq.com" +password = "xxxxxxxxxxxxxx" -def send_email(send_to_addr:str,contest_msg:str): + +def send_email(send_to_addr: str, contest_msg: str): # 连接发信服务器 server = smtplib.SMTP_SSL(smtp_server) # 建立连接--qq邮箱服务和端口号 @@ -22,31 +26,35 @@ def send_email(send_to_addr:str,contest_msg:str): # 配置邮件正文内容 msg = MIMEMultipart() - msg['From'] = Header('小钟同学') # 设置来自于邮件的发送者信息 - msg['To'] = Header('其他人同学') # 设置来自于邮件的接收人信息 - msg['Subject'] = Header("用户注册通知", 'utf-8') # 设置邮件主题 + msg["From"] = Header("小钟同学") # 设置来自于邮件的发送者信息 + msg["To"] = Header("其他人同学") # 设置来自于邮件的接收人信息 + msg["Subject"] = Header("用户注册通知", "utf-8") # 设置邮件主题 # 邮件正文内容 - msg.attach(MIMEText(contest_msg, 'html', 'utf-8')) + msg.attach(MIMEText(contest_msg, "html", "utf-8")) # 构造附件1,传送文本附件 - file_name = 'test1.txt' - test_file_att = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file_att["Content-Type"] = 'application/octet-stream' + file_name = "test1.txt" + test_file_att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file_att["Content-Type"] = "application/octet-stream" test_file_att["Content-Disposition"] = f'attachment; filename="{file_name}"' msg.attach(test_file_att) # 构造附件1,传送文本附件 - file_name = 'test2.txt' - test_file = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file.add_header('Content-Type','application/octet-stream') - test_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', file_name)) + file_name = "test2.txt" + test_file = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file.add_header("Content-Type", "application/octet-stream") + test_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", file_name) + ) msg.attach(test_file) # 构造附件2,文件附件 - image_file_name = 'test.jpg' - image_file = MIMEImage(open(image_file_name, 'rb').read()) - image_file.add_header('Content-Type', 'application/octet-stream') - image_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', image_file_name)) + image_file_name = "test.jpg" + image_file = MIMEImage(open(image_file_name, "rb").read()) + image_file.add_header("Content-Type", "application/octet-stream") + image_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", image_file_name) + ) msg.attach(image_file) server.sendmail(from_addr, send_to_addr, msg.as_string()) @@ -58,5 +66,4 @@ def send_email(send_to_addr:str,contest_msg:str):

您好,您申请的XXXX注册成功,请点击下面链接进行确认!

确认

""" -send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg) - +send_email(send_to_addr="3022600790@qq.com", contest_msg=html_msg) diff --git a/chapter16/Jaeger/test_jaeger_client/main.py b/chapter16/Jaeger/test_jaeger_client/main.py index aa342ce..afe8d36 100644 --- a/chapter16/Jaeger/test_jaeger_client/main.py +++ b/chapter16/Jaeger/test_jaeger_client/main.py @@ -5,26 +5,30 @@ def construct_span(tracer): # 定义span的名称为TestSpan - with tracer.start_span('TestSpan') as span: + with tracer.start_span("TestSpan") as span: # 设置这个span传递的日志信息 - span.log_kv({'event': '父Span', 'other': "我是第一个父的Span"}) + span.log_kv({"event": "父Span", "other": "我是第一个父的Span"}) time.sleep(1) # 定义AliyunTestSpan的子Span,类似第一个追踪的数据的子层级 - with tracer.start_span('TestSpan-ChildSpan-01', child_of=span) as child_span: + with tracer.start_span("TestSpan-ChildSpan-01", child_of=span) as child_span: time.sleep(2) # 设置父的span键值对日志信息 - span.log_kv({'event': '我是父Span--日志1'}) + span.log_kv({"event": "我是父Span--日志1"}) # 设置子child_span的日志 - child_span.log_kv({'event': '父Span--第一层子Span-01'}) - with tracer.start_span('TestSpan-ChildSpan-01', child_of=span) as child_span: + child_span.log_kv({"event": "父Span--第一层子Span-01"}) + with tracer.start_span("TestSpan-ChildSpan-01", child_of=span) as child_span: time.sleep(3) - span.log_kv({'event': '我是父Span--日志2'}) - child_span.log_kv({'event': '父Span--第一层子Span-02'}) + span.log_kv({"event": "我是父Span--日志2"}) + child_span.log_kv({"event": "父Span--第一层子Span-02"}) - with tracer.start_span('TestSpanC-hildSpan-01-01', child_of=child_span) as Span3_child_span: + with tracer.start_span( + "TestSpanC-hildSpan-01-01", child_of=child_span + ) as Span3_child_span: time.sleep(4) - span.log_kv({'event': '我是父Span--日志3'}) - Span3_child_span.log_kv({'event': '父Span--第一层子Span-的下一个子Span'}) + span.log_kv({"event": "我是父Span--日志3"}) + Span3_child_span.log_kv( + {"event": "父Span--第一层子Span-的下一个子Span"} + ) return span @@ -32,30 +36,30 @@ def construct_span(tracer): if __name__ == "__main__": # 定义日志输出的登记 log_level = logging.DEBUG - logging.getLogger('').handlers = [] + logging.getLogger("").handlers = [] # 配置日志默认输出格式 - logging.basicConfig(format='%(asctime)s %(message)s', level=log_level) + logging.basicConfig(format="%(asctime)s %(message)s", level=log_level) # Jaeger配置信息 config = Config( # 服务信息配置 config={ # sampler 采样 - 'sampler': { - 'type': 'const', # 采样类型 - 'param': 1, # 采样开关 1:开启全部采样 0:关闭全部 + "sampler": { + "type": "const", # 采样类型 + "param": 1, # 采样开关 1:开启全部采样 0:关闭全部 }, # 配置链接到我们的本地的agent,通过agent来上报 - 'local_agent': { + "local_agent": { # 注意这里是指定了JaegerAgent的host和port。 # 根据官方建议为了保证数据可靠性,JaegerClient和JaegerAgent运行在同一台主机内,因此reporting_host填写为127.0.0.1。 - 'reporting_host': '192.168.126.130', - 'reporting_port': 6831, + "reporting_host": "192.168.126.130", + "reporting_port": 6831, }, - 'logging': True, + "logging": True, }, # 这里填写应用名称---服务的名称 service_name="MyFirstSpan", - validate=True + validate=True, ) # this call also sets opentracing.tracer diff --git a/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py b/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py index be84349..c8b27c8 100644 --- a/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py +++ b/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/__init__.py @@ -1,4 +1,3 @@ - from typing import List, Any from fastapi import Request from jaeger_client import Config @@ -9,18 +8,16 @@ from fastapi import FastAPI - - class OpentracingJaegerMiddleware(BaseHTTPMiddleware): - def __init__(self,fastapiapp: FastAPI,*args,**kwargs) -> None: - super().__init__(*args,**kwargs) + def __init__(self, fastapiapp: FastAPI, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) self.fastapiapp = fastapiapp - self.fastapiapp.add_event_handler('startup', self.setup_opentracing) + self.fastapiapp.add_event_handler("startup", self.setup_opentracing) def setup_opentracing(self): # 配置连接信息 - jaeger_host = '192.168.126.130' + jaeger_host = "192.168.126.130" jaeger_port = 6831 service_name = "测试2" trace_id_header = "X-TRACE-ID" @@ -31,28 +28,28 @@ def setup_opentracing(self): config={ "local_agent": { "reporting_host": jaeger_host, - "reporting_port": jaeger_port + "reporting_port": jaeger_port, }, "sampler": { "type": jaeger_sampler_type, "param": jaeger_sampler_rate, }, - "trace_id_header": trace_id_header + "trace_id_header": trace_id_header, }, service_name=service_name, validate=True, - scope_manager=AsyncioScopeManager() + scope_manager=AsyncioScopeManager(), ) self.fastapiapp.state.tracer = _tracer_config.initialize_tracer() - - async def dispatch(self, request: Request, call_next: Any) -> Response: # 获取tracer对象 tracer = request.app.state.tracer # 开始解析上下文(Extract函数): # 该函数主要用于在跨服务进程中,进行解析还原上一个传入Span 信息,通常是通过获取请求的headers进行参数信息提取; - span_context = tracer.extract(format=Format.HTTP_HEADERS, carrier=request.headers) + span_context = tracer.extract( + format=Format.HTTP_HEADERS, carrier=request.headers + ) # 开始创建span对象通过span_context,来决定是否存在层级span span = tracer.start_span( operation_name=f"{request.method} {request.url.path}", @@ -71,15 +68,12 @@ async def dispatch(self, request: Request, call_next: Any) -> Response: # 设置client请求来源端口的标签 span.set_tag(tags.PEER_PORT, request.client.port or "") # #Component(字符串)ia模块、库或正在生成跨区的包。 - span.set_tag(tags.COMPONENT, 'Fastapi') + span.set_tag(tags.COMPONENT, "Fastapi") # 标记表示RPC或其他远程调用的服务器端的范围 span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_SERVER) # (字符串)是请求的HTTP方法。 span.set_tag(tags.HTTP_METHOD, request.method) - - - # Scope 对象 主要是管理Active Span的容器 # Scope 代表着当前活跃的Span; 是对当前活跃Span的一个抽象 # ScopeManager 包含一个 Scope, Scope 又包含了 当前Span @@ -99,5 +93,3 @@ async def dispatch(self, request: Request, call_next: Any) -> Response: # inject之后,实际 headers = {'uber-trace-id': '6997ed0a6a74f050:bf49be2de63d86e7:e02975aab05fd358:1'} print(headers) return response - - diff --git a/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/main.py b/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/main.py index afd7e50..b6ffb19 100644 --- a/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/main.py +++ b/chapter16/Jaeger/test_jaeger_client_fastapi/middeware/main.py @@ -8,23 +8,28 @@ @app.get("/tracing") -def tracing(request: Request, x_trace_id: Optional[str] = Header(None, convert_underscores=True)): +def tracing( + request: Request, x_trace_id: Optional[str] = Header(None, convert_underscores=True) +): # 拿到当前生效的tracer tracer = request.app.state.tracer # 判断是否存在对应的上一个层级的span span = request.state.opentracing_span # 创建新的span - with tracer.start_span('new—span-test', child_of=span) as child_span_1: - span.log_kv({'event': '父类的span事件信息1'}) - span.log_kv({'event': '父类的span事件信息2', - 'request.args': request.query_params, }) + with tracer.start_span("new—span-test", child_of=span) as child_span_1: + span.log_kv({"event": "父类的span事件信息1"}) + span.log_kv( + { + "event": "父类的span事件信息2", + "request.args": request.query_params, + } + ) # child_span_1.log_kv({'event': 'child_span-down below'}) # with tracer.start_span('new—span-test-childspan', child_of=child_span_1) as child_span_2: # child_span_2.log_kv({'event': 'new—span-test-childspan-childspan'}) - return "ok" @@ -34,4 +39,4 @@ def tracing(request: Request, x_trace_id: Optional[str] = Header(None, convert_u app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/async_sync_change/main_asgiref_async_to_sync.py b/chapter16/async_sync_change/main_asgiref_async_to_sync.py index a71535e..c323aac 100644 --- a/chapter16/async_sync_change/main_asgiref_async_to_sync.py +++ b/chapter16/async_sync_change/main_asgiref_async_to_sync.py @@ -1,6 +1,6 @@ from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request from fastapi.responses import PlainTextResponse from fastapi.params import Body @@ -9,14 +9,16 @@ @app.post("/get/access_token") -def access_token(request:Request,name=Body(...)): +def access_token(request: Request, name=Body(...)): # print(reques.body()) from asgiref.sync import async_to_sync + body = async_to_sync(request.body)() print(body) - return PlainTextResponse(body.decode(encoding='utf-8')) + return PlainTextResponse(body.decode(encoding="utf-8")) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) \ No newline at end of file + + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter16/async_sync_change/main_asgiref_sync_to_async.py b/chapter16/async_sync_change/main_asgiref_sync_to_async.py index 4bab1e5..13f4d1c 100644 --- a/chapter16/async_sync_change/main_asgiref_sync_to_async.py +++ b/chapter16/async_sync_change/main_asgiref_sync_to_async.py @@ -1,22 +1,22 @@ from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi.responses import PlainTextResponse, HTMLResponse from asgiref.sync import sync_to_async import requests + # 定义我们的APP服务对象 app = FastAPI() -def getdata(): - return requests.get('http://www.baidu.com').text - +def getdata(): + return requests.get("http://www.baidu.com").text @app.get("/get/access_token") async def access_token(): - asds= await sync_to_async(func=getdata)() + asds = await sync_to_async(func=getdata)() return HTMLResponse(asds) @@ -26,6 +26,4 @@ async def access_token(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) - - + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/async_sync_change/main_asyncer_asyncify.py b/chapter16/async_sync_change/main_asyncer_asyncify.py index 44d1cf9..81e3d0c 100644 --- a/chapter16/async_sync_change/main_asyncer_asyncify.py +++ b/chapter16/async_sync_change/main_asyncer_asyncify.py @@ -1,19 +1,23 @@ -from fastapi import FastAPI,Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi import FastAPI, Request +from fastapi.responses import PlainTextResponse, HTMLResponse from asyncer import asyncify import requests + # 定义我们的APP服务对象 app = FastAPI() + def do_sync_work(name): - return requests.get(f'http://www.baidu.com?name={name}').text + return requests.get(f"http://www.baidu.com?name={name}").text + @app.get("/get/access_token") -async def access_token(request:Request): +async def access_token(request: Request): message = await asyncify(do_sync_work)(name="World") return HTMLResponse(message) -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) + + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter16/async_sync_change/main_asyncer_syncify.py b/chapter16/async_sync_change/main_asyncer_syncify.py index 1cd5b55..53bb120 100644 --- a/chapter16/async_sync_change/main_asyncer_syncify.py +++ b/chapter16/async_sync_change/main_asyncer_syncify.py @@ -1,18 +1,20 @@ -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request from fastapi.responses import PlainTextResponse from fastapi.params import Body -from fastapi.background import BackgroundTasks -from asyncer import asyncify,syncify +from fastapi.background import BackgroundTasks +from asyncer import asyncify, syncify app = FastAPI() + @app.post("/get/access_token") -def access_token(request:Request,name=Body(...)): +def access_token(request: Request, name=Body(...)): body = syncify(request.body)() print(body) - return PlainTextResponse(body.decode(encoding='utf-8')) + return PlainTextResponse(body.decode(encoding="utf-8")) + -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn - uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) + uvicorn.run("main:app", host="127.0.0.1", port=8100, debug=True, reload=True) diff --git a/chapter16/async_wrapper/main_asgiref_sync_to_async.py b/chapter16/async_wrapper/main_asgiref_sync_to_async.py index e9dc0df..4b566ac 100644 --- a/chapter16/async_wrapper/main_asgiref_sync_to_async.py +++ b/chapter16/async_wrapper/main_asgiref_sync_to_async.py @@ -1,18 +1,18 @@ import cProfile from functools import wraps -from fastapi import FastAPI,Request +from fastapi import FastAPI, Request -from fastapi.responses import PlainTextResponse,HTMLResponse +from fastapi.responses import PlainTextResponse, HTMLResponse from asgiref.sync import sync_to_async import requests + # 定义我们的APP服务对象 app = FastAPI() -def getdata(): - return requests.get('http://www.baidu.com').text - +def getdata(): + return requests.get("http://www.baidu.com").text def async_decorator_with_argument(time_to_eat): @@ -25,23 +25,20 @@ def actual_decorator(func): @wraps(func) async def wrapper(*args, **kwargs): - - - print(time_to_eat) print(args) print(kwargs) return await func(*args, **kwargs) - print("输出结果") return wrapper return actual_decorator + @app.get("/get/access_token") # @async_decorator_with_argument(time_to_eat='555555') -def access_token(request:Request,dsa:str): +def access_token(request: Request, dsa: str): pr = cProfile.Profile() pr.enable() # 开始收集性能分析数据 # asds= await sync_to_async(func=getdata)() @@ -56,6 +53,4 @@ def access_token(request:Request,dsa:str): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1',port=5667, reload=True) - - + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", port=5667, reload=True) diff --git a/chapter16/body/main_01.py b/chapter16/body/main_01.py index 382209d..11202f6 100644 --- a/chapter16/body/main_01.py +++ b/chapter16/body/main_01.py @@ -42,4 +42,4 @@ async def index(request: Request): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/body/main_02.py b/chapter16/body/main_02.py index a5c33bf..7c9d3a8 100644 --- a/chapter16/body/main_02.py +++ b/chapter16/body/main_02.py @@ -31,10 +31,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取:消费request.body()",_body) + print("Loger中间件解析读取:消费request.body()", _body) response = await call_next(request) return response + app.add_middleware(LogerMiddleware) @@ -45,12 +46,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/body/main_03.py b/chapter16/body/main_03.py index 9e3b7fb..86493a0 100644 --- a/chapter16/body/main_03.py +++ b/chapter16/body/main_03.py @@ -31,12 +31,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取11111111:消费request.body()",_body) + print("Loger中间件解析读取11111111:消费request.body()", _body) response = await call_next(request) return response - class LogerMiddleware2(BaseHTTPMiddleware): async def set_body(self, request): @@ -51,10 +50,11 @@ async def dispatch(self, request: Request, call_next): await self.set_body(request) # 需要在日志中间件里读取body数据 _body = await request.body() - print("Loger中间件解析读取22222222:消费request.body()",_body) + print("Loger中间件解析读取22222222:消费request.body()", _body) response = await call_next(request) return response + app.add_middleware(LogerMiddleware) app.add_middleware(LogerMiddleware2) @@ -66,12 +66,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/body/main_04.py b/chapter16/body/main_04.py index 330c301..b505a3c 100644 --- a/chapter16/body/main_04.py +++ b/chapter16/body/main_04.py @@ -20,9 +20,8 @@ class LogerMiddleware1: def __init__( - self, - app: ASGIApp, - + self, + app: ASGIApp, ) -> None: self.app = app @@ -45,9 +44,8 @@ async def receive(): class LogerMiddleware2: def __init__( - self, - app: ASGIApp, - + self, + app: ASGIApp, ) -> None: self.app = app @@ -57,6 +55,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: return # 接收一次 receive_ = await receive() + async def receive(): return receive_ @@ -71,6 +70,7 @@ async def receive(): app.add_middleware(LogerMiddleware1) app.add_middleware(LogerMiddleware2) + @app.get("/") async def index(request: Request): _body = await request.body() @@ -78,12 +78,10 @@ async def index(request: Request): return PlainTextResponse("消费request.body()!") - - if __name__ == "__main__": import uvicorn import os app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/contextvar_request/bind_.py b/chapter16/contextvar_request/bind_.py index d3d8f64..1aea75c 100644 --- a/chapter16/contextvar_request/bind_.py +++ b/chapter16/contextvar_request/bind_.py @@ -20,4 +20,4 @@ def __setitem__(self, index, value): def __delitem__(self, index): del contextvar.get()[index] - return ContextVarBind() \ No newline at end of file + return ContextVarBind() diff --git a/chapter16/contextvar_request/main_class.py b/chapter16/contextvar_request/main_class.py index e8f4ac9..b70ab09 100644 --- a/chapter16/contextvar_request/main_class.py +++ b/chapter16/contextvar_request/main_class.py @@ -19,20 +19,17 @@ async def add_process_time_header(request: Request, call_next): request_var.reset(token) - - -@app.post('/index') +@app.post("/index") async def index(): # 这里应该使用事务处理 print(request.headers) - return JSONResponse({ - "code": 200, - "msg": "成功" - }) + return JSONResponse({"code": 200, "msg": "成功"}) + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/contextvar_request/request.py b/chapter16/contextvar_request/request.py index 4762281..e854dc5 100644 --- a/chapter16/contextvar_request/request.py +++ b/chapter16/contextvar_request/request.py @@ -3,4 +3,4 @@ from chapter15.contextvar_request.bind_ import bind_contextvar request_var: ContextVar[Request] = ContextVar("request") -request:Request = bind_contextvar(request_var) \ No newline at end of file +request: Request = bind_contextvar(request_var) diff --git a/chapter16/depends/main_class.py b/chapter16/depends/main_class.py index a011a70..bf6a6bc 100644 --- a/chapter16/depends/main_class.py +++ b/chapter16/depends/main_class.py @@ -10,13 +10,16 @@ class AuthCheck: def __init__(self, role: str): self.role = role + @app.get("/auth_check") def auth_check(role: dict = Depends(AuthCheck)): return role + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/depends/main_class_call.py b/chapter16/depends/main_class_call.py index 7ff35dd..1064bf8 100644 --- a/chapter16/depends/main_class_call.py +++ b/chapter16/depends/main_class_call.py @@ -10,19 +10,24 @@ class AuthCheck: def __init__(self, role_name: str): self.role_name = role_name - def __call__(self,): - print("当前角色是:",self.role_name) - if self.role_name =='admin': + def __call__( + self, + ): + print("当前角色是:", self.role_name) + if self.role_name == "admin": return "管理员" return "普通用户" + @app.get("/auth_check") def auth_check(role: str = Depends(AuthCheck(role_name="admin"))): return role + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/depends/main_class_security_scopes.py b/chapter16/depends/main_class_security_scopes.py index 19c056b..2947089 100644 --- a/chapter16/depends/main_class_security_scopes.py +++ b/chapter16/depends/main_class_security_scopes.py @@ -22,4 +22,4 @@ def auth_check(role: str = Security(AuthCheck, scopes=["admin"])): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/depends/main_fun.py b/chapter16/depends/main_fun.py index 798a12a..71ad825 100644 --- a/chapter16/depends/main_fun.py +++ b/chapter16/depends/main_fun.py @@ -6,15 +6,19 @@ app = FastAPI() -def auth_check(role:str): +def auth_check(role: str): return role + @app.get("/auth_check") def auth_check(role: str = Depends(auth_check)): return role + + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/depends/main_fun_security_scopes.py b/chapter16/depends/main_fun_security_scopes.py index 554c051..827d2b3 100644 --- a/chapter16/depends/main_fun_security_scopes.py +++ b/chapter16/depends/main_fun_security_scopes.py @@ -7,7 +7,7 @@ def auth_check(security_scopes: SecurityScopes): print("传入的参数:", security_scopes.scopes) - if security_scopes.scopes[0] == 'admin': + if security_scopes.scopes[0] == "admin": return "管理者" return "普通用户" @@ -23,4 +23,4 @@ def auth_check(role: str = Security(auth_check, scopes=["admin"])): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/model_sort/main_asyncer_syncify.py b/chapter16/model_sort/main_asyncer_syncify.py index 395043c..4628def 100644 --- a/chapter16/model_sort/main_asyncer_syncify.py +++ b/chapter16/model_sort/main_asyncer_syncify.py @@ -11,7 +11,9 @@ class Item(BaseModel): def __new__(cls, *args, **kwargs): instance = super().__new__(cls) # 对当前__fields__重新进行排序 - cls.__fields__ = {key: cls.__fields__[key] for key in sorted(cls.__fields__.keys())} + cls.__fields__ = { + key: cls.__fields__[key] for key in sorted(cls.__fields__.keys()) + } return instance desc: Optional[str] = None @@ -20,7 +22,7 @@ def __new__(cls, *args, **kwargs): aname: str -@app.post('/items/', response_model=Item) +@app.post("/items/", response_model=Item) async def getitem(item: Item): return item diff --git a/chapter16/plugins/base.py b/chapter16/plugins/base.py index 3a3b740..915ee87 100644 --- a/chapter16/plugins/base.py +++ b/chapter16/plugins/base.py @@ -10,27 +10,43 @@ class PluginBase(abc.ABC): - def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): + def __init__( + self, app: fastapi.FastAPI = None, config: pydantic.BaseSettings = None + ): if app is not None: self.init_app(app) @abc.abstractmethod - def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: - raise NotImplementedError('需要实现初始化') - + def init_app( + self, + app: fastapi.FastAPI, + config: pydantic.BaseSettings = None, + *args, + **kwargs + ) -> None: + raise NotImplementedError("需要实现初始化") class HookPluginClient(PluginBase): # 设置插件默认的参数信息 - def __init__(self, - on_before_request: typing.Sequence[typing.Callable] = None, - on_after_request: typing.Sequence[typing.Callable] = None, - on_teardown_appcontext: typing.Sequence[typing.Callable] = None, - *args, **kwargs): + def __init__( + self, + on_before_request: typing.Sequence[typing.Callable] = None, + on_after_request: typing.Sequence[typing.Callable] = None, + on_teardown_appcontext: typing.Sequence[typing.Callable] = None, + *args, + **kwargs + ): super().__init__(*args, **kwargs) - self.on_before_request = [] if on_before_request is None else list(on_before_request) - self.on_after_request = [] if on_after_request is None else list(on_after_request) - self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + self.on_before_request = ( + [] if on_before_request is None else list(on_before_request) + ) + self.on_after_request = ( + [] if on_after_request is None else list(on_after_request) + ) + self.on_teardown_appcontext = ( + [] if on_teardown_appcontext is None else list(on_teardown_appcontext) + ) def init_app(self, app: FastAPI, *args, **kwargs): @app.middleware("http") @@ -83,4 +99,4 @@ async def teardown_appcontext(self, request, response) -> None: if asyncio.iscoroutinefunction(handler): await handler(request, response) else: - handler(request, response) \ No newline at end of file + handler(request, response) diff --git a/chapter16/plugins/main.py b/chapter16/plugins/main.py index b0a21c8..2e3af86 100644 --- a/chapter16/plugins/main.py +++ b/chapter16/plugins/main.py @@ -6,34 +6,40 @@ app = FastAPI() # 导入插件类 from plugins.request_hook import HookPluginClient -rehook:HookPluginClient = HookPluginClient() + +rehook: HookPluginClient = HookPluginClient() rehook.init_app(app) -@rehook.on_event(event_type='before_request') + +@rehook.on_event(event_type="before_request") def before_request(reqest): print("before_request", reqest) -@rehook.on_event(event_type='after_request') -def after_request(reqest,response): - print("after_request", reqest,response) +@rehook.on_event(event_type="after_request") +def after_request(reqest, response): + print("after_request", reqest, response) -@rehook.on_event(event_type='teardown_appcontext') +@rehook.on_event(event_type="teardown_appcontext") def teardown_appcontext(request, response): - print("teardown_appcontext", request,response) + print("teardown_appcontext", request, response) + class AuthCheck: def __init__(self, role: str): self.role = role + @app.get("/index") def index(): - return 'index' + return "index" + if __name__ == "__main__": import uvicorn import os + app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) + uvicorn.run(f"{app_modeel_name}:app", host="127.0.0.1", reload=True) diff --git a/chapter16/sentry/main.py b/chapter16/sentry/main.py index 6ac7108..803eab6 100644 --- a/chapter16/sentry/main.py +++ b/chapter16/sentry/main.py @@ -14,6 +14,7 @@ app = FastAPI() + @app.get("/sentry-debug") async def trigger_error(): division_by_zero = 1 / 0 @@ -25,4 +26,4 @@ async def trigger_error(): app_modeel_name = os.path.basename(__file__).replace(".py", "") print(app_modeel_name) - uvicorn.run(f"{app_modeel_name}:app", reload=True) \ No newline at end of file + uvicorn.run(f"{app_modeel_name}:app", reload=True) diff --git a/chapter16/smtplib/aaaa.py b/chapter16/smtplib/aaaa.py index 945b3c0..4520f80 100644 --- a/chapter16/smtplib/aaaa.py +++ b/chapter16/smtplib/aaaa.py @@ -1,19 +1,21 @@ # smtplib 用于邮件的发信动作 import smtplib + # email 用于构建邮件内容 from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart + # 构建邮件头 from email.header import Header # 发信方的信息:发信邮箱,QQ 邮箱授权码 -from_addr = '@qq.com' -password = '****' +from_addr = "@qq.com" +password = "****" # 收信方邮箱 -to_addr = 'xxxxx@qq.com' +to_addr = "xxxxx@qq.com" # 发信服务器 -smtp_server = 'smtp.qq.com' +smtp_server = "smtp.qq.com" html_msg = """

Python 邮件发送HTML格式文件测试...

@@ -23,30 +25,30 @@ # 创建一个带附件的实例msg msg = MIMEMultipart() -msg['From'] = Header('张三') # 发送者 -msg['To'] = Header('李四') # 接收者 -subject = 'Python SMTP 邮件测试' -msg['Subject'] = Header(subject, 'utf-8') # 邮件主题 +msg["From"] = Header("张三") # 发送者 +msg["To"] = Header("李四") # 接收者 +subject = "Python SMTP 邮件测试" +msg["Subject"] = Header(subject, "utf-8") # 邮件主题 # 邮件正文内容 -msg.attach(MIMEText(html_msg, 'html', 'utf-8')) +msg.attach(MIMEText(html_msg, "html", "utf-8")) # 构造附件1,传送当前目录下的 test1.txt 文件 -att1 = MIMEText(open('test1.txt', 'rb').read(), 'base64', 'utf-8') -att1["Content-Type"] = 'application/octet-stream' +att1 = MIMEText(open("test1.txt", "rb").read(), "base64", "utf-8") +att1["Content-Type"] = "application/octet-stream" # 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att1["Content-Disposition"] = 'attachment; filename="test1.txt"' msg.attach(att1) # 构造附件2,传送当前目录下的 test2.txt 文件 -att2 = MIMEText(open('test2.txt', 'rb').read(), 'base64', 'utf-8') -att2["Content-Type"] = 'application/octet-stream' +att2 = MIMEText(open("test2.txt", "rb").read(), "base64", "utf-8") +att2["Content-Type"] = "application/octet-stream" att2["Content-Disposition"] = 'attachment; filename="test2.txt"' msg.attach(att2) smtpobj = None try: smtpobj = smtplib.SMTP_SSL(smtp_server) - smtpobj.connect(smtp_server, 465) # 建立连接--qq邮箱服务和端口号 - smtpobj.login(from_addr, password) # 登录--发送者账号和口令 + smtpobj.connect(smtp_server, 465) # 建立连接--qq邮箱服务和端口号 + smtpobj.login(from_addr, password) # 登录--发送者账号和口令 smtpobj.sendmail(from_addr, to_addr, msg.as_string()) print("邮件发送成功") except smtplib.SMTPException: diff --git a/chapter16/smtplib/main_aiosmtplib.py b/chapter16/smtplib/main_aiosmtplib.py index 7d64723..28772e5 100644 --- a/chapter16/smtplib/main_aiosmtplib.py +++ b/chapter16/smtplib/main_aiosmtplib.py @@ -2,23 +2,26 @@ import asyncio import aiosmtplib + # email 用于构建邮件内容 from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -#构建邮件头 +# 构建邮件头 from email.header import Header + # 发信服务器 -smtp_server = 'smtp.qq.com' +smtp_server = "smtp.qq.com" # 发信方的信息:发信邮箱账号 -from_addr = '308711822@qq.com' +from_addr = "308711822@qq.com" # 发信方的信息:QQ 邮箱授权码 -password = 'zbpqbvcgimmrbjib' +password = "zbpqbvcgimmrbjib" + -async def send_email(send_to_addr:str,contest_msg:str): +async def send_email(send_to_addr: str, contest_msg: str): # 连接发信服务器 - server = aiosmtplib.SMTP(hostname=smtp_server, port=465,use_tls=True) + server = aiosmtplib.SMTP(hostname=smtp_server, port=465, use_tls=True) # 建立连接--qq邮箱服务和端口号 await server.connect() # 登入邮箱 @@ -26,31 +29,35 @@ async def send_email(send_to_addr:str,contest_msg:str): # 配置邮件正文内容 msg = MIMEMultipart() - msg['From'] = Header('小钟同学') # 设置来自于邮件的发送者信息 - msg['To'] = Header('其他人同学') # 设置来自于邮件的接收人信息 - msg['Subject'] = Header("用户注册通知", 'utf-8') # 设置邮件主题 + msg["From"] = Header("小钟同学") # 设置来自于邮件的发送者信息 + msg["To"] = Header("其他人同学") # 设置来自于邮件的接收人信息 + msg["Subject"] = Header("用户注册通知", "utf-8") # 设置邮件主题 # 邮件正文内容 - msg.attach(MIMEText(contest_msg, 'html', 'utf-8')) + msg.attach(MIMEText(contest_msg, "html", "utf-8")) # 构造附件1,传送文本附件 - file_name = 'test1.txt' - test_file_att = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file_att["Content-Type"] = 'application/octet-stream' + file_name = "test1.txt" + test_file_att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file_att["Content-Type"] = "application/octet-stream" test_file_att["Content-Disposition"] = f'attachment; filename="{file_name}"' msg.attach(test_file_att) # 构造附件1,传送文本附件 - file_name = 'test2.txt' - test_file = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file.add_header('Content-Type','application/octet-stream') - test_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', file_name)) + file_name = "test2.txt" + test_file = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file.add_header("Content-Type", "application/octet-stream") + test_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", file_name) + ) msg.attach(test_file) # 构造附件2,文件附件 - image_file_name = 'test.jpg' - image_file = MIMEImage(open(image_file_name, 'rb').read()) - image_file.add_header('Content-Type', 'application/octet-stream') - image_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', image_file_name)) + image_file_name = "test.jpg" + image_file = MIMEImage(open(image_file_name, "rb").read()) + image_file.add_header("Content-Type", "application/octet-stream") + image_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", image_file_name) + ) msg.attach(image_file) await server.sendmail(from_addr, send_to_addr, msg.as_string()) @@ -64,7 +71,9 @@ async def send_email(send_to_addr:str,contest_msg:str): """ -if __name__ == '__main__': +if __name__ == "__main__": loop = asyncio.get_event_loop() - loop.run_until_complete(send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg)) + loop.run_until_complete( + send_email(send_to_addr="3022600790@qq.com", contest_msg=html_msg) + ) # asyncio.run(send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg)) diff --git a/chapter16/smtplib/main_smtplib.py b/chapter16/smtplib/main_smtplib.py index f4a07cd..ed6fec3 100644 --- a/chapter16/smtplib/main_smtplib.py +++ b/chapter16/smtplib/main_smtplib.py @@ -1,18 +1,22 @@ # smtplib 用于邮件的发信动作 import smtplib + # email 用于构建邮件内容 from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -#构建邮件头 + +# 构建邮件头 from email.header import Header + # 发信服务器 -smtp_server = 'smtp.qq.com' +smtp_server = "smtp.qq.com" # 发信方的信息:发信邮箱,QQ 邮箱授权码 -from_addr = '308711822@qq.com' -password = 'zbpqbvcgimmrbjib' +from_addr = "308711822@qq.com" +password = "zbpqbvcgimmrbjib" -def send_email(send_to_addr:str,contest_msg:str): + +def send_email(send_to_addr: str, contest_msg: str): # 连接发信服务器 server = smtplib.SMTP_SSL(smtp_server) # 建立连接--qq邮箱服务和端口号 @@ -22,31 +26,35 @@ def send_email(send_to_addr:str,contest_msg:str): # 配置邮件正文内容 msg = MIMEMultipart() - msg['From'] = Header('小钟同学') # 设置来自于邮件的发送者信息 - msg['To'] = Header('其他人同学') # 设置来自于邮件的接收人信息 - msg['Subject'] = Header("用户注册通知", 'utf-8') # 设置邮件主题 + msg["From"] = Header("小钟同学") # 设置来自于邮件的发送者信息 + msg["To"] = Header("其他人同学") # 设置来自于邮件的接收人信息 + msg["Subject"] = Header("用户注册通知", "utf-8") # 设置邮件主题 # 邮件正文内容 - msg.attach(MIMEText(contest_msg, 'html', 'utf-8')) + msg.attach(MIMEText(contest_msg, "html", "utf-8")) # 构造附件1,传送文本附件 - file_name = 'test1.txt' - test_file_att = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file_att["Content-Type"] = 'application/octet-stream' + file_name = "test1.txt" + test_file_att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file_att["Content-Type"] = "application/octet-stream" test_file_att["Content-Disposition"] = f'attachment; filename="{file_name}"' msg.attach(test_file_att) # 构造附件1,传送文本附件 - file_name = 'test2.txt' - test_file = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') - test_file.add_header('Content-Type','application/octet-stream') - test_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', file_name)) + file_name = "test2.txt" + test_file = MIMEText(open(file_name, "rb").read(), "base64", "utf-8") + test_file.add_header("Content-Type", "application/octet-stream") + test_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", file_name) + ) msg.attach(test_file) # 构造附件2,文件附件 - image_file_name = 'test.jpg' - image_file = MIMEImage(open(image_file_name, 'rb').read()) - image_file.add_header('Content-Type', 'application/octet-stream') - image_file.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', image_file_name)) + image_file_name = "test.jpg" + image_file = MIMEImage(open(image_file_name, "rb").read()) + image_file.add_header("Content-Type", "application/octet-stream") + image_file.add_header( + "Content-Disposition", "attachment", filename=("utf-8", "", image_file_name) + ) msg.attach(image_file) server.sendmail(from_addr, send_to_addr, msg.as_string()) @@ -58,5 +66,4 @@ def send_email(send_to_addr:str,contest_msg:str):

您好,您申请的XXXX注册成功,请点击下面链接进行确认!

确认

""" -send_email(send_to_addr='3022600790@qq.com', contest_msg=html_msg) - +send_email(send_to_addr="3022600790@qq.com", contest_msg=html_msg)