Skip to content
This repository was archived by the owner on Oct 4, 2019. It is now read-only.

Commit 6c7e95e

Browse files
author
Justin Shreve
authored
Add data endpoints for getting currencies (#9)
* Adds endpoints for getting a list of supported currencies, along with their name and symbol. * Limit regex check for currency code to 3 characters.
1 parent db1c191 commit 6c7e95e

File tree

4 files changed

+324
-1
lines changed

4 files changed

+324
-1
lines changed

api/class-wc-rest-dev-data-controller.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ public function get_items_permissions_check( $request ) {
6666
return true;
6767
}
6868

69+
/**
70+
* Check whether a given request has permission to read site settings.
71+
*
72+
* @param WP_REST_Request $request Full details about the request.
73+
* @return WP_Error|boolean
74+
*/
75+
public function get_item_permissions_check( $request ) {
76+
if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
77+
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
78+
}
79+
80+
return true;
81+
}
82+
6983
/**
7084
* Return the list of data resources.
7185
*
@@ -84,6 +98,10 @@ public function get_items( $request ) {
8498
'slug' => 'countries',
8599
'description' => __( 'List of supported states in a given country.', 'woocommerce' ),
86100
),
101+
array(
102+
'slug' => 'currencies',
103+
'description' => __( 'List of supported currencies.', 'woocommerce' ),
104+
),
87105
);
88106

89107
foreach ( $resources as $resource ) {
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?php
2+
/**
3+
* REST API Data currencies controller.
4+
*
5+
* Handles requests to the /data/currencies endpoint.
6+
*
7+
* @author Automattic
8+
* @category API
9+
* @package WooCommerce/API
10+
*/
11+
12+
if ( ! defined( 'ABSPATH' ) ) {
13+
exit;
14+
}
15+
16+
/**
17+
* REST API Data Currencies controller class.
18+
*
19+
* @package WooCommerce/API
20+
*/
21+
class WC_REST_Dev_Data_Currencies_Controller extends WC_REST_Dev_Data_Controller {
22+
23+
/**
24+
* Endpoint namespace.
25+
*
26+
* @var string
27+
*/
28+
protected $namespace = 'wc/v3';
29+
30+
/**
31+
* Route base.
32+
*
33+
* @var string
34+
*/
35+
protected $rest_base = 'data/currencies';
36+
37+
/**
38+
* Register routes.
39+
*/
40+
public function register_routes() {
41+
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
42+
array(
43+
'methods' => WP_REST_Server::READABLE,
44+
'callback' => array( $this, 'get_items' ),
45+
'permission_callback' => array( $this, 'get_items_permissions_check' ),
46+
),
47+
'schema' => array( $this, 'get_public_item_schema' ),
48+
) );
49+
register_rest_route( $this->namespace, '/' . $this->rest_base . '/current', array(
50+
array(
51+
'methods' => WP_REST_Server::READABLE,
52+
'callback' => array( $this, 'get_current_item' ),
53+
'permission_callback' => array( $this, 'get_item_permissions_check' ),
54+
),
55+
'schema' => array( $this, 'get_public_item_schema' ),
56+
) );
57+
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<currency>[\w-]{3}+)', array(
58+
array(
59+
'methods' => WP_REST_Server::READABLE,
60+
'callback' => array( $this, 'get_item' ),
61+
'permission_callback' => array( $this, 'get_item_permissions_check' ),
62+
'args' => array(
63+
'location' => array(
64+
'description' => __( 'ISO4217 currency code.', 'woocommerce' ),
65+
'type' => 'string',
66+
),
67+
),
68+
),
69+
'schema' => array( $this, 'get_public_item_schema' ),
70+
) );
71+
}
72+
73+
/**
74+
* Get currency information.
75+
*
76+
* @param string $code
77+
* @param WP_REST_Request $request
78+
* @return array|mixed Response data, ready for insertion into collection data.
79+
*/
80+
public function get_currency( $code = false, $request ) {
81+
$currencies = get_woocommerce_currencies();
82+
$data = array();
83+
84+
if ( ! array_key_exists( $code, $currencies ) ) {
85+
return false;
86+
}
87+
88+
$currency = array(
89+
'code' => $code,
90+
'name' => $currencies[ $code ],
91+
'symbol' => get_woocommerce_currency_symbol( $code ),
92+
);
93+
94+
return $currency;
95+
}
96+
97+
/**
98+
* Return the list of currencies.
99+
*
100+
* @param WP_REST_Request $request
101+
* @return WP_Error|WP_REST_Response
102+
*/
103+
public function get_items( $request ) {
104+
$currencies = get_woocommerce_currencies();
105+
foreach ( array_keys( $currencies ) as $code ) {
106+
$currency = $this->get_currency( $code, $request );
107+
$response = $this->prepare_item_for_response( $currency, $request );
108+
$data[] = $this->prepare_response_for_collection( $response );
109+
}
110+
111+
return rest_ensure_response( $data );
112+
}
113+
114+
/**
115+
* Return information for a specific currency.
116+
*
117+
* @param WP_REST_Request $request
118+
* @return WP_Error|WP_REST_Response
119+
*/
120+
public function get_item( $request ) {
121+
$data = $this->get_currency( strtoupper( $request['currency'] ), $request );
122+
if ( empty( $data ) ) {
123+
return new WP_Error( 'woocommerce_rest_data_invalid_currency', __( 'There are no currencies matching these parameters.', 'woocommerce' ), array( 'status' => 404 ) );
124+
}
125+
return $this->prepare_item_for_response( $data, $request );
126+
}
127+
128+
/**
129+
* Return information for the current site currency.
130+
*
131+
* @param WP_REST_Request $request
132+
* @return WP_Error|WP_REST_Response
133+
*/
134+
public function get_current_item( $request ) {
135+
$currency = get_option( 'woocommerce_currency' );
136+
return $this->prepare_item_for_response( $this->get_currency( $currency, $request ), $request );
137+
}
138+
139+
/**
140+
* Prepare the data object for response.
141+
*
142+
* @param object $item Data object.
143+
* @param WP_REST_Request $request Request object.
144+
* @return WP_REST_Response $response Response data.
145+
*/
146+
public function prepare_item_for_response( $item, $request ) {
147+
$data = $this->add_additional_fields_to_object( $item, $request );
148+
$data = $this->filter_response_by_context( $data, 'view' );
149+
$response = rest_ensure_response( $data );
150+
151+
$response->add_links( $this->prepare_links( $item ) );
152+
153+
/**
154+
* Filter currency returned from the API.
155+
*
156+
* @param WP_REST_Response $response The response object.
157+
* @param array $item Currency data.
158+
* @param WP_REST_Request $request Request used to generate the response.
159+
*/
160+
return apply_filters( 'woocommerce_rest_prepare_data_currency', $response, $item, $request );
161+
}
162+
163+
/**
164+
* Prepare links for the request.
165+
*
166+
* @param object $item Data object.
167+
* @return array Links for the given currency.
168+
*/
169+
protected function prepare_links( $item ) {
170+
$code = strtoupper( $item['code'] );
171+
$links = array(
172+
'self' => array(
173+
'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $code ) ),
174+
),
175+
'collection' => array(
176+
'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
177+
),
178+
);
179+
180+
return $links;
181+
}
182+
183+
184+
/**
185+
* Get the currency schema, conforming to JSON Schema.
186+
*
187+
* @return array
188+
*/
189+
public function get_item_schema() {
190+
$schema = array(
191+
'$schema' => 'http://json-schema.org/draft-04/schema#',
192+
'title' => 'data_currencies',
193+
'type' => 'object',
194+
'properties' => array(
195+
'code' => array(
196+
'type' => 'string',
197+
'description' => __( 'ISO4217 currency code.', 'woocommerce' ),
198+
'context' => array( 'view' ),
199+
'readonly' => true,
200+
),
201+
'name' => array(
202+
'type' => 'string',
203+
'description' => __( 'Full name of currency.', 'woocommerce' ),
204+
'context' => array( 'view' ),
205+
'readonly' => true,
206+
),
207+
'symbol' => array(
208+
'type' => 'string',
209+
'description' => __( 'Currency symbol.', 'woocommerce' ),
210+
'context' => array( 'view' ),
211+
'readonly' => true,
212+
),
213+
),
214+
);
215+
216+
return $this->add_additional_fields_schema( $schema );
217+
}
218+
}

