@mongoui/skills 0.1.9 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ # TMC API Endpoint Index
2
+
3
+ Primary source: `open-platform-go/docs/swagger/tmc-api.en-US.json` (3.0.3, 94 operations, 80 paths). Customer-facing short paths omit the shared `/openapi/v1/tmc` prefix; signed runtime calls use the full path. Use `tmc-api.json` only when the user specifically needs Simplified Chinese wording.
4
+
5
+ | No. | Method | Path | Summary | Module | API Code | Operation ID |
6
+ | --- | --- | --- | --- | --- | --- | --- |
7
+ | 1 | POST | `/auth/token` | Get Token | Access and Authorization | `tmc.postAuthToken` | `tmc_postAuthToken` |
8
+ | 2 | GET | `/departments` | Get Department Tree | Organization and People Master Data | `tmc.getDepartments` | `tmc_getDepartments` |
9
+ | 3 | POST | `/employees` | Create Employee | Organization and People Master Data | `tmc.postEmployees` | `tmc_postEmployees` |
10
+ | 4 | PUT | `/employees/{userId}` | Update Employee | Organization and People Master Data | `tmc.putEmployeesUserId` | `tmc_putEmployeesUserId` |
11
+ | 5 | GET | `/employees` | List Employees | Organization and People Master Data | `tmc.getEmployees` | `tmc_getEmployees` |
12
+ | 6 | GET | `/employees/{userId}` | Get Employee Details | Organization and People Master Data | `tmc.getEmployeesUserId` | `tmc_getEmployeesUserId` |
13
+ | 7 | DELETE | `/employees/{userId}` | Delete Employee | Organization and People Master Data | `tmc.deleteEmployeesUserId` | `tmc_deleteEmployeesUserId` |
14
+ | 8 | POST | `/guests/add` | Create Frequent Guest | Organization and People Master Data | `tmc.postGuestsAdd` | `tmc_postGuestsAdd` |
15
+ | 9 | PUT | `/guests/{id}` | Update Frequent Guest | Organization and People Master Data | `tmc.putGuestsId` | `tmc_putGuestsId` |
16
+ | 10 | GET | `/guests` | List Frequent Guests | Organization and People Master Data | `tmc.getGuests` | `tmc_getGuests` |
17
+ | 11 | GET | `/guests/{id}` | Get Frequent Guest Details | Organization and People Master Data | `tmc.getGuestsId` | `tmc_getGuestsId` |
18
+ | 12 | DELETE | `/guests/{id}` | Delete Frequent Guest | Organization and People Master Data | `tmc.deleteGuestsId` | `tmc_deleteGuestsId` |
19
+ | 13 | POST | `/booking-users/list` | List Booking Candidate Users | Organization and People Master Data | `tmc.postBookingUsersList` | `tmc_postBookingUsersList` |
20
+ | 14 | POST | `/email-domains` | Create Email Domain | Organization and People Master Data | `tmc.postEmailDomains` | `tmc_postEmailDomains` |
21
+ | 15 | DELETE | `/email-domains/{id}` | Delete Email Domain | Organization and People Master Data | `tmc.deleteEmailDomainsId` | `tmc_deleteEmailDomainsId` |
22
+ | 16 | GET | `/email-domains` | List Email Domains | Organization and People Master Data | `tmc.getEmailDomains` | `tmc_getEmailDomains` |
23
+ | 17 | GET | `/dict/airports` | List Airports | Reference Data and Dictionaries | `tmc.getDictAirports` | `tmc_getDictAirports` |
24
+ | 18 | GET | `/dict/airlines` | List Airlines | Reference Data and Dictionaries | `tmc.getDictAirlines` | `tmc_getDictAirlines` |
25
+ | 19 | GET | `/dict/nationalities` | List Nationalities | Reference Data and Dictionaries | `tmc.getDictNationalities` | `tmc_getDictNationalities` |
26
+ | 20 | POST | `/approval-policies` | Create Approval Policy | Approval Policy Configuration | `tmc.postApprovalPolicies` | `tmc_postApprovalPolicies` |
27
+ | 21 | PUT | `/approval-policies/{policyId}` | Update Approval Policy | Approval Policy Configuration | `tmc.putApprovalPoliciesPolicyId` | `tmc_putApprovalPoliciesPolicyId` |
28
+ | 22 | DELETE | `/approval-policies/{policyId}` | Delete Approval Policy | Approval Policy Configuration | `tmc.deleteApprovalPoliciesPolicyId` | `tmc_deleteApprovalPoliciesPolicyId` |
29
+ | 23 | GET | `/approval-policies/{policyId}` | Get Approval Policy Details | Approval Policy Configuration | `tmc.getApprovalPoliciesPolicyId` | `tmc_getApprovalPoliciesPolicyId` |
30
+ | 24 | POST | `/approval-policies/page` | Page Approval Policies | Approval Policy Configuration | `tmc.postApprovalPoliciesPage` | `tmc_postApprovalPoliciesPage` |
31
+ | 25 | POST | `/approval-policies/employees` | List Selectable Employees | Approval Policy Configuration | `tmc.postApprovalPoliciesEmployees` | `tmc_postApprovalPoliciesEmployees` |
32
+ | 26 | GET | `/approvals/{approvalNo}` | Get Approval Details | Approval Workflow | `tmc.getApprovalsApprovalNo` | `tmc_getApprovalsApprovalNo` |
33
+ | 27 | POST | `/approvals/page` | Page Approval Orders | Approval Workflow | `tmc.postApprovalsPage` | `tmc_postApprovalsPage` |
34
+ | 28 | POST | `/approvals/audit` | Submit Approval Action | Approval Workflow | `tmc.postApprovalsAudit` | `tmc_postApprovalsAudit` |
35
+ | 29 | POST | `/approvals/resubmit` | Resubmit Approval Order | Approval Workflow | `tmc.postApprovalsResubmit` | `tmc_postApprovalsResubmit` |
36
+ | 30 | GET | `/approvals/{approvalNo}/records` | List Approval Records | Approval Workflow | `tmc.getApprovalsApprovalNoRecords` | `tmc_getApprovalsApprovalNoRecords` |
37
+ | 31 | GET | `/approvals/statistics` | Approval Statistics | Approval Workflow | `tmc.getApprovalsStatistics` | `tmc_getApprovalsStatistics` |
38
+ | 32 | POST | `/travel-policies/hotel` | Create Hotel Travel Policy | Travel Policy Configuration | `tmc.postTravelPoliciesHotel` | `tmc_postTravelPoliciesHotel` |
39
+ | 33 | PUT | `/travel-policies/hotel/{policyId}` | Update Hotel Travel Policy | Travel Policy Configuration | `tmc.putTravelPoliciesHotelPolicyId` | `tmc_putTravelPoliciesHotelPolicyId` |
40
+ | 34 | DELETE | `/travel-policies/hotel/{policyId}` | Delete Hotel Travel Policy | Travel Policy Configuration | `tmc.deleteTravelPoliciesHotelPolicyId` | `tmc_deleteTravelPoliciesHotelPolicyId` |
41
+ | 35 | GET | `/travel-policies/hotel/{policyId}` | Get Hotel Travel Policy Details | Travel Policy Configuration | `tmc.getTravelPoliciesHotelPolicyId` | `tmc_getTravelPoliciesHotelPolicyId` |
42
+ | 36 | POST | `/travel-policies/hotel/page` | Page Hotel Travel Policies | Travel Policy Configuration | `tmc.postTravelPoliciesHotelPage` | `tmc_postTravelPoliciesHotelPage` |
43
+ | 37 | POST | `/travel-policies/hotel/enable` | Enable or Disable Hotel Travel Policy | Travel Policy Configuration | `tmc.postTravelPoliciesHotelEnable` | `tmc_postTravelPoliciesHotelEnable` |
44
+ | 38 | POST | `/travel-policies/flight` | Create Flight Travel Policy | Travel Policy Configuration | `tmc.postTravelPoliciesFlight` | `tmc_postTravelPoliciesFlight` |
45
+ | 39 | PUT | `/travel-policies/flight/{policyId}` | Update Flight Travel Policy | Travel Policy Configuration | `tmc.putTravelPoliciesFlightPolicyId` | `tmc_putTravelPoliciesFlightPolicyId` |
46
+ | 40 | DELETE | `/travel-policies/flight/{policyId}` | Delete Flight Travel Policy | Travel Policy Configuration | `tmc.deleteTravelPoliciesFlightPolicyId` | `tmc_deleteTravelPoliciesFlightPolicyId` |
47
+ | 41 | GET | `/travel-policies/flight/{policyId}` | Get Flight Travel Policy Details | Travel Policy Configuration | `tmc.getTravelPoliciesFlightPolicyId` | `tmc_getTravelPoliciesFlightPolicyId` |
48
+ | 42 | POST | `/travel-policies/flight/page` | Page Flight Travel Policies | Travel Policy Configuration | `tmc.postTravelPoliciesFlightPage` | `tmc_postTravelPoliciesFlightPage` |
49
+ | 43 | POST | `/travel-policies/flight/enable` | Enable or Disable Flight Travel Policy | Travel Policy Configuration | `tmc.postTravelPoliciesFlightEnable` | `tmc_postTravelPoliciesFlightEnable` |
50
+ | 44 | GET | `/travel-policies/users/{employeeId}` | Get User Travel Policy | Travel Policy Configuration | `tmc.getTravelPoliciesUsersEmployeeId` | `tmc_getTravelPoliciesUsersEmployeeId` |
51
+ | 45 | POST | `/flight/search` | Search Flights | Flight Search and Booking | `tmc.postFlightSearch` | `tmc_postFlightSearch` |
52
+ | 46 | POST | `/flight/cabin` | Get Cabin and Price Details | Flight Search and Booking | `tmc.postFlightCabin` | `tmc_postFlightCabin` |
53
+ | 47 | POST | `/flight/verify` | Verify Flight Price | Flight Search and Booking | `tmc.postFlightVerify` | `tmc_postFlightVerify` |
54
+ | 48 | POST | `/flight/order/init` | Initialize Flight Order | Flight Search and Booking | `tmc.postFlightOrderInit` | `tmc_postFlightOrderInit` |
55
+ | 49 | POST | `/flight/order/policy-check` | Travel Policy Check | Flight Search and Booking | `tmc.postFlightOrderPolicyCheck` | `tmc_postFlightOrderPolicyCheck` |
56
+ | 50 | POST | `/flight/order` | Create Flight Order | Flight Search and Booking | `tmc.postFlightOrder` | `tmc_postFlightOrder` |
57
+ | 51 | POST | `/flight/orders` | List Flight Orders | Flight Search and Booking | `tmc.postFlightOrders` | `tmc_postFlightOrders` |
58
+ | 52 | GET | `/flight/orders/{orderCode}` | Get Flight Order Details | Flight Search and Booking | `tmc.getFlightOrdersOrderCode` | `tmc_getFlightOrdersOrderCode` |
59
+ | 53 | POST | `/flight/orders/{orderCode}/cancel` | Cancel Order | Flight Search and Booking | `tmc.postFlightOrdersOrderCodeCancel` | `tmc_postFlightOrdersOrderCodeCancel` |
60
+ | 54 | GET | `/flight/orders/{orderCode}/schedule-changes` | List Flight Schedule Changes | Flight Search and Booking | `tmc.getFlightOrdersOrderCodeScheduleChanges` | `tmc_getFlightOrdersOrderCodeScheduleChanges` |
61
+ | 55 | POST | `/flight/aftersale/capability` | Query Refund and Change Capability | Flight After-Sales | `tmc.postFlightAftersaleCapability` | `tmc_postFlightAftersaleCapability` |
62
+ | 56 | POST | `/flight/aftersale/records` | Query After-Sales Records | Flight After-Sales | `tmc.postFlightAftersaleRecords` | `tmc_postFlightAftersaleRecords` |
63
+ | 57 | POST | `/flight/refund/apply` | Apply for Flight Refund | Flight After-Sales | `tmc.postFlightRefundApply` | `tmc_postFlightRefundApply` |
64
+ | 58 | POST | `/flight/refund/detail` | Get Flight Refund Details | Flight After-Sales | `tmc.postFlightRefundDetail` | `tmc_postFlightRefundDetail` |
65
+ | 59 | POST | `/flight/refund/confirm` | Confirm or Cancel Flight Refund | Flight After-Sales | `tmc.postFlightRefundConfirm` | `tmc_postFlightRefundConfirm` |
66
+ | 60 | POST | `/flight/refund/remaining/passenger-journeys` | List Remaining Refundable Passengers and Segments | Flight After-Sales | `tmc.postFlightRefundRemainingPassengerJourneys` | `tmc_postFlightRefundRemainingPassengerJourneys` |
67
+ | 61 | POST | `/flight/change/search` | Search Flight Change Candidates | Flight After-Sales | `tmc.postFlightChangeSearch` | `tmc_postFlightChangeSearch` |
68
+ | 62 | POST | `/flight/change/compare` | Compare Flight Change Options | Flight After-Sales | `tmc.postFlightChangeCompare` | `tmc_postFlightChangeCompare` |
69
+ | 63 | POST | `/flight/change/apply` | Apply for Flight Change | Flight After-Sales | `tmc.postFlightChangeApply` | `tmc_postFlightChangeApply` |
70
+ | 64 | POST | `/flight/change/detail` | Get Flight Change Details | Flight After-Sales | `tmc.postFlightChangeDetail` | `tmc_postFlightChangeDetail` |
71
+ | 65 | POST | `/flight/change/cancel` | Cancel Flight Change | Flight After-Sales | `tmc.postFlightChangeCancel` | `tmc_postFlightChangeCancel` |
72
+ | 66 | POST | `/flight/change/remaining/passengers` | List Remaining Changeable Passengers | Flight After-Sales | `tmc.postFlightChangeRemainingPassengers` | `tmc_postFlightChangeRemainingPassengers` |
73
+ | 67 | POST | `/flight/change/remaining/segments` | List Remaining Changeable Segments | Flight After-Sales | `tmc.postFlightChangeRemainingSegments` | `tmc_postFlightChangeRemainingSegments` |
74
+ | 68 | GET | `/hotel/locations` | Search Destinations | Hotel Search and Booking | `tmc.getHotelLocations` | `tmc_getHotelLocations` |
75
+ | 69 | GET | `/hotel/search/filters` | Get Hotel Search Filters | Hotel Search and Booking | `tmc.getHotelSearchFilters` | `tmc_getHotelSearchFilters` |
76
+ | 70 | POST | `/hotel/search` | Search Hotels | Hotel Search and Booking | `tmc.postHotelSearch` | `tmc_postHotelSearch` |
77
+ | 71 | GET | `/hotel/{hotelId}` | Get Hotel Details | Hotel Search and Booking | `tmc.getHotelHotelId` | `tmc_getHotelHotelId` |
78
+ | 72 | POST | `/hotel/products/search` | Search Hotel Products | Hotel Search and Booking | `tmc.postHotelProductsSearch` | `tmc_postHotelProductsSearch` |
79
+ | 73 | POST | `/hotel/prices/lowest` | Query Lowest Hotel Prices | Hotel Search and Booking | `tmc.postHotelPricesLowest` | `tmc_postHotelPricesLowest` |
80
+ | 74 | POST | `/hotel/check-booking` | Check Booking | Hotel Search and Booking | `tmc.postHotelCheckBooking` | `tmc_postHotelCheckBooking` |
81
+ | 75 | POST | `/hotel/order/policy-check` | Travel Policy Check | Hotel Search and Booking | `tmc.postHotelOrderPolicyCheck` | `tmc_postHotelOrderPolicyCheck` |
82
+ | 76 | POST | `/hotel/order` | Create Hotel Order | Hotel Search and Booking | `tmc.postHotelOrder` | `tmc_postHotelOrder` |
83
+ | 77 | POST | `/hotel/orders` | List Hotel Orders | Hotel Search and Booking | `tmc.postHotelOrders` | `tmc_postHotelOrders` |
84
+ | 78 | GET | `/hotel/orders/{orderCode}` | Get Hotel Order Details | Hotel Search and Booking | `tmc.getHotelOrdersOrderCode` | `tmc_getHotelOrdersOrderCode` |
85
+ | 79 | POST | `/hotel/orders/{orderCode}/cancel` | Cancel Order | Hotel Search and Booking | `tmc.postHotelOrdersOrderCodeCancel` | `tmc_postHotelOrdersOrderCodeCancel` |
86
+ | 80 | GET | `/hotel/orders/statistics` | Order Status Statistics | Hotel Search and Booking | `tmc.getHotelOrdersStatistics` | `tmc_getHotelOrdersStatistics` |
87
+ | 81 | POST | `/hotel/early-checkout/apply` | Apply for Early Checkout | Hotel After-Sales | `tmc.postHotelEarlyCheckoutApply` | `tmc_postHotelEarlyCheckoutApply` |
88
+ | 82 | POST | `/hotel/early-checkout/detail` | Get Early Checkout Details | Hotel After-Sales | `tmc.postHotelEarlyCheckoutDetail` | `tmc_postHotelEarlyCheckoutDetail` |
89
+ | 83 | POST | `/hotel/early-checkout/can-apply` | Check Early Checkout Eligibility | Hotel After-Sales | `tmc.postHotelEarlyCheckoutCanApply` | `tmc_postHotelEarlyCheckoutCanApply` |
90
+ | 84 | POST | `/payments/payOrder` | Unified Payment | Payment | `tmc.postPaymentsPayOrder` | `tmc_postPaymentsPayOrder` |
91
+ | 85 | POST | `/attachments/upload` | Upload Attachment | Common Capabilities | `tmc.postAttachmentsUpload` | `tmc_postAttachmentsUpload` |
92
+ | 86 | GET | `/attachments/download` | Download Attachment | Common Capabilities | `tmc.getAttachmentsDownload` | `tmc_getAttachmentsDownload` |
93
+ | 87 | GET | `/employees/{userId}/certificates` | List Employee Certificates | Common | `tmc.getEmployeesUserIdCertificates` | `tmc_getEmployeesUserIdCertificates` |
94
+ | 88 | POST | `/employees/certificates` | Create or Update Employee Certificate | Common | `tmc.postEmployeesCertificates` | `tmc_postEmployeesCertificates` |
95
+ | 89 | DELETE | `/employees/certificates/{id}` | Delete Employee Certificate | Common | `tmc.deleteEmployeesCertificatesId` | `tmc_deleteEmployeesCertificatesId` |
96
+ | 90 | GET | `/employees/certificates/{id}` | Get Employee Certificate Details | Common | `tmc.getEmployeesCertificatesId` | `tmc_getEmployeesCertificatesId` |
97
+ | 91 | GET | `/guests/{guestId}/certificates` | List Frequent Guest Certificates | Common | `tmc.getGuestsGuestIdCertificates` | `tmc_getGuestsGuestIdCertificates` |
98
+ | 92 | POST | `/guests/certificates` | Create or Update Frequent Guest Certificate | Common | `tmc.postGuestsCertificates` | `tmc_postGuestsCertificates` |
99
+ | 93 | DELETE | `/guests/certificates/{id}` | Delete Frequent Guest Certificate | Common | `tmc.deleteGuestsCertificatesId` | `tmc_deleteGuestsCertificatesId` |
100
+ | 94 | GET | `/guests/certificates/{id}` | Get Frequent Guest Certificate Details | Common | `tmc.getGuestsCertificatesId` | `tmc_getGuestsCertificatesId` |
101
+
102
+ ## Module Coverage
103
+
104
+ - Access and Authorization: 1 interfaces.
105
+ - Organization and People Master Data: 15 interfaces.
106
+ - Reference Data and Dictionaries: 3 interfaces.
107
+ - Approval Policy Configuration: 6 interfaces.
108
+ - Approval Workflow: 6 interfaces.
109
+ - Travel Policy Configuration: 13 interfaces.
110
+ - Flight Search and Booking: 10 interfaces.
111
+ - Flight After-Sales: 13 interfaces.
112
+ - Hotel Search and Booking: 13 interfaces.
113
+ - Hotel After-Sales: 3 interfaces.
114
+ - Payment: 1 interfaces.
115
+ - Common Capabilities: 2 interfaces.
116
+ - Common: 8 interfaces.
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env python3
2
+ """Generate or send signed requests for the TMC open-platform gateway.
3
+
4
+ Examples:
5
+ python scripts/tmc_signed_request.py ^
6
+ --method POST ^
7
+ --path /auth/token ^
8
+ --body-json "{\"externalUserId\":\"demo_external_user\"}" ^
9
+ --app-key open_app_xxx ^
10
+ --app-secret sk_xxx
11
+
12
+ python scripts/tmc_signed_request.py ^
13
+ --method POST ^
14
+ --path /flight/search ^
15
+ --body-json "{}" ^
16
+ --app-key open_app_xxx ^
17
+ --app-secret sk_xxx ^
18
+ --send
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import hashlib
25
+ import hmac
26
+ import json
27
+ import os
28
+ import sys
29
+ import time
30
+ import urllib.parse
31
+ import urllib.request
32
+ import uuid
33
+ from pathlib import Path
34
+
35
+ GATEWAY_PREFIX = "/openapi/v1/tmc"
36
+
37
+
38
+ def sha256_hex(data: bytes) -> str:
39
+ return hashlib.sha256(data).hexdigest()
40
+
41
+
42
+ def normalize_path(path: str) -> str:
43
+ if not path.startswith("/"):
44
+ path = f"/{path}"
45
+ if path == GATEWAY_PREFIX or path.startswith(f"{GATEWAY_PREFIX}/"):
46
+ return path
47
+ return f"{GATEWAY_PREFIX}{path}"
48
+
49
+
50
+ def parse_query_items(items: list[str]) -> list[tuple[str, str]]:
51
+ pairs: list[tuple[str, str]] = []
52
+ for item in items:
53
+ if "=" not in item:
54
+ raise ValueError(f"invalid query item: {item!r}; expected key=value")
55
+ key, value = item.split("=", 1)
56
+ pairs.append((key, value))
57
+ return pairs
58
+
59
+
60
+ def canonical_query(pairs: list[tuple[str, str]]) -> str:
61
+ ordered = sorted(pairs, key=lambda item: (item[0], item[1]))
62
+ return "&".join(
63
+ f"{urllib.parse.quote(key, safe='~-._')}={urllib.parse.quote(value, safe='~-._')}"
64
+ for key, value in ordered
65
+ )
66
+
67
+
68
+ def build_sign_payload(
69
+ method: str,
70
+ path: str,
71
+ query_string: str,
72
+ body_bytes: bytes,
73
+ timestamp: str,
74
+ nonce: str,
75
+ app_key: str,
76
+ ) -> str:
77
+ return "\n".join(
78
+ [
79
+ method.upper(),
80
+ path,
81
+ query_string,
82
+ sha256_hex(body_bytes),
83
+ timestamp,
84
+ nonce,
85
+ app_key,
86
+ ]
87
+ )
88
+
89
+
90
+ def sign(secret: str, payload: str) -> str:
91
+ return hmac.new(secret.encode("utf-8"), payload.encode("utf-8"), hashlib.sha256).hexdigest()
92
+
93
+
94
+ def load_body(args: argparse.Namespace) -> bytes:
95
+ if args.body_file:
96
+ return Path(args.body_file).read_bytes()
97
+ if args.body_json is None:
98
+ return b""
99
+ parsed = json.loads(args.body_json)
100
+ return json.dumps(parsed, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
101
+
102
+
103
+ def build_url(base_url: str, path: str, query_string: str) -> str:
104
+ base = base_url.rstrip("/")
105
+ url = f"{base}{path}"
106
+ if query_string:
107
+ url = f"{url}?{query_string}"
108
+ return url
109
+
110
+
111
+ def build_headers(app_key: str, timestamp: str, nonce: str, signature: str, has_body: bool) -> dict[str, str]:
112
+ headers = {
113
+ "Accept": "application/json",
114
+ "X-OP-App-Key": app_key,
115
+ "X-OP-Timestamp": timestamp,
116
+ "X-OP-Nonce": nonce,
117
+ "X-OP-Sign": signature,
118
+ }
119
+ if has_body:
120
+ headers["Content-Type"] = "application/json"
121
+ return headers
122
+
123
+
124
+ def send_request(method: str, url: str, headers: dict[str, str], body_bytes: bytes, timeout: float) -> tuple[int, str]:
125
+ request = urllib.request.Request(url=url, data=body_bytes or None, headers=headers, method=method.upper())
126
+ try:
127
+ with urllib.request.urlopen(request, timeout=timeout) as response:
128
+ return response.status, response.read().decode("utf-8", errors="replace")
129
+ except urllib.error.HTTPError as exc:
130
+ return exc.code, exc.read().decode("utf-8", errors="replace")
131
+
132
+
133
+ def main() -> int:
134
+ parser = argparse.ArgumentParser(description="Generate or send a signed TMC open-platform request.")
135
+ parser.add_argument("--base-url", default=os.getenv("OPEN_PLATFORM_BASE_URL", "http://127.0.0.1:8671"))
136
+ parser.add_argument("--method", required=True)
137
+ parser.add_argument("--path", required=True, help="Short interface path, such as /search/auth/token; full gateway paths are also accepted")
138
+ parser.add_argument("--query", action="append", default=[], help="Repeatable key=value query parameter")
139
+ parser.add_argument("--body-json", help="JSON string request body")
140
+ parser.add_argument("--body-file", help="Path to a raw request body file")
141
+ parser.add_argument("--app-key", default=os.getenv("OPEN_PLATFORM_APP_KEY") or os.getenv("OPEN_PLATFORM_OPEN_APP_ID"))
142
+ parser.add_argument("--app-secret", default=os.getenv("OPEN_PLATFORM_APP_SECRET") or os.getenv("OPEN_PLATFORM_OPEN_SECRET"))
143
+ parser.add_argument("--timestamp", default=str(int(time.time())))
144
+ parser.add_argument("--nonce", default=uuid.uuid4().hex)
145
+ parser.add_argument("--send", action="store_true")
146
+ parser.add_argument("--timeout", type=float, default=15.0)
147
+ args = parser.parse_args()
148
+
149
+ if not args.app_key or not args.app_secret:
150
+ print("app key and app secret are required", file=sys.stderr)
151
+ return 2
152
+
153
+ try:
154
+ query_pairs = parse_query_items(args.query)
155
+ body_bytes = load_body(args)
156
+ runtime_path = normalize_path(args.path)
157
+ except Exception as exc:
158
+ print(str(exc), file=sys.stderr)
159
+ return 2
160
+
161
+ query_string = canonical_query(query_pairs)
162
+ payload = build_sign_payload(
163
+ method=args.method,
164
+ path=runtime_path,
165
+ query_string=query_string,
166
+ body_bytes=body_bytes,
167
+ timestamp=args.timestamp,
168
+ nonce=args.nonce,
169
+ app_key=args.app_key,
170
+ )
171
+ signature = sign(args.app_secret, payload)
172
+ headers = build_headers(args.app_key, args.timestamp, args.nonce, signature, bool(body_bytes))
173
+ url = build_url(args.base_url, runtime_path, query_string)
174
+
175
+ print("URL:")
176
+ print(url)
177
+ print()
178
+ print("Canonical String:")
179
+ print(payload)
180
+ print()
181
+ print("Headers:")
182
+ print(json.dumps(headers, ensure_ascii=False, indent=2))
183
+ if body_bytes:
184
+ print()
185
+ print("Body:")
186
+ print(body_bytes.decode("utf-8", errors="replace"))
187
+
188
+ if not args.send:
189
+ return 0
190
+
191
+ status, response_text = send_request(args.method, url, headers, body_bytes, args.timeout)
192
+ print()
193
+ print(f"HTTP {status}")
194
+ print(response_text)
195
+ return 0
196
+
197
+
198
+ if __name__ == "__main__":
199
+ raise SystemExit(main())
@@ -1,8 +0,0 @@
1
- ---
2
- name: tmc-whitelabel
3
- description: Placeholder skill for TMC Whitelabel.
4
- ---
5
-
6
- # TMC Whitelabel
7
-
8
- 内容待补充。