Skip to content

Commit 0580115

Browse files
committed
Add support for custom inputs
1 parent ed59718 commit 0580115

9 files changed

Lines changed: 223 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
CHANGELOG
22
=========
33

4+
1.5.0 (2017-07-07)
5+
------------------
6+
7+
* Added support for custom inputs. These can be set up from your account portal.
48
* Added support for new Device inputs. These are:
59
* `/device/session_age`
610
* `/device/session_id`

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ Transaction request = new Transaction.Builder(
206206
.price(3.)
207207
.quantity(1)
208208
.build()
209+
).customInputs(
210+
new CustomInputs.Builder()
211+
.put("float_input", 12.1)
212+
.put("integer_input", 3123)
213+
.put("string_input", "This is a string input.")
214+
.put("boolean_input", true)
215+
.build()
209216
).build();
210217

211218
WebServiceClient client = new WebServiceClient.Builder(6, "ABCD567890").build();
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package com.maxmind.minfraud.request;
2+
3+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
4+
import com.maxmind.minfraud.AbstractModel;
5+
6+
import java.util.Collections;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Custom inputs to be used in
13+
* <a href="https://www.maxmind.com/en/minfraud-interactive/#/custom-rules">Custom Rules</a>.
14+
* In order to use custom inputs, you must set them up from your account portal.
15+
*/
16+
public final class CustomInputs extends AbstractModel {
17+
private final Map<String, Object> inputs;
18+
19+
private CustomInputs(Builder builder) {
20+
inputs = Collections.unmodifiableMap(new HashMap<>(builder.inputs));
21+
}
22+
23+
/**
24+
* {@code Builder} creates instances of {@code CustomInputs}
25+
* from values set by the builder's methods.
26+
*/
27+
public static class Builder {
28+
private static final long NUM_MAX = 1L << 53;
29+
private static final Pattern KEY_PATTERN = Pattern.compile("^[a-z0-9_]{1,25}$");
30+
31+
final Map<String, Object> inputs = new HashMap<>();
32+
33+
/**
34+
* Add a string custom input.
35+
*
36+
* @param key The key for the custom input as defined on your account
37+
* portal.
38+
* @param value The custom input value. Must be less than 256 characters
39+
* and must not contain new lines.
40+
* @return The builder object.
41+
* @throws IllegalArgumentException when the key or value are invalid.
42+
*/
43+
public Builder put(String key, String value) {
44+
validateKey(key);
45+
if (value.length() > 255 || value.contains("\n"))
46+
throw new IllegalArgumentException("The custom input string " +
47+
value + " is invalid. The string be less than" +
48+
"256 characters and the string must not contain a newline.");
49+
inputs.put(key, value);
50+
return this;
51+
}
52+
53+
/**
54+
* Add a numeric custom input.
55+
*
56+
* @param key The key for the custom input as defined on your account
57+
* portal.
58+
* @param value The custom input value. Must be between -2^53 and 2^53,
59+
* exclusive.
60+
* @return The builder object.
61+
* @throws IllegalArgumentException when the key or value are invalid.
62+
*/
63+
public Builder put(String key, Number value) {
64+
validateKey(key);
65+
double doubleValue = value.doubleValue();
66+
if (doubleValue <= -NUM_MAX || doubleValue >= NUM_MAX)
67+
throw new IllegalArgumentException(
68+
"The custom input number " + value + "is invalid. " +
69+
"The number must be between -" + NUM_MAX +
70+
" and " + NUM_MAX + ", exclusive.");
71+
inputs.put(key, value);
72+
return this;
73+
}
74+
75+
/**
76+
* Add a boolean custom input.
77+
*
78+
* @param key The key for the custom input as defined on your account
79+
* portal.
80+
* @param value The custom input value.
81+
* @return The builder object.
82+
* @throws IllegalArgumentException when the key or value are invalid.
83+
*/
84+
public Builder put(String key, boolean value) {
85+
validateKey(key);
86+
inputs.put(key, value);
87+
return this;
88+
}
89+
90+
/**
91+
* @return An instance of {@code CustomInputs} created from the
92+
* fields set on this builder.
93+
*/
94+
public CustomInputs build() {
95+
return new CustomInputs(this);
96+
}
97+
98+
99+
private void validateKey(String key) {
100+
if (!KEY_PATTERN.matcher(key).matches()) {
101+
throw new IllegalArgumentException("The custom input key "
102+
+ key + " is invalid.");
103+
}
104+
}
105+
}
106+
107+
/**
108+
* @return an unmodifiable map containing the custom inputs.
109+
*/
110+
@JsonAnyGetter
111+
public Map<String, Object> getInputs() {
112+
return inputs;
113+
}
114+
}