tests/unit-tests/data.php

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ public function test_register_routes() {
2727
$this->assertArrayHasKey( '/wc/v3/data', $routes );
2828
$this->assertArrayHasKey( '/wc/v3/data/continents', $routes );
2929
$this->assertArrayHasKey( '/wc/v3/data/countries', $routes );
30+
$this->assertArrayHasKey( '/wc/v3/data/currencies', $routes );
31+
$this->assertArrayHasKey( '/wc/v3/data/currencies/current', $routes );
32+
$this->assertArrayHasKey( '/wc/v3/data/currencies/(?P<currency>[\w-]{3}+)', $routes );
3033
}
3134

3235
/**
@@ -38,9 +41,10 @@ public function test_get_index() {
3841
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data' ) );
3942
$index = $response->get_data();
4043
$this->assertEquals( 200, $response->get_status() );
41-
$this->assertCount( 2, $index );
44+
$this->assertCount( 3, $index );
4245
$this->assertEquals( 'continents', $index[0]['slug'] );
4346
$this->assertEquals( 'countries', $index[1]['slug'] );
47+
$this->assertEquals( 'currencies', $index[2]['slug'] );
4448
}
4549

4650
/**
@@ -149,4 +153,85 @@ public function test_get_countries_without_permission() {
149153
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/countries' ) );
150154
$this->assertEquals( 401, $response->get_status() );
151155
}
156+
157+
/**
158+
* Test getting currencies.
159+
*/
160+
public function test_get_currencies() {
161+
wp_set_current_user( $this->user );
162+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies' ) );
163+
$currencies = $response->get_data();
164+
$this->assertEquals( 200, $response->get_status() );
165+
$this->assertTrue( is_array( $currencies ) );
166+
$this->assertGreaterThan( 1, count( $currencies ) );
167+
$this->assertNotEmpty( $currencies[0]['code'] );
168+
$this->assertNotEmpty( $currencies[0]['name'] );
169+
$this->assertNotEmpty( $currencies[0]['symbol'] );
170+
$this->assertNotEmpty( $currencies[0]['_links'] );
171+
}
172+
173+
/**
174+
* Test getting a single currency.
175+
*/
176+
public function test_get_currency() {
177+
wp_set_current_user( $this->user );
178+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/CAD' ) );
179+
$currency = $response->get_data();
180+
$this->assertEquals( 200, $response->get_status() );
181+
$this->assertEquals( 'CAD', $currency['code'] );
182+
$this->assertEquals( 'Canadian dollar', $currency['name'] );
183+
$this->assertEquals( '&#36;', $currency['symbol'] );
184+
$links = $response->get_links();
185+
$this->assertCount( 2, $links );
186+
}
187+
188+
/**
189+
* Test getting current currency.
190+
*/
191+
public function test_get_current_currency() {
192+
$current = get_option( 'woocommerce_currency' );
193+
update_option( 'woocommerce_currency', 'BTC' );
194+
195+
wp_set_current_user( $this->user );
196+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/current' ) );
197+
$currency = $response->get_data();
198+
$this->assertEquals( 200, $response->get_status() );
199+
$this->assertEquals( 'BTC', $currency['code'] );
200+
$this->assertEquals( 'Bitcoin', $currency['name'] );
201+
$this->assertEquals( '&#3647;', $currency['symbol'] );
202+
$links = $response->get_links();
203+
$this->assertCount( 2, $links );
204+
205+
update_option( 'woocommerce_currency', $current );
206+
}
207+
208+
/**
209+
* Test getting currency from an invalid code.
210+
*/
211+
public function test_get_currency_from_invalid_code() {
212+
wp_set_current_user( $this->user );
213+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/xxy' ) );
214+
$this->assertEquals( 404, $response->get_status() );
215+
$this->assertEquals( 'woocommerce_rest_data_invalid_currency', $response->data['code'] );
216+
}
217+
218+
/**
219+
* Test getting currency from an code that is too long.
220+
*/
221+
public function test_get_currency_from_long_code() {
222+
wp_set_current_user( $this->user );
223+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/xxyy' ) );
224+
$this->assertEquals( 404, $response->get_status() );
225+
$this->assertEquals( 'rest_no_route', $response->data['code'] );
226+
}
227+
228+
/**
229+
* Test getting currencies without permissions.
230+
*/
231+
public function test_get_currency_without_permission() {
232+
wp_set_current_user( 0 );
233+
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies' ) );
234+
$this->assertEquals( 401, $response->get_status() );
235+
}
236+
152237
}

wc-api-dev.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public function includes() {
7979
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-controller.php' );
8080
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-continents-controller.php' );
8181
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-countries-controller.php' );
82+
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-currencies-controller.php' );
8283
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-orders-controller.php' );
8384
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-order-notes-controller.php' );
8485
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-order-refunds-controller.php' );
@@ -121,6 +122,7 @@ public function register_routes() {
121122
'WC_REST_Dev_Data_Controller',
122123
'WC_REST_Dev_Data_Continents_Controller',
123124
'WC_REST_Dev_Data_Countries_Controller',
125+
'WC_REST_Dev_Data_Currencies_Controller',
124126
'WC_REST_Dev_Order_Notes_Controller',
125127
'WC_REST_Dev_Order_Refunds_Controller',
126128
'WC_REST_Dev_Orders_Controller',

0 commit comments

Comments
 (0)