dev
dart 289 lines 8.59 KB
Raw
1 import 'dart:convert';
2
3 import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
4 import 'package:cake_wallet/cake_pay/src/models/cake_pay_user_credentials.dart';
5 import 'package:cake_wallet/cake_pay/src/models/cake_pay_vendor.dart';
6 import 'package:cake_wallet/utils/feature_flag.dart';
7 import 'package:cw_core/utils/proxy_wrapper.dart';
8 import 'package:cw_core/utils/print_verbose.dart';
9
10 class CakePayApi {
11 static const testBaseUri = false; //FeatureFlag.hasDevOptions;
12
13 static const baseTestCakePayUri = 'api-stg.cakepay.com';
14 static const baseProdCakePayUri = 'api-prod.cakepay.com';
15
16 static const baseCakePayUri = testBaseUri ? baseTestCakePayUri : baseProdCakePayUri;
17
18 static const vendorsPath = '/api/marketplace/vendors';
19 static const authPath = '/api/accounts/auth';
20 static final verifyEmailPath = '/api/accounts/auth/verify';
21 static final logoutPath = '/api/accounts/logout';
22 static final orderPath = '/api/orders/order';
23 static final simulatePaymentPath = '/api/orders/simulate-payment';
24
25 /// AuthenticateUser
26 Future<String> authenticateUser({required String email, required String apiKey}) async {
27 try {
28 final uri = Uri.https(baseCakePayUri, authPath);
29 final headers = {
30 'Accept': 'application/json',
31 'Content-Type': 'application/json',
32 'Authorization': 'Api-Key $apiKey',
33 };
34 final response = await ProxyWrapper().post(
35 clearnetUri: uri,
36 headers: headers,
37 body: json.encode({'email': email}),
38 );
39
40 if (response.statusCode != 200) {
41 throw Exception('Unexpected http status: ${response.statusCode}');
42 }
43
44 final bodyJson = json.decode(response.body) as Map<String, dynamic>;
45
46 if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) {
47 return bodyJson['user']['email'] as String;
48 }
49
50 throw Exception('Failed to authenticate user with error: $bodyJson');
51 } catch (e) {
52 throw Exception('Failed to authenticate user with error: $e');
53 }
54 }
55
56 /// Verify email
57 Future<CakePayUserCredentials> verifyEmail({
58 required String email,
59 required String code,
60 required String apiKey,
61 }) async {
62 final uri = Uri.https(baseCakePayUri, verifyEmailPath);
63 final headers = {
64 'Accept': 'application/json',
65 'Content-Type': 'application/json',
66 'Authorization': 'Api-Key $apiKey',
67 };
68 final query = <String, String>{'email': email, 'otp': code};
69
70 final response = await ProxyWrapper().post(
71 clearnetUri: uri,
72 headers: headers,
73 body: json.encode(query),
74 );
75
76 if (response.statusCode != 200) {
77 throw Exception('Unexpected http status: ${response.statusCode}');
78 }
79
80 final bodyJson = json.decode(response.body) as Map<String, dynamic>;
81
82 if (bodyJson.containsKey('error')) {
83 throw Exception(bodyJson['error'] as String);
84 }
85
86 if (bodyJson.containsKey('token')) {
87 final token = bodyJson['token'] as String;
88 final userEmail = bodyJson['user']['email'] as String;
89 return CakePayUserCredentials(userEmail, token);
90 } else {
91 throw Exception('E-mail verification failed.');
92 }
93 }
94
95 /// createOrder
96 Future<CakePayOrder> createOrder({
97 required String apiKey,
98 required int cardId,
99 required String price,
100 required int quantity,
101 required String userEmail,
102 required String token,
103 required bool confirmsNoVpn,
104 required bool confirmsVoidedRefund,
105 required bool confirmsTermsAgreed,
106 }) async {
107 final uri = Uri.https(baseCakePayUri, orderPath);
108
109 final headers = {
110 'Accept': 'application/json',
111 'Content-Type': 'application/json',
112 'Authorization': 'Token $token',
113 };
114
115 final body = json.encode({
116 'card_id': cardId,
117 'price': price,
118 'quantity': quantity,
119 'user_email': userEmail,
120 'send_email': true,
121 'confirms_no_vpn': confirmsNoVpn,
122 'confirms_voided_refund': confirmsVoidedRefund,
123 'confirms_terms_agreed': confirmsTermsAgreed,
124 });
125
126 final response = await ProxyWrapper().post(
127 clearnetUri: uri,
128 headers: headers,
129 body: body,
130 );
131
132 if (response.statusCode == 201) {
133 final data = json.decode(response.body) as Map<String, dynamic>;
134 return CakePayOrder.fromMap(data);
135 }
136
137 String message = 'Server error ${response.statusCode}';
138
139 final isJson = response.headers['content-type']?.contains('application/json') == true ||
140 response.body.trim().startsWith(RegExp(r'[\{\[]'));
141
142 if (isJson) {
143 try {
144 final decoded = json.decode(response.body);
145 if (decoded is List && decoded.isNotEmpty) {
146 message = decoded.first.toString();
147 } else if (decoded is Map && decoded['detail'] != null) {
148 message = decoded['detail'].toString();
149 } else {
150 message = decoded.toString();
151 }
152 } on FormatException {}
153 }
154
155 throw Exception(message);
156 }
157
158 /// Get Order by ID
159 Future<CakePayOrder> getOrderById({required String orderId, required String token}) async {
160 final uri = Uri.https(baseCakePayUri, '$orderPath/$orderId');
161 final headers = {
162 'Accept': 'application/json',
163 'Content-Type': 'application/json',
164 'Authorization': 'Token $token',
165 };
166 final response = await ProxyWrapper().get(
167 clearnetUri: uri,
168 headers: headers,
169 );
170
171 if (response.statusCode != 200) {
172 throw Exception('Unexpected http status: ${response.statusCode}');
173 }
174
175 final bodyJson = json.decode(response.body) as Map<String, dynamic>;
176
177 return CakePayOrder.fromMap(bodyJson);
178 }
179
180 ///Simulate Payment
181 Future<String> simulatePayment(
182 {required String CSRFToken,
183 required String authorization,
184 required String orderId,
185 required String token}) async {
186 final uri = Uri.https(baseCakePayUri, simulatePaymentPath);
187
188 final headers = {
189 'Accept': 'application/json',
190 'Content-Type': 'application/json',
191 'Authorization': 'Token $token',
192 };
193
194 final body = json.encode({
195 'order_id': orderId,
196 });
197
198 final response = await ProxyWrapper().post(
199 clearnetUri: uri,
200 headers: headers,
201 body: body,
202 );
203
204 printV('Response: ${response.statusCode}');
205
206 if (response.statusCode != 200) {
207 throw Exception('Unexpected http status: ${response.statusCode}');
208 }
209
210 final bodyJson = json.decode(response.body) as Map<String, dynamic>;
211
212 return 'You just SIMULATED a buying of a gift card with ID: ${bodyJson['order_id']}';
213 }
214
215 /// Logout
216 Future<void> logoutUser({required String email, required String apiKey}) async {
217 final uri = Uri.https(baseCakePayUri, logoutPath);
218 final headers = {
219 'Accept': 'application/json',
220 'Content-Type': 'application/json',
221 'Authorization': 'Api-Key $apiKey',
222 };
223
224 try {
225 final response = await ProxyWrapper().post(
226 clearnetUri: uri,
227 headers: headers,
228 body: json.encode({'email': email}),
229 );
230
231 if (response.statusCode != 200) {
232 throw Exception('Unexpected http status: ${response.statusCode}');
233 }
234 } catch (e) {
235 printV('Caught exception: $e');
236 }
237 }
238
239 /// Get Vendors
240 Future<List<CakePayVendor>> getVendors({
241 required String apiKey,
242 required int page,
243 required String countryCode,
244 String? country,
245 String? search,
246 List<String>? vendorIds,
247 bool? giftCards = true,
248 bool? prepaidCards = true,
249 bool? onDemand,
250 bool? custom,
251 }) async {
252 var queryParams = {
253 'page': page.toString(),
254 'country_code': countryCode,
255 if (search != null && search.isNotEmpty) 'search': search,
256 if (vendorIds != null && vendorIds.isNotEmpty) 'vendor_ids': vendorIds.join(','),
257 };
258
259 if (giftCards == false || prepaidCards == false) {
260 queryParams['gift_cards'] = giftCards.toString();
261 queryParams['prepaid_cards'] = prepaidCards.toString();
262 }
263
264 final uri = Uri.https(baseCakePayUri, vendorsPath, queryParams);
265
266 var headers = {
267 'accept': 'application/json; charset=UTF-8',
268 'Content-Type': 'application/json; charset=UTF-8',
269 'Authorization': 'Api-Key $apiKey',
270 };
271
272 var response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
273
274 if (response.statusCode != 200) {
275 throw Exception(
276 'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}');
277 }
278
279 final bodyJson = json.decode(response.body);
280
281 if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
282 return [];
283 }
284
285 return (bodyJson['results'] as List)
286 .map((e) => CakePayVendor.fromJson(e as Map<String, dynamic>))
287 .toList();
288 }
289 }