src/main/java/com/maxmind/minfraud/request/Transaction.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public final class Transaction extends AbstractModel {
1313
private final Account account;
1414
private final Billing billing;
1515
private final CreditCard creditCard;
16+
private final CustomInputs customInputs;
1617
private final Device device;
1718
private final Email email;
1819
private final Event event;
@@ -25,6 +26,7 @@ private Transaction(Transaction.Builder builder) {
2526
account = builder.account;
2627
billing = builder.billing;
2728
creditCard = builder.creditCard;
29+
customInputs = builder.customInputs;
2830
device = builder.device;
2931
email = builder.email;
3032
event = builder.event;
@@ -42,6 +44,7 @@ public static class Builder {
4244
Account account;
4345
Billing billing;
4446
CreditCard creditCard;
47+
CustomInputs customInputs;
4548
Device device;
4649
Email email;
4750
Event event;
@@ -89,6 +92,15 @@ public Builder creditCard(CreditCard val) {
8992
return this;
9093
}
9194

95+
/**
96+
* @param val The CustomInputs object.
97+
* @return The builder object.
98+
*/
99+
public Builder customInputs(CustomInputs val) {
100+
customInputs = val;
101+
return this;
102+
}
103+
92104
/**
93105
* @param val The Email object.
94106
* @return The builder object.
@@ -178,6 +190,14 @@ public CreditCard getCreditCard() {
178190
return creditCard;
179191
}
180192

193+
/**
194+
* @return The CustomInputs object.
195+
*/
196+
@JsonProperty("custom_inputs")
197+
public CustomInputs getCustomInputs() {
198+
return customInputs;
199+
}
200+
181201
/**
182202
* @return The Device object.
183203
*/
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.maxmind.minfraud.request;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Map;
6+
7+
import static org.junit.Assert.assertEquals;
8+
9+
public class CustomInputsTest {
10+
@Test
11+
public void TestPuttingTypes() {
12+
Map<String, Object> inputs = new CustomInputs.Builder()
13+
.put("string_input_1", "test string")
14+
.put("int_input", 19)
15+
.put("long_input", 12L)
16+
.put("float_input", 3.2f)
17+
.put("double_input", 32.123d)
18+
.put("bool_input", true)
19+
.build().getInputs();
20+
21+
assertEquals("test string", inputs.get("string_input_1"));
22+
assertEquals(19, inputs.get("int_input"));
23+
assertEquals(12L, inputs.get("long_input"));
24+
assertEquals(3.2f, inputs.get("float_input"));
25+
assertEquals(32.123d, inputs.get("double_input"));
26+
assertEquals(true, inputs.get("bool_input"));
27+
}
28+
29+
@Test(expected = IllegalArgumentException.class)
30+
public void testInvalidKey() throws Exception {
31+
new CustomInputs.Builder().put("InvalidKey", 1);
32+
}
33+
34+
@Test(expected = IllegalArgumentException.class)
35+
public void testStringThatIsTooLong() throws Exception {
36+
new CustomInputs.Builder().put("string",
37+
new String(new char[256]).replace('\0', 'x'));
38+
}
39+
40+
@Test(expected = IllegalArgumentException.class)
41+
public void testStringWithNewLine() throws Exception {
42+
new CustomInputs.Builder().put("string", "test\n");
43+
}
44+
45+
@Test(expected = IllegalArgumentException.class)
46+
public void testTooLargeLong() throws Exception {
47+
new CustomInputs.Builder().put("long", 1L << 53);
48+
}
49+
50+
@Test(expected = IllegalArgumentException.class)
51+
public void testTooSmallLong() throws Exception {
52+
new CustomInputs.Builder().put("long", -(1L << 53));
53+
}
54+
55+
@Test(expected = IllegalArgumentException.class)
56+
public void testTooLargeDouble() throws Exception {
57+
new CustomInputs.Builder().put("double", (double) (1L << 53));
58+
}
59+
}

src/test/java/com/maxmind/minfraud/request/RequestTestHelper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ public static Transaction fullTransaction() throws Exception {
116116
.quantity(1)
117117
.price(100.)
118118
.build()
119+
).customInputs(
120+
new CustomInputs.Builder()
121+
.put("float_input", 12.1)
122+
.put("integer_input", 3123)
123+
.put("string_input", "This is a string input.")
124+
.put("boolean_input", true)
125+
.build()
119126
).build();
120127
}
121128

src/test/java/com/maxmind/minfraud/request/TransactionTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ public void testCreditCard() throws Exception {
2929
Transaction request = this.builder().creditCard(new CreditCard.Builder().bankName("name").build()).build();
3030
assertEquals("name", request.getCreditCard().getBankName());
3131
}
32+
@Test
33+
public void testCustomInputs() throws Exception {
34+
Transaction request = this.builder().customInputs(
35+
new CustomInputs.Builder().put("key", "value").build()).build();
36+
assertEquals("value", request.getCustomInputs().getInputs().get("key"));
37+
}
3238

3339
@Test
3440
public void testDevice() throws Exception {

src/test/java/com/maxmind/minfraud/response/DispositionTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import com.fasterxml.jackson.jr.ob.JSON;
44
import org.junit.Test;
55

6-
import java.util.UUID;
7-
86
import static org.junit.Assert.assertEquals;
97

108
public class DispositionTest extends AbstractOutputTest {

src/test/resources/test-data/full-request.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
"cvv_result": "N",
5656
"token": "123456abc1234"
5757
},
58+
"custom_inputs": {
59+
"float_input": 12.1,
60+
"integer_input": 3123,
61+
"string_input": "This is a string input.",
62+
"boolean_input": true
63+
},
5864
"order": {
5965
"amount": 323.21,
6066
"currency": "USD",

0 commit comments

Comments
 (0)