Skip to content

Commit 30d2aff

Browse files
committed
Fix
1 parent 60af125 commit 30d2aff

6 files changed

Lines changed: 577 additions & 387 deletions

File tree

examples/flask-echo/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def callback():
7070
continue
7171
if not isinstance(event.message, TextMessageContent):
7272
continue
73-
line_bot_api.reply_message_with_http_info(
73+
line_bot_api.reply_message(
7474
ReplyMessageRequest(
7575
reply_token=event.reply_token,
7676
messages=[TextMessage(text=event.message.text)]

examples/flask-echo/app_with_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def callback():
6969

7070
@handler.add(MessageEvent, message=TextMessageContent)
7171
def message_text(event):
72-
line_bot_api.reply_message_with_http_info(
72+
line_bot_api.reply_message(
7373
ReplyMessageRequest(
7474
reply_token=event.reply_token,
7575
messages=[TextMessage(text=event.message.text)]

linebot/v3/async_line_bot_client.py

Lines changed: 221 additions & 196 deletions
Large diffs are not rendered by default.

linebot/v3/line_bot_client.py

Lines changed: 209 additions & 184 deletions
Large diffs are not rendered by default.

tests/v3/test_line_bot_client.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,134 @@ def test_mission_sticker_v3(self):
371371
self.assertEqual(body["sendPresentMessage"], False)
372372

373373

374+
class TestLineBotClientAuthorizationHeader(unittest.TestCase):
375+
"""Test that the Authorization header is correctly propagated to all domains."""
376+
377+
def _assert_bearer_token(self, httpserver, uri, method, token):
378+
"""Helper: call an endpoint and verify the Authorization header."""
379+
request, _ = httpserver.log[-1]
380+
self.assertEqual(request.headers.get("Authorization"), f"Bearer {token}")
381+
382+
def test_messaging_api_sends_bearer_token(self):
383+
with HTTPServer() as httpserver:
384+
httpserver.expect_request(
385+
uri="/v2/bot/profile/U123",
386+
method="GET",
387+
).respond_with_json(
388+
{"displayName": "T", "userId": "U123"}, status=200
389+
)
390+
391+
with LineBotClient(
392+
channel_access_token="my-secret-token",
393+
host=httpserver.url_for("/")
394+
) as client:
395+
client.get_profile(user_id="U123")
396+
397+
request, _ = httpserver.log[0]
398+
self.assertEqual(
399+
request.headers.get("Authorization"), "Bearer my-secret-token"
400+
)
401+
402+
def test_insight_api_sends_bearer_token(self):
403+
with HTTPServer() as httpserver:
404+
httpserver.expect_request(
405+
uri="/v2/bot/insight/followers",
406+
method="GET",
407+
).respond_with_json(
408+
{"status": "ready", "followers": 0, "targetedReaches": 0, "blocks": 0},
409+
status=200
410+
)
411+
412+
with LineBotClient(
413+
channel_access_token="insight-token",
414+
host=httpserver.url_for("/")
415+
) as client:
416+
client.get_number_of_followers(var_date="20240101")
417+
418+
request, _ = httpserver.log[0]
419+
self.assertEqual(
420+
request.headers.get("Authorization"), "Bearer insight-token"
421+
)
422+
423+
def test_audience_api_sends_bearer_token(self):
424+
with HTTPServer() as httpserver:
425+
httpserver.expect_request(
426+
uri="/v2/bot/audienceGroup/99999",
427+
method="DELETE",
428+
).respond_with_json({}, status=200)
429+
430+
with LineBotClient(
431+
channel_access_token="audience-token",
432+
host=httpserver.url_for("/")
433+
) as client:
434+
client.delete_audience_group(audience_group_id=99999)
435+
436+
request, _ = httpserver.log[0]
437+
self.assertEqual(
438+
request.headers.get("Authorization"), "Bearer audience-token"
439+
)
440+
441+
def test_liff_api_sends_bearer_token(self):
442+
with HTTPServer() as httpserver:
443+
httpserver.expect_request(
444+
uri="/liff/v1/apps",
445+
method="GET",
446+
).respond_with_json({"apps": []}, status=200)
447+
448+
with LineBotClient(
449+
channel_access_token="liff-token",
450+
host=httpserver.url_for("/")
451+
) as client:
452+
client.get_all_liff_apps()
453+
454+
request, _ = httpserver.log[0]
455+
self.assertEqual(
456+
request.headers.get("Authorization"), "Bearer liff-token"
457+
)
458+
459+
def test_module_api_sends_bearer_token(self):
460+
with HTTPServer() as httpserver:
461+
httpserver.expect_request(
462+
uri="/v2/bot/list",
463+
method="GET",
464+
).respond_with_json({"bots": []}, status=200)
465+
466+
with LineBotClient(
467+
channel_access_token="module-token",
468+
host=httpserver.url_for("/")
469+
) as client:
470+
client.get_modules()
471+
472+
request, _ = httpserver.log[0]
473+
self.assertEqual(
474+
request.headers.get("Authorization"), "Bearer module-token"
475+
)
476+
477+
def test_shop_api_sends_bearer_token(self):
478+
with HTTPServer() as httpserver:
479+
httpserver.expect_request(
480+
uri="/shop/v3/mission",
481+
method="POST",
482+
).respond_with_json({}, status=200)
483+
484+
with LineBotClient(
485+
channel_access_token="shop-token",
486+
host=httpserver.url_for("/")
487+
) as client:
488+
req = MissionStickerRequest(
489+
to="U123",
490+
productId="p",
491+
productType="t",
492+
sendPresentMessage=False
493+
)
494+
client.mission_sticker_v3(mission_sticker_request=req)
495+
496+
request, _ = httpserver.log[0]
497+
self.assertEqual(
498+
request.headers.get("Authorization"), "Bearer shop-token"
499+
)
500+
501+
374502
class TestLineBotClientErrors(unittest.TestCase):
375503
"""Test error handling through LineBotClient."""
376504

tools/generate_unified_client.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def _extract_params_source(func: ast.FunctionDef) -> str:
176176
for i, arg in enumerate(all_args):
177177
part = arg.arg
178178
if arg.annotation:
179-
part += " : " + ast.unparse(arg.annotation)
179+
part += ": " + ast.unparse(arg.annotation)
180180
default_index = i - (num_args - num_defaults)
181181
if default_index >= 0:
182182
part += " = " + ast.unparse(args.defaults[default_index])
@@ -496,8 +496,14 @@ def generate_sync_client(
496496
lines.append('')
497497
lines.append(' def close(self) -> None:')
498498
lines.append(' """Close all underlying API clients."""')
499+
lines.append(' errors: list[BaseException] = []')
499500
for mod in unique_modules:
500-
lines.append(f' self._{mod}_api_client.close()')
501+
lines.append(f' try:')
502+
lines.append(f' self._{mod}_api_client.close()')
503+
lines.append(f' except Exception as e:')
504+
lines.append(f' errors.append(e)')
505+
lines.append(' if errors:')
506+
lines.append(' raise errors[0]')
501507
lines.append('')
502508

503509
# Delegating methods
@@ -516,7 +522,7 @@ def generate_sync_client(
516522

517523
output_path = os.path.join(repo_root, "linebot/v3/line_bot_client.py")
518524
with open(output_path, "w") as f:
519-
f.write("\n".join(lines))
525+
f.write("\n".join(lines) + "\n")
520526
print(f"Generated {output_path} ({len(all_methods)} methods)")
521527

522528

@@ -639,8 +645,14 @@ def generate_async_client(
639645

640646
lines.append(' async def close(self) -> None:')
641647
lines.append(' """Close all underlying async API clients."""')
648+
lines.append(' errors: list[BaseException] = []')
642649
for mod in unique_modules:
643-
lines.append(f' await self._{mod}_api_client.close()')
650+
lines.append(f' try:')
651+
lines.append(f' await self._{mod}_api_client.close()')
652+
lines.append(f' except Exception as e:')
653+
lines.append(f' errors.append(e)')
654+
lines.append(' if errors:')
655+
lines.append(' raise errors[0]')
644656
lines.append('')
645657

646658
# Delegating methods — async client methods are actually ``def`` (not ``async def``).
@@ -660,7 +672,7 @@ def generate_async_client(
660672

661673
output_path = os.path.join(repo_root, "linebot/v3/async_line_bot_client.py")
662674
with open(output_path, "w") as f:
663-
f.write("\n".join(lines))
675+
f.write("\n".join(lines) + "\n")
664676
print(f"Generated {output_path} ({len(all_methods)} methods)")
665677

666678

0 commit comments

Comments
 (0)