Purchase API Refactoring: Gems [Gold] (#10271)

* remove `keyRequired` - change to `missingKeyParam` - i18n-string

* extract & convert buyGemsOperation

* fix lint
This commit is contained in:
negue
2018-04-27 19:29:26 +02:00
committed by Matteo Pagliazzi
parent 58ce3a9a42
commit 4f963e99dc
11 changed files with 289 additions and 261 deletions

151
package-lock.json generated
View File

@@ -7353,7 +7353,6 @@
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz",
"integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==",
"optional": true,
"requires": { "requires": {
"nan": "2.6.2", "nan": "2.6.2",
"node-pre-gyp": "0.6.39" "node-pre-gyp": "0.6.39"
@@ -7362,14 +7361,12 @@
"abbrev": { "abbrev": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
"integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8="
"optional": true
}, },
"ajv": { "ajv": {
"version": "4.11.8", "version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"optional": true,
"requires": { "requires": {
"co": "4.6.0", "co": "4.6.0",
"json-stable-stringify": "1.0.1" "json-stable-stringify": "1.0.1"
@@ -7383,14 +7380,12 @@
"aproba": { "aproba": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz",
"integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=", "integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s="
"optional": true
}, },
"are-we-there-yet": { "are-we-there-yet": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"optional": true,
"requires": { "requires": {
"delegates": "1.0.0", "delegates": "1.0.0",
"readable-stream": "2.2.9" "readable-stream": "2.2.9"
@@ -7399,32 +7394,27 @@
"asn1": { "asn1": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
"optional": true
}, },
"assert-plus": { "assert-plus": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
"optional": true
}, },
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
"optional": true
}, },
"aws-sign2": { "aws-sign2": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
"optional": true
}, },
"aws4": { "aws4": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
"optional": true
}, },
"balanced-match": { "balanced-match": {
"version": "0.4.2", "version": "0.4.2",
@@ -7473,14 +7463,12 @@
"caseless": { "caseless": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
"optional": true
}, },
"co": { "co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
"optional": true
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
@@ -7522,7 +7510,6 @@
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"optional": true,
"requires": { "requires": {
"assert-plus": "1.0.0" "assert-plus": "1.0.0"
}, },
@@ -7530,8 +7517,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"optional": true
} }
} }
}, },
@@ -7539,7 +7525,6 @@
"version": "2.6.8", "version": "2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
"optional": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "2.0.0"
} }
@@ -7547,8 +7532,7 @@
"deep-extend": { "deep-extend": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
"integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8="
"optional": true
}, },
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
@@ -7558,14 +7542,12 @@
"delegates": { "delegates": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
"optional": true
}, },
"detect-libc": { "detect-libc": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.2.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.2.tgz",
"integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE=", "integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE="
"optional": true
}, },
"ecc-jsbn": { "ecc-jsbn": {
"version": "0.1.1", "version": "0.1.1",
@@ -7579,8 +7561,7 @@
"extend": { "extend": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
"optional": true
}, },
"extsprintf": { "extsprintf": {
"version": "1.0.2", "version": "1.0.2",
@@ -7590,14 +7571,12 @@
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
"optional": true
}, },
"form-data": { "form-data": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
"optional": true,
"requires": { "requires": {
"asynckit": "0.4.0", "asynckit": "0.4.0",
"combined-stream": "1.0.5", "combined-stream": "1.0.5",
@@ -7624,7 +7603,6 @@
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
"integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
"optional": true,
"requires": { "requires": {
"fstream": "1.0.11", "fstream": "1.0.11",
"inherits": "2.0.3", "inherits": "2.0.3",
@@ -7635,7 +7613,6 @@
"version": "2.7.4", "version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"optional": true,
"requires": { "requires": {
"aproba": "1.1.1", "aproba": "1.1.1",
"console-control-strings": "1.1.0", "console-control-strings": "1.1.0",
@@ -7651,7 +7628,6 @@
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"optional": true,
"requires": { "requires": {
"assert-plus": "1.0.0" "assert-plus": "1.0.0"
}, },
@@ -7659,8 +7635,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"optional": true
} }
} }
}, },
@@ -7685,14 +7660,12 @@
"har-schema": { "har-schema": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
"integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4="
"optional": true
}, },
"har-validator": { "har-validator": {
"version": "4.2.1", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
"optional": true,
"requires": { "requires": {
"ajv": "4.11.8", "ajv": "4.11.8",
"har-schema": "1.0.5" "har-schema": "1.0.5"
@@ -7701,8 +7674,7 @@
"has-unicode": { "has-unicode": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
"optional": true
}, },
"hawk": { "hawk": {
"version": "3.1.3", "version": "3.1.3",
@@ -7724,7 +7696,6 @@
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
"optional": true,
"requires": { "requires": {
"assert-plus": "0.2.0", "assert-plus": "0.2.0",
"jsprim": "1.4.0", "jsprim": "1.4.0",
@@ -7748,8 +7719,7 @@
"ini": { "ini": {
"version": "1.3.4", "version": "1.3.4",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4="
"optional": true
}, },
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
@@ -7762,8 +7732,7 @@
"is-typedarray": { "is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
"optional": true
}, },
"isarray": { "isarray": {
"version": "1.0.0", "version": "1.0.0",
@@ -7773,8 +7742,7 @@
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
"optional": true
}, },
"jodid25519": { "jodid25519": {
"version": "1.0.2", "version": "1.0.2",
@@ -7794,14 +7762,12 @@
"json-schema": { "json-schema": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
"optional": true
}, },
"json-stable-stringify": { "json-stable-stringify": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"optional": true,
"requires": { "requires": {
"jsonify": "0.0.0" "jsonify": "0.0.0"
} }
@@ -7809,20 +7775,17 @@
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
"optional": true
}, },
"jsonify": { "jsonify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
"optional": true
}, },
"jsprim": { "jsprim": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
"integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
"optional": true,
"requires": { "requires": {
"assert-plus": "1.0.0", "assert-plus": "1.0.0",
"extsprintf": "1.0.2", "extsprintf": "1.0.2",
@@ -7833,8 +7796,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"optional": true
} }
} }
}, },
@@ -7875,14 +7837,12 @@
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"optional": true
}, },
"node-pre-gyp": { "node-pre-gyp": {
"version": "0.6.39", "version": "0.6.39",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz",
"integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==", "integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==",
"optional": true,
"requires": { "requires": {
"detect-libc": "1.0.2", "detect-libc": "1.0.2",
"hawk": "3.1.3", "hawk": "3.1.3",
@@ -7901,7 +7861,6 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"optional": true,
"requires": { "requires": {
"abbrev": "1.1.0", "abbrev": "1.1.0",
"osenv": "0.1.4" "osenv": "0.1.4"
@@ -7911,7 +7870,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz",
"integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==", "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==",
"optional": true,
"requires": { "requires": {
"are-we-there-yet": "1.1.4", "are-we-there-yet": "1.1.4",
"console-control-strings": "1.1.0", "console-control-strings": "1.1.0",
@@ -7927,14 +7885,12 @@
"oauth-sign": { "oauth-sign": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
"optional": true
}, },
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
@@ -7947,20 +7903,17 @@
"os-homedir": { "os-homedir": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
"optional": true
}, },
"os-tmpdir": { "os-tmpdir": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
"optional": true
}, },
"osenv": { "osenv": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz",
"integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=",
"optional": true,
"requires": { "requires": {
"os-homedir": "1.0.2", "os-homedir": "1.0.2",
"os-tmpdir": "1.0.2" "os-tmpdir": "1.0.2"
@@ -7974,8 +7927,7 @@
"performance-now": { "performance-now": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
"integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
"optional": true
}, },
"process-nextick-args": { "process-nextick-args": {
"version": "1.0.7", "version": "1.0.7",
@@ -7985,20 +7937,17 @@
"punycode": { "punycode": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
"optional": true
}, },
"qs": { "qs": {
"version": "6.4.0", "version": "6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
"optional": true
}, },
"rc": { "rc": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz",
"integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=",
"optional": true,
"requires": { "requires": {
"deep-extend": "0.4.2", "deep-extend": "0.4.2",
"ini": "1.3.4", "ini": "1.3.4",
@@ -8009,8 +7958,7 @@
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
"optional": true
} }
} }
}, },
@@ -8032,7 +7980,6 @@
"version": "2.81.0", "version": "2.81.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
"optional": true,
"requires": { "requires": {
"aws-sign2": "0.6.0", "aws-sign2": "0.6.0",
"aws4": "1.6.0", "aws4": "1.6.0",
@@ -8074,20 +8021,17 @@
"semver": { "semver": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
"optional": true
}, },
"set-blocking": { "set-blocking": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
"optional": true
}, },
"signal-exit": { "signal-exit": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
"optional": true
}, },
"sntp": { "sntp": {
"version": "1.0.9", "version": "1.0.9",
@@ -8101,7 +8045,6 @@
"version": "1.13.0", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
"integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=", "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=",
"optional": true,
"requires": { "requires": {
"asn1": "0.2.3", "asn1": "0.2.3",
"assert-plus": "1.0.0", "assert-plus": "1.0.0",
@@ -8117,8 +8060,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"optional": true
} }
} }
}, },
@@ -8143,8 +8085,7 @@
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
"optional": true
}, },
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
@@ -8157,8 +8098,7 @@
"strip-json-comments": { "strip-json-comments": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
"optional": true
}, },
"tar": { "tar": {
"version": "2.2.1", "version": "2.2.1",
@@ -8174,7 +8114,6 @@
"version": "3.4.0", "version": "3.4.0",
"resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz",
"integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=",
"optional": true,
"requires": { "requires": {
"debug": "2.6.8", "debug": "2.6.8",
"fstream": "1.0.11", "fstream": "1.0.11",
@@ -8190,7 +8129,6 @@
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
"integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
"optional": true,
"requires": { "requires": {
"punycode": "1.4.1" "punycode": "1.4.1"
} }
@@ -8199,7 +8137,6 @@
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"optional": true,
"requires": { "requires": {
"safe-buffer": "5.0.1" "safe-buffer": "5.0.1"
} }
@@ -8213,8 +8150,7 @@
"uid-number": { "uid-number": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
"integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
"optional": true
}, },
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
@@ -8224,14 +8160,12 @@
"uuid": { "uuid": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
"integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE="
"optional": true
}, },
"verror": { "verror": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
"integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
"optional": true,
"requires": { "requires": {
"extsprintf": "1.0.2" "extsprintf": "1.0.2"
} }
@@ -8240,7 +8174,6 @@
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"optional": true,
"requires": { "requires": {
"string-width": "1.0.2" "string-width": "1.0.2"
} }

View File

@@ -0,0 +1,141 @@
/* eslint-disable camelcase */
import sinon from 'sinon'; // eslint-disable-line no-shadow
import {
generateUser,
} from '../../../helpers/common.helper';
import {
BadRequest, NotAuthorized,
} from '../../../../website/common/script/libs/errors';
import i18n from '../../../../website/common/script/i18n';
import {BuyGemOperation} from '../../../../website/common/script/ops/buy/buyGem';
import planGemLimits from '../../../../website/common/script/libs/planGemLimits';
function buyGem (user, req, analytics) {
let buyOp = new BuyGemOperation(user, req, analytics);
return buyOp.purchase();
}
describe('shared.ops.buyGem', () => {
let user;
let analytics = {track () {}};
let goldPoints = 40;
let gemsBought = 40;
let userGemAmount = 10;
beforeEach(() => {
user = generateUser({
stats: { gp: goldPoints },
balance: userGemAmount,
purchased: {
plan: {
gemsBought: 0,
customerId: 'costumer-id',
},
},
});
sinon.stub(analytics, 'track');
});
afterEach(() => {
analytics.track.restore();
});
context('Gems', () => {
it('purchases gems', () => {
let [, message] = buyGem(user, {params: {type: 'gems', key: 'gem'}}, analytics);
expect(message).to.equal(i18n.t('plusGem', {count: 1}));
expect(user.balance).to.equal(userGemAmount + 0.25);
expect(user.purchased.plan.gemsBought).to.equal(1);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
expect(analytics.track).to.be.calledOnce;
});
it('purchases gems with a different language than the default', () => {
let [, message] = buyGem(user, {params: {type: 'gems', key: 'gem'}, language: 'de'});
expect(message).to.equal(i18n.t('plusGem', {count: 1}, 'de'));
expect(user.balance).to.equal(userGemAmount + 0.25);
expect(user.purchased.plan.gemsBought).to.equal(1);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
});
it('makes bulk purchases of gems', () => {
let [, message] = buyGem(user, {
params: {type: 'gems', key: 'gem'},
quantity: 2,
});
expect(message).to.equal(i18n.t('plusGem', {count: 2}));
expect(user.balance).to.equal(userGemAmount + 0.50);
expect(user.purchased.plan.gemsBought).to.equal(2);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate * 2);
});
context('Failure conditions', () => {
it('returns an error when key is not provided', (done) => {
try {
buyGem(user, {params: {type: 'gems'}});
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('missingKeyParam'));
done();
}
});
it('prevents unsubscribed user from buying gems', (done) => {
delete user.purchased.plan.customerId;
try {
buyGem(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustSubscribeToPurchaseGems'));
done();
}
});
it('prevents user with not enough gold from buying gems', (done) => {
user.stats.gp = 15;
try {
buyGem(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('prevents user that have reached the conversion cap from buying gems', (done) => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('reachedGoldToGemCap', {convCap: planGemLimits.convCap}));
done();
}
});
it('prevents user from buying an invalid quantity', (done) => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, {params: {type: 'gems', key: 'gem'}, quantity: 'a'});
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
});
});
});

View File

@@ -1,6 +1,5 @@
import purchase from '../../../../website/common/script/ops/buy/purchase'; import purchase from '../../../../website/common/script/ops/buy/purchase';
import pinnedGearUtils from '../../../../website/common/script/ops/pinnedGearUtils'; import pinnedGearUtils from '../../../../website/common/script/ops/pinnedGearUtils';
import planGemLimits from '../../../../website/common/script/libs/planGemLimits';
import { import {
BadRequest, BadRequest,
NotAuthorized, NotAuthorized,
@@ -17,7 +16,6 @@ describe('shared.ops.purchase', () => {
const SEASONAL_FOOD = 'Meat'; const SEASONAL_FOOD = 'Meat';
let user; let user;
let goldPoints = 40; let goldPoints = 40;
let gemsBought = 40;
let analytics = {track () {}}; let analytics = {track () {}};
before(() => { before(() => {
@@ -45,63 +43,6 @@ describe('shared.ops.purchase', () => {
} }
}); });
it('returns an error when key is not provided', (done) => {
try {
purchase(user, {params: {type: 'gems'}});
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('keyRequired'));
done();
}
});
it('prevents unsubscribed user from buying gems', (done) => {
try {
purchase(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustSubscribeToPurchaseGems'));
done();
}
});
it('prevents user with not enough gold from buying gems', (done) => {
user.purchased.plan.customerId = 'customer-id';
try {
purchase(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('prevents user that have reached the conversion cap from buying gems', (done) => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
purchase(user, {params: {type: 'gems', key: 'gem'}});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('reachedGoldToGemCap', {convCap: planGemLimits.convCap}));
done();
}
});
it('prevents user from buying an invalid quantity', (done) => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
purchase(user, {params: {type: 'gems', key: 'gem'}, quantity: 'a'});
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
it('returns error when unknown type is provided', (done) => { it('returns error when unknown type is provided', (done) => {
try { try {
@@ -185,25 +126,6 @@ describe('shared.ops.purchase', () => {
user.pinnedItems.push({type: 'bundles', key: 'featheredFriends'}); user.pinnedItems.push({type: 'bundles', key: 'featheredFriends'});
}); });
it('purchases gems', () => {
let [, message] = purchase(user, {params: {type: 'gems', key: 'gem'}}, analytics);
expect(message).to.equal(i18n.t('plusOneGem'));
expect(user.balance).to.equal(userGemAmount + 0.25);
expect(user.purchased.plan.gemsBought).to.equal(1);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
expect(analytics.track).to.be.calledOnce;
});
it('purchases gems with a different language than the default', () => {
let [, message] = purchase(user, {params: {type: 'gems', key: 'gem'}, language: 'de'});
expect(message).to.equal(i18n.t('plusOneGem', 'de'));
expect(user.balance).to.equal(userGemAmount + 0.5);
expect(user.purchased.plan.gemsBought).to.equal(2);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate * 2);
});
it('purchases eggs', () => { it('purchases eggs', () => {
let type = 'eggs'; let type = 'eggs';
let key = 'Wolf'; let key = 'Wolf';
@@ -307,18 +229,6 @@ describe('shared.ops.purchase', () => {
} }
}); });
it('makes bulk purchases of gems', () => {
let [, message] = purchase(user, {
params: {type: 'gems', key: 'gem'},
quantity: 2,
});
expect(message).to.equal(i18n.t('plusOneGem'));
expect(user.balance).to.equal(userGemAmount + 0.50);
expect(user.purchased.plan.gemsBought).to.equal(2);
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate * 2);
});
it('makes bulk purchases of eggs', () => { it('makes bulk purchases of eggs', () => {
let type = 'eggs'; let type = 'eggs';
let key = 'TigerCub'; let key = 'TigerCub';

View File

@@ -36,7 +36,7 @@ describe('shared.ops.sell', () => {
sell(user, {params: { type } }); sell(user, {params: { type } });
} catch (err) { } catch (err) {
expect(err).to.be.an.instanceof(BadRequest); expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('keyRequired')); expect(err.message).to.equal(i18n.t('missingKeyParam'));
done(); done();
} }
}); });

View File

@@ -93,10 +93,9 @@
"mustPurchaseToSet": "Must purchase <%= val %> to set it on <%= key %>.", "mustPurchaseToSet": "Must purchase <%= val %> to set it on <%= key %>.",
"typeRequired": "Type is required", "typeRequired": "Type is required",
"positiveAmountRequired": "Positive amount is required", "positiveAmountRequired": "Positive amount is required",
"keyRequired": "Key is required",
"notAccteptedType": "Type must be in [eggs, hatchingPotions, premiumHatchingPotions, food, quests, gear]", "notAccteptedType": "Type must be in [eggs, hatchingPotions, premiumHatchingPotions, food, quests, gear]",
"contentKeyNotFound": "Key not found for Content <%= type %>", "contentKeyNotFound": "Key not found for Content <%= type %>",
"plusOneGem": "+1 Gem", "plusGem": "+<%= count %> Gem",
"typeNotSellable": "Type is not sellable. Must be one of the following <%= acceptedTypes %>", "typeNotSellable": "Type is not sellable. Must be one of the following <%= acceptedTypes %>",
"userItemsKeyNotFound": "Key not found for user.items <%= type %>", "userItemsKeyNotFound": "Key not found for user.items <%= type %>",
"userItemsNotEnough": "You do not have enough <%= type %>", "userItemsNotEnough": "You do not have enough <%= type %>",

View File

@@ -7,6 +7,7 @@
"buyGemsGoldText": "Alexander the Merchant will sell you Gems at a cost of 20 Gold per Gem. His monthly shipments are initially capped at 25 Gems per month, but for every 3 consecutive months that you are subscribed, this cap increases by 5 Gems, up to a maximum of 50 Gems per month!", "buyGemsGoldText": "Alexander the Merchant will sell you Gems at a cost of 20 Gold per Gem. His monthly shipments are initially capped at 25 Gems per month, but for every 3 consecutive months that you are subscribed, this cap increases by 5 Gems, up to a maximum of 50 Gems per month!",
"mustSubscribeToPurchaseGems": "Must subscribe to purchase gems with GP", "mustSubscribeToPurchaseGems": "Must subscribe to purchase gems with GP",
"reachedGoldToGemCap": "You've reached the Gold=>Gem conversion cap <%= convCap %> for this month. We have this to prevent abuse / farming. The cap resets within the first three days of each month.", "reachedGoldToGemCap": "You've reached the Gold=>Gem conversion cap <%= convCap %> for this month. We have this to prevent abuse / farming. The cap resets within the first three days of each month.",
"reachedGoldToGemCapQuantity": "Your requested amount <%= quantity %> exceeds the Gold=>Gem conversion cap <%= convCap %> for this month. We have this to prevent abuse / farming. The cap resets within the first three days of each month.",
"retainHistory": "Retain additional history entries", "retainHistory": "Retain additional history entries",
"retainHistoryText": "Makes completed To-Dos and task history available for longer.", "retainHistoryText": "Makes completed To-Dos and task history available for longer.",
"doubleDrops": "Daily drop caps doubled", "doubleDrops": "Daily drop caps doubled",

View File

@@ -74,6 +74,10 @@ export class AbstractBuyOperation {
return resultObj; return resultObj;
} }
analyticsLabel () {
return 'acquire item';
}
sendToAnalytics (additionalData = {}) { sendToAnalytics (additionalData = {}) {
// spread-operator produces an "unexpected token" error // spread-operator produces an "unexpected token" error
let analyticsData = _merge(additionalData, { let analyticsData = _merge(additionalData, {
@@ -87,7 +91,7 @@ export class AbstractBuyOperation {
analyticsData.quantityPurchased = this.quantity; analyticsData.quantityPurchased = this.quantity;
} }
this.analytics.track('acquire item', analyticsData); this.analytics.track(this.analyticsLabel(), analyticsData);
} }
} }
@@ -100,6 +104,10 @@ export class AbstractGoldItemOperation extends AbstractBuyOperation {
return item.value; return item.value;
} }
getIemKey (item) {
return item.key;
}
canUserPurchase (user, item) { canUserPurchase (user, item) {
this.item = item; this.item = item;
let itemValue = this.getItemValue(item); let itemValue = this.getItemValue(item);
@@ -110,20 +118,20 @@ export class AbstractGoldItemOperation extends AbstractBuyOperation {
throw new NotAuthorized(this.i18n('messageNotEnoughGold')); throw new NotAuthorized(this.i18n('messageNotEnoughGold'));
} }
if (item.canOwn && !item.canOwn(user)) { if (item && item.canOwn && !item.canOwn(user)) {
throw new NotAuthorized(this.i18n('cannotBuyItem')); throw new NotAuthorized(this.i18n('cannotBuyItem'));
} }
} }
subtractCurrency (user, item, quantity = 1) { subtractCurrency (user, item) {
let itemValue = this.getItemValue(item); let itemValue = this.getItemValue(item);
user.stats.gp -= itemValue * quantity; user.stats.gp -= itemValue * this.quantity;
} }
analyticsData () { analyticsData () {
return { return {
itemKey: this.item.key, itemKey: this.getIemKey(this.item),
itemType: 'Market', itemType: 'Market',
acquireMethod: 'Gold', acquireMethod: 'Gold',
goldCost: this.getItemValue(this.item), goldCost: this.getItemValue(this.item),

View File

@@ -11,6 +11,7 @@ import {BuyQuestWithGoldOperation} from './buyQuest';
import buySpecialSpell from './buySpecialSpell'; import buySpecialSpell from './buySpecialSpell';
import purchaseOp from './purchase'; import purchaseOp from './purchase';
import hourglassPurchase from './hourglassPurchase'; import hourglassPurchase from './hourglassPurchase';
import {BuyGemOperation} from './buyGem';
// @TODO: remove the req option style. Dependency on express structure is an anti-pattern // @TODO: remove the req option style. Dependency on express structure is an anti-pattern
// We should either have more parms or a set structure validated by a Type checker // We should either have more parms or a set structure validated by a Type checker
@@ -45,13 +46,18 @@ module.exports = function buy (user, req = {}, analytics) {
buyRes = buyOp.purchase(); buyRes = buyOp.purchase();
break; break;
} }
case 'gems': {
const buyOp = new BuyGemOperation(user, req, analytics);
buyRes = buyOp.purchase();
break;
}
case 'eggs': case 'eggs':
case 'hatchingPotions': case 'hatchingPotions':
case 'food': case 'food':
case 'quests': case 'quests':
case 'gear': case 'gear':
case 'bundles': case 'bundles':
case 'gems':
buyRes = purchaseOp(user, req, analytics); buyRes = purchaseOp(user, req, analytics);
break; break;
case 'pets': case 'pets':

View File

@@ -0,0 +1,81 @@
import pick from 'lodash/pick';
import splitWhitespace from '../../libs/splitWhitespace';
import {
BadRequest,
NotAuthorized,
} from '../../libs/errors';
import {AbstractGoldItemOperation} from './abstractBuyOperation';
import get from 'lodash/get';
import planGemLimits from '../../libs/planGemLimits';
export class BuyGemOperation extends AbstractGoldItemOperation {
constructor (user, req, analytics) {
super(user, req, analytics);
}
multiplePurchaseAllowed () {
return true;
}
getItemValue () {
return planGemLimits.convRate;
}
getIemKey () {
return 'gem';
}
extractAndValidateParams (user, req) {
let key = this.key = get(req, 'params.key');
if (!key) throw new BadRequest(this.i18n('missingKeyParam'));
let convCap = planGemLimits.convCap;
convCap += user.purchased.plan.consecutive.gemCapExtra;
// todo better name?
this.convCap = convCap;
this.canUserPurchase(user);
}
canUserPurchase (user, item) {
if (!user.purchased || !user.purchased.plan || !user.purchased.plan.customerId) {
throw new NotAuthorized(this.i18n('mustSubscribeToPurchaseGems'));
}
super.canUserPurchase(user, item);
if (user.purchased.plan.gemsBought >= this.convCap) {
throw new NotAuthorized(this.i18n('reachedGoldToGemCap', {convCap: this.convCap}));
}
if (user.purchased.plan.gemsBought + this.quantity >= this.convCap) {
throw new NotAuthorized(this.i18n('reachedGoldToGemCapQuantity', {
convCap: this.convCap,
quantity: this.quantity,
}));
}
}
executeChanges (user, item) {
user.balance += 0.25 * this.quantity;
user.purchased.plan.gemsBought += this.quantity;
this.subtractCurrency(user, item);
return [
pick(user, splitWhitespace('stats balance')),
this.i18n('plusGem', {count: this.quantity}),
];
}
analyticsLabel () {
return 'purchase gems';
}
analyticsData () {
let data = super.analyticsData();
data.itemKey = 'gem';
return data;
}
}

View File

@@ -4,7 +4,6 @@ import get from 'lodash/get';
import pick from 'lodash/pick'; import pick from 'lodash/pick';
import forEach from 'lodash/forEach'; import forEach from 'lodash/forEach';
import splitWhitespace from '../../libs/splitWhitespace'; import splitWhitespace from '../../libs/splitWhitespace';
import planGemLimits from '../../libs/planGemLimits';
import { import {
NotFound, NotFound,
NotAuthorized, NotAuthorized,
@@ -14,48 +13,6 @@ import {
import { removeItemByPath } from '../pinnedGearUtils'; import { removeItemByPath } from '../pinnedGearUtils';
import getItemInfo from '../../libs/getItemInfo'; import getItemInfo from '../../libs/getItemInfo';
function buyGems (user, analytics, req, key) {
let convRate = planGemLimits.convRate;
let convCap = planGemLimits.convCap;
convCap += user.purchased.plan.consecutive.gemCapExtra;
// Some groups limit their members ability to obtain gems
// The check is async so it's done on the server (in server/controllers/api-v3/user#purchase)
// only and not on the client,
// resulting in a purchase that will seem successful until the request hit the server.
if (!user.purchased || !user.purchased.plan || !user.purchased.plan.customerId) {
throw new NotAuthorized(i18n.t('mustSubscribeToPurchaseGems', req.language));
}
if (user.stats.gp < convRate) {
throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language));
}
if (user.purchased.plan.gemsBought >= convCap) {
throw new NotAuthorized(i18n.t('reachedGoldToGemCap', {convCap}, req.language));
}
user.balance += 0.25;
user.purchased.plan.gemsBought++;
user.stats.gp -= convRate;
if (analytics) {
analytics.track('purchase gems', {
uuid: user._id,
itemKey: key,
acquireMethod: 'Gold',
goldCost: convRate,
category: 'behavior',
headers: req.headers,
});
}
return [
pick(user, splitWhitespace('stats balance')),
i18n.t('plusOneGem', req.language),
];
}
function getItemAndPrice (user, type, key, req) { function getItemAndPrice (user, type, key, req) {
let item; let item;
let price; let price;
@@ -120,15 +77,7 @@ module.exports = function purchase (user, req = {}, analytics) {
} }
if (!key) { if (!key) {
throw new BadRequest(i18n.t('keyRequired', req.language)); throw new BadRequest(i18n.t('missingKeyParam', req.language));
}
if (type === 'gems' && key === 'gem') {
let gemResponse;
for (let i = 0; i < quantity; i += 1) {
gemResponse = buyGems(user, analytics, req, key);
}
return gemResponse;
} }
if (!acceptedTypes.includes(type)) { if (!acceptedTypes.includes(type)) {

View File

@@ -26,7 +26,7 @@ module.exports = function sell (user, req = {}) {
} }
if (!key) { if (!key) {
throw new BadRequest(i18n.t('keyRequired', req.language)); throw new BadRequest(i18n.t('missingKeyParam', req.language));
} }
if (ACCEPTEDTYPES.indexOf(type) === -1) { if (ACCEPTEDTYPES.indexOf(type) === -1) {