mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-10-30 04:32:45 +01:00
Compare commits
403 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6d20fead7 | ||
|
|
f7c23ccac8 | ||
|
|
819f7433db | ||
|
|
bfc84be690 | ||
|
|
5cf2c592b5 | ||
|
|
d79e0b32d2 | ||
|
|
2ab197745a | ||
|
|
7f29088c29 | ||
|
|
d1afbf4b92 | ||
|
|
e1d30eec98 | ||
|
|
1cf3ba26b7 | ||
|
|
8a57d77550 | ||
|
|
11b7cfe176 | ||
|
|
2432492e81 | ||
|
|
c75fdd6b3a | ||
|
|
d52d79f2b1 | ||
|
|
92d19eff80 | ||
|
|
9c6a0e047c | ||
|
|
33d7391202 | ||
|
|
43acb6da95 | ||
|
|
4870623869 | ||
|
|
ee7e40b5c8 | ||
|
|
a3b1e2b524 | ||
|
|
0a4bff0587 | ||
|
|
936fa28a25 | ||
|
|
c3cff31edf | ||
|
|
8f0a9e978d | ||
|
|
81be2f0c28 | ||
|
|
31a5b420d9 | ||
|
|
d206c39b8d | ||
|
|
ba063ec74e | ||
|
|
f84cdfa3cf | ||
|
|
9149588025 | ||
|
|
61427e7bfc | ||
|
|
bcbcd29da7 | ||
|
|
1c851af612 | ||
|
|
3c4bbd673c | ||
|
|
3643b4d320 | ||
|
|
57b9dc374a | ||
|
|
5dc5b4ac92 | ||
|
|
f7e2f04da6 | ||
|
|
47e4ee222d | ||
|
|
9a4e6a5012 | ||
|
|
1859f43133 | ||
|
|
2bcf00fb54 | ||
|
|
78946bf328 | ||
|
|
cab6b35e49 | ||
|
|
04b18641ff | ||
|
|
bd121d4286 | ||
|
|
c3a8305a40 | ||
|
|
b0349d7297 | ||
|
|
e83ac52f17 | ||
|
|
2aa9a65765 | ||
|
|
9bdeb33f4c | ||
|
|
dd691a84e6 | ||
|
|
cac5e0a10c | ||
|
|
ff7b6c592e | ||
|
|
1a0e266ebb | ||
|
|
b121585c68 | ||
|
|
51726d8d8e | ||
|
|
2b8e25833d | ||
|
|
1d7ec89b47 | ||
|
|
9afcf8d5eb | ||
|
|
93393f4835 | ||
|
|
3031caffe8 | ||
|
|
1492994fa8 | ||
|
|
7533eb9d96 | ||
|
|
7461a5d509 | ||
|
|
960a86888a | ||
|
|
4b98a0bf35 | ||
|
|
0dd8cab2a0 | ||
|
|
7eb75f8587 | ||
|
|
3a0aa95788 | ||
|
|
0133184a83 | ||
|
|
743faa8eca | ||
|
|
dd0634d777 | ||
|
|
102cca36e5 | ||
|
|
a78dc7f40d | ||
|
|
0ebdb75fc8 | ||
|
|
58b955c405 | ||
|
|
99282d1a98 | ||
|
|
61d0f6863e | ||
|
|
8acc001004 | ||
|
|
71f8febec7 | ||
|
|
4ef221bfe8 | ||
|
|
caf5eaeb9b | ||
|
|
ccae63f26d | ||
|
|
b652e1ae1b | ||
|
|
71d78c60ff | ||
|
|
0cbf500277 | ||
|
|
6b3b282b98 | ||
|
|
c0eb147e1a | ||
|
|
f8bab04a0e | ||
|
|
e6d20117c1 | ||
|
|
02d5ad35c6 | ||
|
|
3e12774e40 | ||
|
|
17b1365853 | ||
|
|
360aaa9f0b | ||
|
|
94b34f1f80 | ||
|
|
ec7ded042b | ||
|
|
d17cf14866 | ||
|
|
3cde9ed32f | ||
|
|
2f341c6e83 | ||
|
|
b0a1a23b68 | ||
|
|
7c70729843 | ||
|
|
ca842229c9 | ||
|
|
abfcb4ef44 | ||
|
|
7cd59cef35 | ||
|
|
fe34caa2b8 | ||
|
|
56141b6d5b | ||
|
|
15ed76c8f2 | ||
|
|
ea9d939577 | ||
|
|
e65ed4ee36 | ||
|
|
9297685825 | ||
|
|
86eeb3c849 | ||
|
|
fdcca53ee9 | ||
|
|
223eda501b | ||
|
|
66ecb48cda | ||
|
|
07ee36e94d | ||
|
|
e29d06dcd9 | ||
|
|
e03ebbdf46 | ||
|
|
7cb9a752ec | ||
|
|
0bac3c0b5f | ||
|
|
0d9010572c | ||
|
|
ed7a54dfd6 | ||
|
|
4cccaf33e2 | ||
|
|
3a6c296883 | ||
|
|
38896d3103 | ||
|
|
ed7be562f7 | ||
|
|
a1e3127d36 | ||
|
|
a0e5a56bf2 | ||
|
|
c1ea91803c | ||
|
|
fe4a35d1d1 | ||
|
|
f99e3fab8b | ||
|
|
7b4671fbf9 | ||
|
|
07349c70bc | ||
|
|
88243a32fa | ||
|
|
d62653f0fd | ||
|
|
0ecafb4a2e | ||
|
|
6f6a0e51df | ||
|
|
5b215470f7 | ||
|
|
7e027a1a25 | ||
|
|
477743260a | ||
|
|
08f12ac163 | ||
|
|
d079b52c63 | ||
|
|
3eaf993c1b | ||
|
|
a625e83b53 | ||
|
|
07cffe9e16 | ||
|
|
e09a70570e | ||
|
|
5aa371bf90 | ||
|
|
ce4729f069 | ||
|
|
c96d3c8ec5 | ||
|
|
4b0ce7ffc1 | ||
|
|
8bae0223bb | ||
|
|
01d0c5d407 | ||
|
|
e262da4691 | ||
|
|
ecc1c0bba3 | ||
|
|
00f44b655e | ||
|
|
bcf7bcf03c | ||
|
|
415f28995d | ||
|
|
e0e9811ab6 | ||
|
|
0c27fb24a5 | ||
|
|
9cd43db401 | ||
|
|
5aac8e46a5 | ||
|
|
676eeaf190 | ||
|
|
481836f035 | ||
|
|
54e088a097 | ||
|
|
7eb5efb571 | ||
|
|
e47c3211b0 | ||
|
|
85fb5f33aa | ||
|
|
e37f4467f8 | ||
|
|
20f2cf7d27 | ||
|
|
0d90a1db4c | ||
|
|
621787915c | ||
|
|
90c917f69e | ||
|
|
7864ba75c7 | ||
|
|
50cae0165c | ||
|
|
5b57d91a9b | ||
|
|
85eab76a71 | ||
|
|
e1246ff99f | ||
|
|
16c8825b2b | ||
|
|
ca7399f6c1 | ||
|
|
20ef27028e | ||
|
|
916ebcacff | ||
|
|
df0a633b09 | ||
|
|
cc8d3a9f36 | ||
|
|
2a4e103812 | ||
|
|
d19b3857ee | ||
|
|
3a6a4092f9 | ||
|
|
17c7a2bad1 | ||
|
|
5b406ba70f | ||
|
|
e021328067 | ||
|
|
db02712c98 | ||
|
|
45f7cf04ab | ||
|
|
e0a2528a4f | ||
|
|
9a2bb981a9 | ||
|
|
823a1034e0 | ||
|
|
03f7adf596 | ||
|
|
9c20c3595a | ||
|
|
228f2379aa | ||
|
|
211da982b3 | ||
|
|
9c93daf542 | ||
|
|
f933cb624c | ||
|
|
8308f88865 | ||
|
|
d7d2789991 | ||
|
|
33bd3dc65b | ||
|
|
e92320a256 | ||
|
|
3c7d3aafe5 | ||
|
|
86dbc23f3c | ||
|
|
cca5b8492b | ||
|
|
4faa06f37d | ||
|
|
33b26a69b8 | ||
|
|
b466d12263 | ||
|
|
e69275663b | ||
|
|
e2781964bb | ||
|
|
2d3f2500e8 | ||
|
|
77b188833e | ||
|
|
b44fbdcb14 | ||
|
|
5b61f65711 | ||
|
|
46e4036c01 | ||
|
|
dadcf5db07 | ||
|
|
b21a07aa66 | ||
|
|
c6be804723 | ||
|
|
a8846b17c0 | ||
|
|
e6ca63cc36 | ||
|
|
dd9f459bbf | ||
|
|
a715ec1a0f | ||
|
|
47e9278814 | ||
|
|
2192646c0a | ||
|
|
2db03da7b4 | ||
|
|
c5690e5ea9 | ||
|
|
bbbe0cca09 | ||
|
|
0072a3968d | ||
|
|
f3fb09f4f9 | ||
|
|
c4f44fce4c | ||
|
|
e1abeeb78a | ||
|
|
17e8b0a0fd | ||
|
|
ef1e7ba336 | ||
|
|
5a633e7b64 | ||
|
|
b4035b5116 | ||
|
|
b142225a5a | ||
|
|
119e6dd7a2 | ||
|
|
ebfced4a2e | ||
|
|
1efb21709b | ||
|
|
f184384175 | ||
|
|
2843484f44 | ||
|
|
a2e1922e8d | ||
|
|
de5669dfec | ||
|
|
01d272d2c4 | ||
|
|
5f2032a9d5 | ||
|
|
77e5ae584c | ||
|
|
0e8ad2dc42 | ||
|
|
509b2e4522 | ||
|
|
f792513a26 | ||
|
|
8640f452e9 | ||
|
|
4d180b2b3d | ||
|
|
31062fd20c | ||
|
|
ba4d057312 | ||
|
|
388892ccdd | ||
|
|
65e3690e9a | ||
|
|
59b13c8c80 | ||
|
|
70e672df93 | ||
|
|
ca48caab27 | ||
|
|
b342eaacc6 | ||
|
|
e9529d510d | ||
|
|
88b8f20d12 | ||
|
|
749138df4d | ||
|
|
3948f63290 | ||
|
|
326ec5c0e3 | ||
|
|
b4ee784cf3 | ||
|
|
d93d295d9f | ||
|
|
bbf45f263a | ||
|
|
ffb3f760dc | ||
|
|
b23099ae75 | ||
|
|
d5868f67ec | ||
|
|
b81a54b659 | ||
|
|
a986b5d63d | ||
|
|
9a0c493813 | ||
|
|
345311e55a | ||
|
|
cfb46f8a0b | ||
|
|
cf39cd7e82 | ||
|
|
8138553c82 | ||
|
|
f3372716d9 | ||
|
|
d29a7ef651 | ||
|
|
70b6501135 | ||
|
|
c6281b6f17 | ||
|
|
3aa2e30815 | ||
|
|
4690431384 | ||
|
|
39a00cd009 | ||
|
|
2a9f5e1667 | ||
|
|
7b69967412 | ||
|
|
be3ffc8505 | ||
|
|
dd320c6907 | ||
|
|
e0a2730556 | ||
|
|
6600db5c5d | ||
|
|
4afe0cf130 | ||
|
|
ed266adfc2 | ||
|
|
a629ec510f | ||
|
|
6523b6b342 | ||
|
|
6f75a8d99a | ||
|
|
b8c00446a8 | ||
|
|
56b4008835 | ||
|
|
4e9678efe3 | ||
|
|
3d53ab09e8 | ||
|
|
7d732b5612 | ||
|
|
73794a5bb6 | ||
|
|
c63c1f7c9a | ||
|
|
82b811edca | ||
|
|
32b0460063 | ||
|
|
67de080391 | ||
|
|
85ec9e9bfb | ||
|
|
bbd4445aa3 | ||
|
|
03dbd1dfc6 | ||
|
|
945fb674a5 | ||
|
|
bbba0510a7 | ||
|
|
23c7177da6 | ||
|
|
9bf380039e | ||
|
|
201b4551a3 | ||
|
|
9709b92d33 | ||
|
|
c39f53c224 | ||
|
|
b74a14acc3 | ||
|
|
cb6fdd4a15 | ||
|
|
2c881d4a3a | ||
|
|
6294f2a481 | ||
|
|
ce62af1e44 | ||
|
|
24ecbfa51d | ||
|
|
84ac5c2d9f | ||
|
|
b6f3e4ccd8 | ||
|
|
2dca2148f4 | ||
|
|
51f66af320 | ||
|
|
4a66e2fbe0 | ||
|
|
5e50e98738 | ||
|
|
601811eac6 | ||
|
|
071dffe8f2 | ||
|
|
1173a9b586 | ||
|
|
af510ce86f | ||
|
|
076e1b851e | ||
|
|
718ea926d8 | ||
|
|
328ecb22d8 | ||
|
|
be5137d14d | ||
|
|
3fec6fca0e | ||
|
|
bb674d1539 | ||
|
|
59dbd12576 | ||
|
|
e9d5123f8a | ||
|
|
82863bd947 | ||
|
|
8618913a75 | ||
|
|
59f08bc0db | ||
|
|
548c68f878 | ||
|
|
c3d9ac6c4e | ||
|
|
8641a98107 | ||
|
|
664a457b47 | ||
|
|
024e93e89b | ||
|
|
cde279e489 | ||
|
|
0e262dca68 | ||
|
|
b355b3d7f3 | ||
|
|
8c1208031d | ||
|
|
aac23f30cf | ||
|
|
03763f46c9 | ||
|
|
a0b1732f7e | ||
|
|
80ef4a3297 | ||
|
|
46a4948f02 | ||
|
|
f9fdab782a | ||
|
|
2066f1288f | ||
|
|
be9203801e | ||
|
|
916d930a83 | ||
|
|
1562c6944b | ||
|
|
21f14d55b7 | ||
|
|
4417787dfe | ||
|
|
bfa3f9a314 | ||
|
|
6f86600b46 | ||
|
|
d3f964c96e | ||
|
|
d661c7260e | ||
|
|
b2095bdb0e | ||
|
|
1ccb700b3f | ||
|
|
42a4bbeab7 | ||
|
|
e0b78a3cf4 | ||
|
|
5028b271fb | ||
|
|
f5b6291abf | ||
|
|
f5a2cf6726 | ||
|
|
15e2e2ab07 | ||
|
|
999477024b | ||
|
|
b49d2e4d2e | ||
|
|
62bcd878a0 | ||
|
|
d0b72d5dd4 | ||
|
|
d031a4c9aa | ||
|
|
793af2a10d | ||
|
|
2598a6001e | ||
|
|
e548074bc1 | ||
|
|
662e642729 | ||
|
|
dd2c2f62b8 | ||
|
|
577ff4cab9 | ||
|
|
e8b7dbb4d2 | ||
|
|
8d93d6bd16 | ||
|
|
0b7a60e3de | ||
|
|
a450ac3652 | ||
|
|
30ebdcaa4f | ||
|
|
ffa2ea4bb4 | ||
|
|
f65240c217 | ||
|
|
0271d98b91 | ||
|
|
e9c86622c5 | ||
|
|
aae2fb1cb9 | ||
|
|
39761bdc04 | ||
|
|
7d29ae44ba |
14
.babelrc
14
.babelrc
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"plugins": [
|
||||
"transform-es2015-modules-commonjs",
|
||||
"syntax-object-rest-spread",
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ coverage/
|
||||
database_reports/
|
||||
website/build/
|
||||
website/transpiled-babel/
|
||||
# Has its own linter
|
||||
website/client/
|
||||
website/common/transpiled-babel/
|
||||
dist/
|
||||
dist-client/
|
||||
|
||||
10
.eslintrc
10
.eslintrc
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
"extends": [
|
||||
"habitrpg",
|
||||
"habitrpg/esnext"
|
||||
],
|
||||
}
|
||||
6
.eslintrc.js
Normal file
6
.eslintrc.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
'habitrpg/lib/node'
|
||||
],
|
||||
}
|
||||
198
.github/workflows/test.yml
vendored
Normal file
198
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run lint-no-fix
|
||||
apidoc:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run apidoc
|
||||
sanity:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:sanity
|
||||
|
||||
common:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:common
|
||||
content:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:content
|
||||
|
||||
api-unit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo docker run --name mongo -d -p 27017:27017 mongo
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:api:unit
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
api-v3-integration:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo docker run --name mongo -d -p 27017:27017 mongo
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:api-v3:integration
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
api-v4-integration:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo docker run --name mongo -d -p 27017:27017 mongo
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:api-v4:integration
|
||||
env:
|
||||
REQUIRES_SERVER=true: true
|
||||
|
||||
client-unit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
npm ci
|
||||
env:
|
||||
CI: true
|
||||
- run: npm run test:unit
|
||||
working-directory: ./website/client
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,10 +1,5 @@
|
||||
.DS_Store
|
||||
website/client-old/gen
|
||||
website/client-old/common
|
||||
website/client-old/apidoc
|
||||
website/build
|
||||
website/client-old/js/habitrpg-shared.js*
|
||||
website/client-old/css/habitrpg-shared.css
|
||||
website/transpiled-babel/
|
||||
website/common/transpiled-babel/
|
||||
node_modules
|
||||
@@ -15,8 +10,6 @@ apidoc_build
|
||||
config.json
|
||||
npm-debug.log*
|
||||
lib
|
||||
website/client-old/bower_components
|
||||
website/client-old/new-stuff.html
|
||||
newrelic_agent.log
|
||||
.bower-tmp
|
||||
.bower-registry
|
||||
@@ -27,15 +20,13 @@ TODO
|
||||
*.log
|
||||
src/*/*.map
|
||||
src/*/*/*.map
|
||||
test/*.js
|
||||
test/*.map
|
||||
website/client-old/docs
|
||||
*.sublime-workspace
|
||||
coverage
|
||||
coverage.html
|
||||
common/dist/scripts/*
|
||||
dist
|
||||
dist-client
|
||||
website/client/dist
|
||||
test/client/unit/coverage
|
||||
test/client/e2e/reports
|
||||
test/client-old/spec/mocks/translations.js
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
node_modules/**
|
||||
.bower-cache/**
|
||||
.bower-tmp/**
|
||||
.bower-registry/**
|
||||
website/client-old/**
|
||||
website/client/**
|
||||
website/client/store/**
|
||||
website/views/**
|
||||
website/build/**
|
||||
dist/**
|
||||
test/**
|
||||
.git/**
|
||||
Gruntfile.js
|
||||
CHANGELOG.md
|
||||
.idea*
|
||||
*.log
|
||||
newrelic_agent.log
|
||||
*.swp
|
||||
*.swx
|
||||
website/raw_sprites/**
|
||||
|
||||
29
.travis.yml
29
.travis.yml
@@ -1,29 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '12'
|
||||
services:
|
||||
- mongodb
|
||||
cache:
|
||||
directories:
|
||||
- 'node_modules'
|
||||
addons:
|
||||
chrome: stable
|
||||
before_script:
|
||||
- npm run test:build
|
||||
- cp config.json.example config.json
|
||||
- sleep 5
|
||||
script:
|
||||
- npm run $TEST
|
||||
env:
|
||||
global:
|
||||
- DISABLE_REQUEST_LOGGING=true
|
||||
matrix:
|
||||
- TEST="lint"
|
||||
- TEST="test:api:unit" REQUIRES_SERVER=true COVERAGE=true
|
||||
- TEST="test:api-v3:integration" REQUIRES_SERVER=true COVERAGE=true
|
||||
- TEST="test:api-v4:integration" REQUIRES_SERVER=true COVERAGE=true
|
||||
- TEST="test:sanity"
|
||||
- TEST="test:content" COVERAGE=true
|
||||
- TEST="test:common" COVERAGE=true
|
||||
- TEST="client:unit" COVERAGE=true
|
||||
- TEST="apidoc"
|
||||
@@ -19,12 +19,9 @@ RUN npm install -g gulp-cli mocha
|
||||
RUN mkdir -p /usr/src/habitrpg
|
||||
WORKDIR /usr/src/habitrpg
|
||||
RUN git clone --branch release --depth 1 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
|
||||
RUN npm set unsafe-perm true
|
||||
RUN npm install
|
||||
RUN gulp build:prod --force
|
||||
|
||||
# Create Build dir
|
||||
RUN mkdir -p ./website/build
|
||||
|
||||
# Start Habitica
|
||||
EXPOSE 3000
|
||||
EXPOSE 80 8080 36612
|
||||
CMD ["node", "./website/transpiled-babel/index.js"]
|
||||
|
||||
12
README.md
12
README.md
@@ -1,12 +1,16 @@
|
||||
Habitica [](https://travis-ci.org/HabitRPG/habitica) [](https://codeclimate.com/github/HabitRPG/habitrpg) [](https://www.bountysource.com/trackers/68393-habitrpg?utm_source=68393&utm_medium=shield&utm_campaign=TRACKER_BADGE) [](https://www.codetriage.com/habitrpg/habitica)
|
||||
Habitica  [](https://codeclimate.com/github/HabitRPG/habitrpg) [](https://www.bountysource.com/trackers/68393-habitrpg?utm_source=68393&utm_medium=shield&utm_campaign=TRACKER_BADGE) [](https://www.codetriage.com/habitrpg/habitica)
|
||||
===============
|
||||
|
||||
[](https://greenkeeper.io/)
|
||||
|
||||
[Habitica](https://habitica.com) is an open source habit building program which treats your life like a Role Playing Game. Level up as you succeed, lose HP as you fail, earn money to buy weapons and armor.
|
||||
|
||||
We need more programmers! Your assistance will be greatly appreciated.
|
||||
**We need more programmers!** Your assistance will be greatly appreciated. The wiki pages below and the additional pages they link to will tell you how to get started on contributing code and where you can go to seek further help or ask questions:
|
||||
* [Guidance for Blacksmiths](http://habitica.fandom.com/wiki/Guidance_for_Blacksmiths) - an introduction to the technologies used and how the software is organized.
|
||||
* [Setting up Habitica Locally](http://habitica.fandom.com/wiki/Setting_up_Habitica_Locally) - how to set up a local install of Habitica for development and testing on various platforms.
|
||||
|
||||
For an introduction to the technologies used and how the software is organized, refer to [Guidance for Blacksmiths](http://habitica.fandom.com/wiki/Guidance_for_Blacksmiths).
|
||||
Habitica's code is licensed as described at https://github.com/HabitRPG/habitica/blob/develop/LICENSE
|
||||
|
||||
To set up a local install of Habitica for development and testing on various platforms, see [Setting up Habitica Locally](http://habitica.fandom.com/wiki/Setting_up_Habitica_Locally).
|
||||
**Found a bug?** Please report it in the [Report a Bug guild](https://habitica.com/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac) rather than creating an issue (an admin will advise you if a new issue is necessary; usually it is not).
|
||||
|
||||
**Have any questions about Habitica or its community?** See the links in the [habitica.com](https://habitica.com) website's Help menu or drop in to [Guilds > Tavern Chat](https://habitica.com/groups/tavern) to ask questions or chat socially!
|
||||
|
||||
11
VAGRANT.md
11
VAGRANT.md
@@ -1,11 +0,0 @@
|
||||
# Vagrant #
|
||||
|
||||
Vagrant is a system to create reproducible and portable development
|
||||
environments. Because of the variety of systems used for Habitica
|
||||
development and the various issues developers may encounter setting up
|
||||
Habitica on them, vagrant provides a single development enviroment with
|
||||
minimal dependencies on the developer's local platform. It can be used
|
||||
on a variety of systems including Windows, Mac OS X, and Linux.
|
||||
|
||||
Instructions for using the Habitica Vagrant environment are in
|
||||
[Setting up Habitica Locally](http://habitica.fandom.com/wiki/Setting_up_Habitica_Locally).
|
||||
@@ -1,22 +0,0 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 1
|
||||
v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant", "1"]
|
||||
end
|
||||
config.vm.box = "thepeopleseason/habitrpg"
|
||||
config.ssh.forward_agent = true
|
||||
|
||||
config.vm.hostname = "habitrpg"
|
||||
config.vm.network "forwarded_port", guest: 3000, host: 3000, auto_correct: true
|
||||
config.vm.usable_port_range = (3000..3050)
|
||||
config.vm.network "forwarded_port", guest: 8080, host: 8080, auto_correct: true
|
||||
config.vm.usable_port_range = (8080..8130)
|
||||
config.vm.provision :shell, :path => "vagrant_scripts/vagrant.sh"
|
||||
end
|
||||
@@ -33,6 +33,7 @@
|
||||
"LOGGLY_TOKEN": "example-token",
|
||||
"MAINTENANCE_MODE": "false",
|
||||
"NODE_DB_URI": "mongodb://localhost/habitrpg",
|
||||
"MONGODB_POOL_SIZE": "10",
|
||||
"NODE_ENV": "development",
|
||||
"PATH": "bin:node_modules/.bin:/usr/local/bin:/usr/bin:/bin",
|
||||
"PAYPAL_BILLING_PLANS_basic_12mo": "basic_12mo",
|
||||
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
- .:/code
|
||||
- /code/node_modules
|
||||
mongo:
|
||||
image: mongo:3.4
|
||||
image: mongo:3.6
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- mongo
|
||||
|
||||
mongo:
|
||||
image: mongo:3.4
|
||||
image: mongo:3.6
|
||||
ports:
|
||||
- "27017:27017"
|
||||
networks:
|
||||
|
||||
@@ -4,12 +4,12 @@ import apidoc from 'apidoc';
|
||||
|
||||
const APIDOC_DEST_PATH = './apidoc_build';
|
||||
const APIDOC_SRC_PATH = './website/server';
|
||||
gulp.task('apidoc:clean', (done) => {
|
||||
gulp.task('apidoc:clean', done => {
|
||||
clean(APIDOC_DEST_PATH, done);
|
||||
});
|
||||
|
||||
gulp.task('apidoc', gulp.series('apidoc:clean', (done) => {
|
||||
let result = apidoc.createDoc({
|
||||
gulp.task('apidoc', gulp.series('apidoc:clean', done => {
|
||||
const result = apidoc.createDoc({
|
||||
src: APIDOC_SRC_PATH,
|
||||
dest: APIDOC_DEST_PATH,
|
||||
});
|
||||
@@ -21,6 +21,4 @@ gulp.task('apidoc', gulp.series('apidoc:clean', (done) => {
|
||||
}
|
||||
}));
|
||||
|
||||
gulp.task('apidoc:watch', gulp.series('apidoc', (done) => {
|
||||
return gulp.watch(`${APIDOC_SRC_PATH}/**/*.js`, gulp.series('apidoc', done));
|
||||
}));
|
||||
gulp.task('apidoc:watch', gulp.series('apidoc', done => gulp.watch(`${APIDOC_SRC_PATH}/**/*.js`, gulp.series('apidoc', done))));
|
||||
|
||||
@@ -1,43 +1,28 @@
|
||||
import gulp from 'gulp';
|
||||
import babel from 'gulp-babel';
|
||||
import webpackProductionBuild from '../webpack/build';
|
||||
|
||||
gulp.task('build:src', () => {
|
||||
return gulp.src('website/server/**/*.js')
|
||||
.pipe(babel())
|
||||
.pipe(gulp.dest('website/transpiled-babel/'));
|
||||
});
|
||||
gulp.task('build:src', () => gulp.src('website/server/**/*.js')
|
||||
.pipe(babel())
|
||||
.pipe(gulp.dest('website/transpiled-babel/')));
|
||||
|
||||
gulp.task('build:common', () => {
|
||||
return gulp.src('website/common/script/**/*.js')
|
||||
.pipe(babel())
|
||||
.pipe(gulp.dest('website/common/transpiled-babel/'));
|
||||
});
|
||||
gulp.task('build:common', () => gulp.src('website/common/script/**/*.js')
|
||||
.pipe(babel())
|
||||
.pipe(gulp.dest('website/common/transpiled-babel/')));
|
||||
|
||||
gulp.task('build:server', gulp.series('build:src', 'build:common', done => done()));
|
||||
|
||||
// Client Production Build
|
||||
gulp.task('build:client', (done) => {
|
||||
webpackProductionBuild((err, output) => {
|
||||
if (err) return done(err);
|
||||
console.log(output); // eslint-disable-line no-console
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('build:prod', gulp.series(
|
||||
'build:server',
|
||||
'build:client',
|
||||
'apidoc',
|
||||
done => done()
|
||||
done => done(),
|
||||
));
|
||||
|
||||
let buildArgs = [];
|
||||
const buildArgs = [];
|
||||
|
||||
if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env
|
||||
buildArgs.push('build:prod');
|
||||
}
|
||||
|
||||
gulp.task('build', gulp.series(buildArgs, (done) => {
|
||||
gulp.task('build', gulp.series(buildArgs, done => {
|
||||
done();
|
||||
}));
|
||||
}));
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
import mongoose from 'mongoose';
|
||||
import logger from '../website/server/libs/logger';
|
||||
import nconf from 'nconf';
|
||||
import repl from 'repl';
|
||||
import gulp from 'gulp';
|
||||
import nconf from 'nconf';
|
||||
import repl from 'repl';
|
||||
import gulp from 'gulp';
|
||||
import logger from '../website/server/libs/logger';
|
||||
|
||||
// Add additional properties to the repl's context
|
||||
let improveRepl = (context) => {
|
||||
const improveRepl = context => {
|
||||
// Let "exit" and "quit" terminate the console
|
||||
['exit', 'quit'].forEach((term) => {
|
||||
Object.defineProperty(context, term, { get () {
|
||||
process.exit();
|
||||
}});
|
||||
['exit', 'quit'].forEach(term => {
|
||||
Object.defineProperty(context, term, {
|
||||
get () { // eslint-disable-line getter-return
|
||||
process.exit();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// "clear" clears the screen
|
||||
Object.defineProperty(context, 'clear', { get () {
|
||||
process.stdout.write('\u001B[2J\u001B[0;0f');
|
||||
}});
|
||||
Object.defineProperty(context, 'clear', {
|
||||
get () { // eslint-disable-line getter-return
|
||||
process.stdout.write('\u001B[2J\u001B[0;0f');
|
||||
},
|
||||
});
|
||||
|
||||
context.Challenge = require('../website/server/models/challenge').model; // eslint-disable-line global-require
|
||||
context.Group = require('../website/server/models/group').model; // eslint-disable-line global-require
|
||||
context.User = require('../website/server/models/user').model; // eslint-disable-line global-require
|
||||
context.Group = require('../website/server/models/group').model; // eslint-disable-line global-require
|
||||
context.User = require('../website/server/models/user').model; // eslint-disable-line global-require
|
||||
|
||||
const isProd = nconf.get('NODE_ENV') === 'production';
|
||||
const mongooseOptions = !isProd ? {} : {
|
||||
@@ -30,14 +34,14 @@ let improveRepl = (context) => {
|
||||
mongoose.connect(
|
||||
nconf.get('NODE_DB_URI'),
|
||||
mongooseOptions,
|
||||
(err) => {
|
||||
err => {
|
||||
if (err) throw err;
|
||||
logger.info('Connected with Mongoose');
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
gulp.task('console', (done) => {
|
||||
gulp.task('console', done => {
|
||||
improveRepl(repl.start({
|
||||
prompt: 'Habitica > ',
|
||||
}).context);
|
||||
|
||||
@@ -4,29 +4,29 @@ import spritesmith from 'gulp.spritesmith';
|
||||
import clean from 'rimraf';
|
||||
import sizeOf from 'image-size';
|
||||
import mergeStream from 'merge-stream';
|
||||
import {basename} from 'path';
|
||||
import {sync} from 'glob';
|
||||
import {each} from 'lodash';
|
||||
import { basename } from 'path';
|
||||
import { sync } from 'glob';
|
||||
import { each } from 'lodash';
|
||||
import vinylBuffer from 'vinyl-buffer';
|
||||
|
||||
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
|
||||
const MAX_SPRITESHEET_SIZE = 1024 * 1024 * 3;
|
||||
|
||||
const IMG_DIST_PATH = 'website/client/assets/images/sprites/';
|
||||
const CSS_DIST_PATH = 'website/client/assets/css/sprites/';
|
||||
const IMG_DIST_PATH = 'website/client/src/assets/images/sprites/';
|
||||
const CSS_DIST_PATH = 'website/client/src/assets/css/sprites/';
|
||||
|
||||
function checkForSpecialTreatment (name) {
|
||||
let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame|^eyewear_special_\w+HalfMoon/;
|
||||
const regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame|^eyewear_special_\w+HalfMoon/;
|
||||
return name.match(regex) || name === 'head_0';
|
||||
}
|
||||
|
||||
function calculateImgDimensions (img, addPadding) {
|
||||
let dims = sizeOf(img);
|
||||
|
||||
let requiresSpecialTreatment = checkForSpecialTreatment(img);
|
||||
const requiresSpecialTreatment = checkForSpecialTreatment(img);
|
||||
if (requiresSpecialTreatment) {
|
||||
let newWidth = dims.width < 90 ? 90 : dims.width;
|
||||
let newHeight = dims.height < 90 ? 90 : dims.height;
|
||||
const newWidth = dims.width < 90 ? 90 : dims.width;
|
||||
const newHeight = dims.height < 90 ? 90 : dims.height;
|
||||
dims = {
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
@@ -41,17 +41,17 @@ function calculateImgDimensions (img, addPadding) {
|
||||
|
||||
if (!dims.width || !dims.height) console.error('MISSING DIMENSIONS:', dims); // eslint-disable-line no-console
|
||||
|
||||
let totalPixelSize = dims.width * dims.height + padding;
|
||||
const totalPixelSize = dims.width * dims.height + padding;
|
||||
|
||||
return totalPixelSize;
|
||||
}
|
||||
|
||||
function calculateSpritesheetsSrcIndicies (src) {
|
||||
let totalPixels = 0;
|
||||
let slices = [0];
|
||||
const slices = [0];
|
||||
|
||||
each(src, (img, index) => {
|
||||
let imageSize = calculateImgDimensions(img, true);
|
||||
const imageSize = calculateImgDimensions(img, true);
|
||||
totalPixels += imageSize;
|
||||
|
||||
if (totalPixels > MAX_SPRITESHEET_SIZE) {
|
||||
@@ -64,37 +64,35 @@ function calculateSpritesheetsSrcIndicies (src) {
|
||||
}
|
||||
|
||||
function cssVarMap (sprite) {
|
||||
// For hair, skins, beards, etc. we want to output a '.customize-options.WHATEVER' class, which works as a
|
||||
// 60x60 image pointing at the proper part of the 90x90 sprite.
|
||||
// For hair, skins, beards, etc. we want to output a '.customize-options.WHATEVER' class,
|
||||
// which works as a 60x60 image pointing at the proper part of the 90x90 sprite.
|
||||
// We set up the custom info here, and the template makes use of it.
|
||||
let requiresSpecialTreatment = checkForSpecialTreatment(sprite.name);
|
||||
const requiresSpecialTreatment = checkForSpecialTreatment(sprite.name);
|
||||
if (requiresSpecialTreatment) {
|
||||
sprite.custom = {
|
||||
px: {
|
||||
offsetX: `-${ sprite.x + 25 }px`,
|
||||
offsetY: `-${ sprite.y + 15 }px`,
|
||||
offsetX: `-${sprite.x + 25}px`,
|
||||
offsetY: `-${sprite.y + 15}px`,
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
},
|
||||
};
|
||||
}
|
||||
if (sprite.name.indexOf('shirt') !== -1)
|
||||
sprite.custom.px.offsetY = `-${ sprite.y + 35 }px`; // even more for shirts
|
||||
if (sprite.name.indexOf('shirt') !== -1) sprite.custom.px.offsetY = `-${sprite.y + 35}px`; // even more for shirts
|
||||
if (sprite.name.indexOf('hair_base') !== -1) {
|
||||
let styleArray = sprite.name.split('_').slice(2, 3);
|
||||
if (Number(styleArray[0]) > 14)
|
||||
sprite.custom.px.offsetY = `-${ sprite.y }px`; // don't crop updos
|
||||
const styleArray = sprite.name.split('_').slice(2, 3);
|
||||
if (Number(styleArray[0]) > 14) sprite.custom.px.offsetY = `-${sprite.y}px`; // don't crop updos
|
||||
}
|
||||
}
|
||||
|
||||
function createSpritesStream (name, src) {
|
||||
let spritesheetSliceIndicies = calculateSpritesheetsSrcIndicies(src);
|
||||
let stream = mergeStream();
|
||||
const spritesheetSliceIndicies = calculateSpritesheetsSrcIndicies(src);
|
||||
const stream = mergeStream();
|
||||
|
||||
each(spritesheetSliceIndicies, (start, index) => {
|
||||
let slicedSrc = src.slice(start, spritesheetSliceIndicies[index + 1]);
|
||||
const slicedSrc = src.slice(start, spritesheetSliceIndicies[index + 1]);
|
||||
|
||||
let spriteData = gulp.src(slicedSrc)
|
||||
const spriteData = gulp.src(slicedSrc)
|
||||
.pipe(spritesmith({
|
||||
imgName: `spritesmith-${name}-${index}.png`,
|
||||
cssName: `spritesmith-${name}-${index}.css`,
|
||||
@@ -104,12 +102,12 @@ function createSpritesStream (name, src) {
|
||||
cssVarMap,
|
||||
}));
|
||||
|
||||
let imgStream = spriteData.img
|
||||
const imgStream = spriteData.img
|
||||
.pipe(vinylBuffer())
|
||||
.pipe(imagemin())
|
||||
.pipe(gulp.dest(IMG_DIST_PATH));
|
||||
|
||||
let cssStream = spriteData.css
|
||||
const cssStream = spriteData.css
|
||||
.pipe(gulp.dest(CSS_DIST_PATH));
|
||||
|
||||
stream.add(imgStream);
|
||||
@@ -120,32 +118,32 @@ function createSpritesStream (name, src) {
|
||||
}
|
||||
|
||||
gulp.task('sprites:main', () => {
|
||||
let mainSrc = sync('website/raw_sprites/spritesmith/**/*.png');
|
||||
const mainSrc = sync('website/raw_sprites/spritesmith/**/*.png');
|
||||
return createSpritesStream('main', mainSrc);
|
||||
});
|
||||
|
||||
gulp.task('sprites:largeSprites', () => {
|
||||
let largeSrc = sync('website/raw_sprites/spritesmith_large/**/*.png');
|
||||
const largeSrc = sync('website/raw_sprites/spritesmith_large/**/*.png');
|
||||
return createSpritesStream('largeSprites', largeSrc);
|
||||
});
|
||||
|
||||
gulp.task('sprites:clean', (done) => {
|
||||
gulp.task('sprites:clean', done => {
|
||||
clean(`${IMG_DIST_PATH}spritesmith*,${CSS_DIST_PATH}spritesmith*}`, done);
|
||||
});
|
||||
|
||||
gulp.task('sprites:checkCompiledDimensions', gulp.series('sprites:main', 'sprites:largeSprites', (done) => {
|
||||
gulp.task('sprites:checkCompiledDimensions', gulp.series('sprites:main', 'sprites:largeSprites', done => {
|
||||
console.log('Verifiying that images do not exceed max dimensions'); // eslint-disable-line no-console
|
||||
|
||||
let numberOfSheetsThatAreTooBig = 0;
|
||||
|
||||
let distSpritesheets = sync(`${IMG_DIST_PATH}*.png`);
|
||||
const distSpritesheets = sync(`${IMG_DIST_PATH}*.png`);
|
||||
|
||||
each(distSpritesheets, (img) => {
|
||||
let spriteSize = calculateImgDimensions(img);
|
||||
each(distSpritesheets, img => {
|
||||
const spriteSize = calculateImgDimensions(img);
|
||||
|
||||
if (spriteSize > MAX_SPRITESHEET_SIZE) {
|
||||
numberOfSheetsThatAreTooBig++;
|
||||
let name = basename(img, '.png');
|
||||
numberOfSheetsThatAreTooBig += 1;
|
||||
const name = basename(img, '.png');
|
||||
console.error(`WARNING: ${name} might be too big - ${spriteSize} > ${MAX_SPRITESHEET_SIZE}`); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
@@ -155,7 +153,8 @@ gulp.task('sprites:checkCompiledDimensions', gulp.series('sprites:main', 'sprite
|
||||
console.error( // eslint-disable-line no-console
|
||||
`${numberOfSheetsThatAreTooBig} sheets might too big for mobile Safari to be able to handle
|
||||
them, but there is a margin of error in these calculations so it is probably okay. Mention
|
||||
this to an admin so they can test a staging site on mobile Safari after your PR is merged.`);
|
||||
this to an admin so they can test a staging site on mobile Safari after your PR is merged.`,
|
||||
);
|
||||
} else {
|
||||
console.log('All images are within the correct dimensions'); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import gulp from 'gulp';
|
||||
import nodemon from 'gulp-nodemon';
|
||||
|
||||
let pkg = require('../package.json');
|
||||
import pkg from '../package.json';
|
||||
|
||||
gulp.task('nodemon', (done) => {
|
||||
gulp.task('nodemon', done => {
|
||||
nodemon({
|
||||
script: pkg.main,
|
||||
ignore: [
|
||||
'website/client-old/*',
|
||||
'website/views/*',
|
||||
'common/dist/script/content/*',
|
||||
],
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -1,60 +1,59 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { exec } from 'child_process';
|
||||
import gulp from 'gulp';
|
||||
import os from 'os';
|
||||
import nconf from 'nconf';
|
||||
import {
|
||||
pipe,
|
||||
} from './taskHelper';
|
||||
import mongoose from 'mongoose';
|
||||
import { exec } from 'child_process';
|
||||
import gulp from 'gulp';
|
||||
import os from 'os';
|
||||
import nconf from 'nconf';
|
||||
} from './taskHelper';
|
||||
|
||||
// TODO rewrite
|
||||
|
||||
const TEST_SERVER_PORT = 3003;
|
||||
const TEST_SERVER_PORT = 3003;
|
||||
let server;
|
||||
|
||||
const TEST_DB_URI = nconf.get('TEST_DB_URI');
|
||||
const TEST_DB_URI = nconf.get('TEST_DB_URI');
|
||||
|
||||
const SANITY_TEST_COMMAND = 'npm run test:sanity';
|
||||
const COMMON_TEST_COMMAND = 'npm run test:common';
|
||||
const CONTENT_TEST_COMMAND = 'npm run test:content';
|
||||
const CONTENT_OPTIONS = {maxBuffer: 1024 * 500};
|
||||
const CONTENT_OPTIONS = { maxBuffer: 1024 * 500 };
|
||||
|
||||
/* Helper methods for reporting test summary */
|
||||
let testResults = [];
|
||||
let testCount = (stdout, regexp) => {
|
||||
let match = stdout.match(regexp);
|
||||
return parseInt(match && match[1] || 0, 10);
|
||||
const testResults = [];
|
||||
const testCount = (stdout, regexp) => {
|
||||
const match = stdout.match(regexp);
|
||||
return parseInt(match && (match[1] || 0), 10);
|
||||
};
|
||||
|
||||
let testBin = (string, additionalEnvVariables = '') => {
|
||||
const testBin = (string, additionalEnvVariables = '') => {
|
||||
if (os.platform() === 'win32') {
|
||||
if (additionalEnvVariables !== '') {
|
||||
additionalEnvVariables = additionalEnvVariables.split(' ').join('&&set ');
|
||||
additionalEnvVariables = `set ${additionalEnvVariables}&&`;
|
||||
additionalEnvVariables = additionalEnvVariables.split(' ').join('&&set '); // eslint-disable-line no-param-reassign
|
||||
additionalEnvVariables = `set ${additionalEnvVariables}&&`; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
return `set NODE_ENV=test&&${additionalEnvVariables}${string}`;
|
||||
} else {
|
||||
return `NODE_ENV=test ${additionalEnvVariables} ${string}`;
|
||||
}
|
||||
return `NODE_ENV=test ${additionalEnvVariables} ${string}`;
|
||||
};
|
||||
|
||||
gulp.task('test:nodemon', gulp.series(function setupNodemon (done) {
|
||||
gulp.task('test:nodemon', gulp.series(done => {
|
||||
process.env.PORT = TEST_SERVER_PORT; // eslint-disable-line no-process-env
|
||||
process.env.NODE_DB_URI = TEST_DB_URI; // eslint-disable-line no-process-env
|
||||
done();
|
||||
}, 'nodemon'));
|
||||
|
||||
gulp.task('test:prepare:mongo', (cb) => {
|
||||
mongoose.connect(TEST_DB_URI, (err) => {
|
||||
gulp.task('test:prepare:mongo', cb => {
|
||||
mongoose.connect(TEST_DB_URI, err => {
|
||||
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
|
||||
mongoose.connection.dropDatabase((err2) => {
|
||||
return mongoose.connection.dropDatabase(err2 => {
|
||||
if (err2) return cb(err2);
|
||||
mongoose.connection.close(cb);
|
||||
return mongoose.connection.close(cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('test:prepare:server', gulp.series('test:prepare:mongo', (done) => {
|
||||
gulp.task('test:prepare:server', gulp.series('test:prepare:mongo', done => {
|
||||
if (!server) {
|
||||
server = exec(testBin('node ./website/server/index.js', `NODE_DB_URI=${TEST_DB_URI} PORT=${TEST_SERVER_PORT}`), (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
@@ -73,45 +72,43 @@ gulp.task('test:prepare:build', gulp.series('build', done => done()));
|
||||
gulp.task('test:prepare', gulp.series(
|
||||
'test:prepare:build',
|
||||
'test:prepare:mongo',
|
||||
done => done()
|
||||
done => done(),
|
||||
));
|
||||
|
||||
gulp.task('test:sanity', (cb) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:sanity', cb => {
|
||||
const runner = exec(
|
||||
testBin(SANITY_TEST_COMMAND),
|
||||
(err) => {
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
cb();
|
||||
}
|
||||
},
|
||||
);
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:common', gulp.series('test:prepare:build', (cb) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:common', gulp.series('test:prepare:build', cb => {
|
||||
const runner = exec(
|
||||
testBin(COMMON_TEST_COMMAND),
|
||||
(err) => {
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
cb();
|
||||
}
|
||||
},
|
||||
);
|
||||
pipe(runner);
|
||||
}));
|
||||
|
||||
gulp.task('test:common:clean', (cb) => {
|
||||
gulp.task('test:common:clean', cb => {
|
||||
pipe(exec(testBin(COMMON_TEST_COMMAND), () => cb()));
|
||||
});
|
||||
|
||||
gulp.task('test:common:watch', gulp.series('test:common:clean', () => {
|
||||
return gulp.watch(['common/script/**/*', 'test/common/**/*'], gulp.series('test:common:clean', done => done()));
|
||||
}));
|
||||
gulp.task('test:common:watch', gulp.series('test:common:clean', () => gulp.watch(['common/script/**/*', 'test/common/**/*'], gulp.series('test:common:clean', done => done()))));
|
||||
|
||||
gulp.task('test:common:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:common:safe', gulp.series('test:prepare:build', cb => {
|
||||
const runner = exec(
|
||||
testBin(COMMON_TEST_COMMAND),
|
||||
(err, stdout) => { // eslint-disable-line handle-callback-err
|
||||
testResults.push({
|
||||
@@ -121,38 +118,36 @@ gulp.task('test:common:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
pend: testCount(stdout, /(\d+) pending/),
|
||||
});
|
||||
cb();
|
||||
}
|
||||
},
|
||||
);
|
||||
pipe(runner);
|
||||
}));
|
||||
|
||||
gulp.task('test:content', gulp.series('test:prepare:build', (cb) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:content', gulp.series('test:prepare:build', cb => {
|
||||
const runner = exec(
|
||||
testBin(CONTENT_TEST_COMMAND),
|
||||
CONTENT_OPTIONS,
|
||||
(err) => {
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
cb();
|
||||
}
|
||||
},
|
||||
);
|
||||
pipe(runner);
|
||||
}));
|
||||
|
||||
gulp.task('test:content:clean', (cb) => {
|
||||
gulp.task('test:content:clean', cb => {
|
||||
pipe(exec(testBin(CONTENT_TEST_COMMAND), CONTENT_OPTIONS, () => cb()));
|
||||
});
|
||||
|
||||
gulp.task('test:content:watch', gulp.series('test:content:clean', () => {
|
||||
return gulp.watch(['common/script/content/**', 'test/**'], gulp.series('test:content:clean', done => done()));
|
||||
}));
|
||||
gulp.task('test:content:watch', gulp.series('test:content:clean', () => gulp.watch(['common/script/content/**', 'test/**'], gulp.series('test:content:clean', done => done()))));
|
||||
|
||||
gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:content:safe', gulp.series('test:prepare:build', cb => {
|
||||
const runner = exec(
|
||||
testBin(CONTENT_TEST_COMMAND),
|
||||
CONTENT_OPTIONS,
|
||||
(err, stdout) => { // eslint-disable-line handle-callback-err
|
||||
(err, stdout) => { // eslint-disable-line handle-callback-err
|
||||
testResults.push({
|
||||
suite: 'Content Specs\t',
|
||||
pass: testCount(stdout, /(\d+) passing/),
|
||||
@@ -160,81 +155,77 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
pend: testCount(stdout, /(\d+) pending/),
|
||||
});
|
||||
cb();
|
||||
}
|
||||
},
|
||||
);
|
||||
pipe(runner);
|
||||
}));
|
||||
|
||||
gulp.task('test:api:unit', (done) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:api:unit', done => {
|
||||
const runner = exec(
|
||||
testBin('istanbul cover --dir coverage/api-unit node_modules/mocha/bin/_mocha -- test/api/unit --recursive --require ./test/helpers/start-server'),
|
||||
(err) => {
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api:unit:watch', () => {
|
||||
return gulp.watch(['website/server/libs/*', 'test/api/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done()));
|
||||
});
|
||||
gulp.task('test:api:unit:watch', () => gulp.watch(['website/server/libs/*', 'test/api/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done())));
|
||||
|
||||
gulp.task('test:api-v3:integration', (done) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:api-v3:integration', done => {
|
||||
const runner = exec(
|
||||
testBin('istanbul cover --dir coverage/api-v3-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/integration --recursive --require ./test/helpers/start-server'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => {
|
||||
{ maxBuffer: 500 * 1024 },
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api-v3:integration:watch', () => {
|
||||
return gulp.watch([
|
||||
'website/server/controllers/api-v3/**/*', 'common/script/ops/*', 'website/server/libs/*.js',
|
||||
'test/api/v3/integration/**/*',
|
||||
], gulp.series('test:api-v3:integration', done => done()));
|
||||
});
|
||||
gulp.task('test:api-v3:integration:watch', () => gulp.watch([
|
||||
'website/server/controllers/api-v3/**/*', 'common/script/ops/*', 'website/server/libs/*.js',
|
||||
'test/api/v3/integration/**/*',
|
||||
], gulp.series('test:api-v3:integration', done => done())));
|
||||
|
||||
gulp.task('test:api-v3:integration:separate-server', (done) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:api-v3:integration:separate-server', done => {
|
||||
const runner = exec(
|
||||
testBin('mocha test/api/v3/integration --recursive --require ./test/helpers/start-server', 'LOAD_SERVER=0'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => done(err)
|
||||
{ maxBuffer: 500 * 1024 },
|
||||
err => done(err),
|
||||
);
|
||||
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api-v4:integration', (done) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:api-v4:integration', done => {
|
||||
const runner = exec(
|
||||
testBin('istanbul cover --dir coverage/api-v4-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v4 --recursive --require ./test/helpers/start-server'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => {
|
||||
{ maxBuffer: 500 * 1024 },
|
||||
err => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
pipe(runner);
|
||||
});
|
||||
|
||||
gulp.task('test:api-v4:integration:separate-server', (done) => {
|
||||
let runner = exec(
|
||||
gulp.task('test:api-v4:integration:separate-server', done => {
|
||||
const runner = exec(
|
||||
testBin('mocha test/api/v4 --recursive --require ./test/helpers/start-server', 'LOAD_SERVER=0'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => done(err)
|
||||
{ maxBuffer: 500 * 1024 },
|
||||
err => done(err),
|
||||
);
|
||||
|
||||
pipe(runner);
|
||||
@@ -247,11 +238,11 @@ gulp.task('test', gulp.series(
|
||||
'test:api:unit',
|
||||
'test:api-v3:integration',
|
||||
'test:api-v4:integration',
|
||||
done => done()
|
||||
done => done(),
|
||||
));
|
||||
|
||||
gulp.task('test:api-v3', gulp.series(
|
||||
'test:api:unit',
|
||||
'test:api-v3:integration',
|
||||
done => done()
|
||||
done => done(),
|
||||
));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import _ from 'lodash';
|
||||
import gulp from 'gulp';
|
||||
import fs from 'fs';
|
||||
import _ from 'lodash';
|
||||
import gulp from 'gulp';
|
||||
import { postToSlack, conf } from './taskHelper';
|
||||
|
||||
const SLACK_CONFIG = {
|
||||
@@ -14,7 +14,7 @@ const ENGLISH_LOCALE = `${LOCALES}en/`;
|
||||
|
||||
|
||||
function getArrayOfLanguages () {
|
||||
let languages = fs.readdirSync(LOCALES);
|
||||
const languages = fs.readdirSync(LOCALES);
|
||||
languages.shift(); // Remove README.md from array of languages
|
||||
|
||||
return languages;
|
||||
@@ -23,18 +23,16 @@ function getArrayOfLanguages () {
|
||||
const ALL_LANGUAGES = getArrayOfLanguages();
|
||||
|
||||
function stripOutNonJsonFiles (collection) {
|
||||
let onlyJson = _.filter(collection, (file) => {
|
||||
return file.match(/[a-zA-Z]*\.json/);
|
||||
});
|
||||
const onlyJson = _.filter(collection, file => file.match(/[a-zA-Z]*\.json/));
|
||||
|
||||
return onlyJson;
|
||||
}
|
||||
|
||||
function eachTranslationFile (languages, cb) {
|
||||
let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
||||
const jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
||||
|
||||
_.each(languages, (lang) => {
|
||||
_.each(jsonFiles, (filename) => {
|
||||
_.each(languages, lang => {
|
||||
_.each(jsonFiles, filename => {
|
||||
let parsedTranslationFile;
|
||||
try {
|
||||
const translationFile = fs.readFileSync(`${LOCALES}${lang}/${filename}`);
|
||||
@@ -43,10 +41,10 @@ function eachTranslationFile (languages, cb) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
let englishFile = fs.readFileSync(ENGLISH_LOCALE + filename);
|
||||
let parsedEnglishFile = JSON.parse(englishFile);
|
||||
const englishFile = fs.readFileSync(ENGLISH_LOCALE + filename);
|
||||
const parsedEnglishFile = JSON.parse(englishFile);
|
||||
|
||||
cb(null, lang, filename, parsedEnglishFile, parsedTranslationFile);
|
||||
return cb(null, lang, filename, parsedEnglishFile, parsedTranslationFile);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -71,9 +69,9 @@ function formatMessageForPosting (msg, items) {
|
||||
}
|
||||
|
||||
function getStringsWith (json, interpolationRegex) {
|
||||
let strings = {};
|
||||
const strings = {};
|
||||
|
||||
_.each(json, (fileName) => {
|
||||
_.each(json, fileName => {
|
||||
const rawFile = fs.readFileSync(ENGLISH_LOCALE + fileName);
|
||||
const parsedJson = JSON.parse(rawFile);
|
||||
|
||||
@@ -93,66 +91,69 @@ const malformedStringExceptions = {
|
||||
feedPet: true,
|
||||
};
|
||||
|
||||
gulp.task('transifex:missingFiles', (done) => {
|
||||
let missingStrings = [];
|
||||
gulp.task('transifex:missingFiles', done => {
|
||||
const missingStrings = [];
|
||||
|
||||
eachTranslationFile(ALL_LANGUAGES, (error) => {
|
||||
eachTranslationFile(ALL_LANGUAGES, error => {
|
||||
if (error) {
|
||||
missingStrings.push(error.path);
|
||||
}
|
||||
});
|
||||
|
||||
if (!_.isEmpty(missingStrings)) {
|
||||
let message = 'the following files were missing from the translations folder';
|
||||
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||
const message = 'the following files were missing from the translations folder';
|
||||
const formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('transifex:missingStrings', (done) => {
|
||||
let missingStrings = [];
|
||||
gulp.task('transifex:missingStrings', done => {
|
||||
const missingStrings = [];
|
||||
|
||||
eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => {
|
||||
eachTranslationString(ALL_LANGUAGES, (lang, filename, key, englishString, translationString) => {
|
||||
if (!translationString) {
|
||||
let errorString = `${language} - ${filename} - ${key} - ${englishString}`;
|
||||
const errorString = `${lang} - ${filename} - ${key} - ${englishString}`;
|
||||
missingStrings.push(errorString);
|
||||
}
|
||||
});
|
||||
|
||||
if (!_.isEmpty(missingStrings)) {
|
||||
let message = 'The following strings are not translated';
|
||||
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||
const message = 'The following strings are not translated';
|
||||
const formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('transifex:malformedStrings', (done) => {
|
||||
let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
||||
let interpolationRegex = /<%= [a-zA-Z]* %>/g;
|
||||
let stringsToLookFor = getStringsWith(jsonFiles, interpolationRegex);
|
||||
gulp.task('transifex:malformedStrings', done => {
|
||||
const jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
||||
const interpolationRegex = /<%= [a-zA-Z]* %>/g;
|
||||
const stringsToLookFor = getStringsWith(jsonFiles, interpolationRegex);
|
||||
|
||||
let stringsWithMalformedInterpolations = [];
|
||||
let stringsWithIncorrectNumberOfInterpolations = [];
|
||||
const stringsWithMalformedInterpolations = [];
|
||||
const stringsWithIncorrectNumberOfInterpolations = [];
|
||||
|
||||
_.each(ALL_LANGUAGES, (lang) => {
|
||||
_.each(ALL_LANGUAGES, lang => {
|
||||
_.each(stringsToLookFor, (strings, filename) => {
|
||||
let translationFile = fs.readFileSync(`${LOCALES}${lang}/${filename}`);
|
||||
let parsedTranslationFile = JSON.parse(translationFile);
|
||||
const translationFile = fs.readFileSync(`${LOCALES}${lang}/${filename}`);
|
||||
const parsedTranslationFile = JSON.parse(translationFile);
|
||||
|
||||
_.each(strings, (value, key) => { // eslint-disable-line max-nested-callbacks
|
||||
let translationString = parsedTranslationFile[key];
|
||||
const translationString = parsedTranslationFile[key];
|
||||
if (!translationString) return;
|
||||
|
||||
let englishOccurences = stringsToLookFor[filename][key];
|
||||
let translationOccurences = translationString.match(interpolationRegex);
|
||||
const englishOccurences = stringsToLookFor[filename][key];
|
||||
const translationOccurences = translationString.match(interpolationRegex);
|
||||
|
||||
if (!translationOccurences) {
|
||||
let malformedString = `${lang} - ${filename} - ${key} - ${translationString}`;
|
||||
const malformedString = `${lang} - ${filename} - ${key} - ${translationString}`;
|
||||
stringsWithMalformedInterpolations.push(malformedString);
|
||||
} else if (englishOccurences.length !== translationOccurences.length && !malformedStringExceptions[key]) {
|
||||
let missingInterpolationString = `${lang} - ${filename} - ${key} - ${translationString}`;
|
||||
} else if (
|
||||
englishOccurences.length !== translationOccurences.length
|
||||
&& !malformedStringExceptions[key]
|
||||
) {
|
||||
const missingInterpolationString = `${lang} - ${filename} - ${key} - ${translationString}`;
|
||||
stringsWithIncorrectNumberOfInterpolations.push(missingInterpolationString);
|
||||
}
|
||||
});
|
||||
@@ -160,14 +161,17 @@ gulp.task('transifex:malformedStrings', (done) => {
|
||||
});
|
||||
|
||||
if (!_.isEmpty(stringsWithMalformedInterpolations)) {
|
||||
let message = 'The following strings have malformed or missing interpolations';
|
||||
let formattedMessage = formatMessageForPosting(message, stringsWithMalformedInterpolations);
|
||||
const message = 'The following strings have malformed or missing interpolations';
|
||||
const formattedMessage = formatMessageForPosting(message, stringsWithMalformedInterpolations);
|
||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||
}
|
||||
|
||||
if (!_.isEmpty(stringsWithIncorrectNumberOfInterpolations)) {
|
||||
let message = 'The following strings have a different number of string interpolations';
|
||||
let formattedMessage = formatMessageForPosting(message, stringsWithIncorrectNumberOfInterpolations);
|
||||
const message = 'The following strings have a different number of string interpolations';
|
||||
const formattedMessage = formatMessageForPosting(
|
||||
message,
|
||||
stringsWithIncorrectNumberOfInterpolations,
|
||||
);
|
||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||
}
|
||||
done();
|
||||
@@ -176,5 +180,5 @@ gulp.task('transifex:malformedStrings', (done) => {
|
||||
gulp.task(
|
||||
'transifex',
|
||||
gulp.series('transifex:missingFiles', 'transifex:missingStrings', 'transifex:malformedStrings'),
|
||||
(done) => done()
|
||||
);
|
||||
done => done(),
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { exec } from 'child_process';
|
||||
import psTree from 'ps-tree';
|
||||
import nconf from 'nconf';
|
||||
import net from 'net';
|
||||
import { post } from 'superagent';
|
||||
import { sync as glob } from 'glob';
|
||||
import Mocha from 'mocha';
|
||||
import { resolve } from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import psTree from 'ps-tree';
|
||||
import nconf from 'nconf';
|
||||
import net from 'net';
|
||||
import { post } from 'superagent';
|
||||
import { sync as glob } from 'glob';
|
||||
import Mocha from 'mocha'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import { resolve } from 'path';
|
||||
|
||||
/*
|
||||
* Get access to configruable values
|
||||
@@ -19,15 +19,15 @@ export const conf = nconf;
|
||||
* its tasks.
|
||||
*/
|
||||
export function kill (proc) {
|
||||
let killProcess = (pid) => {
|
||||
const killProcess = pid => {
|
||||
psTree(pid, (_, pids) => {
|
||||
if (pids.length) {
|
||||
pids.forEach(kill); return;
|
||||
}
|
||||
try {
|
||||
exec(/^win/.test(process.platform) ?
|
||||
`taskkill /PID ${pid} /T /F` :
|
||||
`kill -9 ${pid}`);
|
||||
exec(/^win/.test(process.platform)
|
||||
? `taskkill /PID ${pid} /T /F`
|
||||
: `kill -9 ${pid}`);
|
||||
} catch (e) {
|
||||
console.log(e); // eslint-disable-line no-console
|
||||
}
|
||||
@@ -46,16 +46,15 @@ export function kill (proc) {
|
||||
export function awaitPort (port, max = 60) {
|
||||
return new Promise((rej, res) => {
|
||||
let socket;
|
||||
let timeout;
|
||||
let interval;
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
clearInterval(interval);
|
||||
rej(`Timed out after ${max} seconds`);
|
||||
}, max * 1000);
|
||||
|
||||
interval = setInterval(() => {
|
||||
socket = net.connect({port}, () => {
|
||||
socket = net.connect({ port }, () => {
|
||||
clearInterval(interval);
|
||||
clearTimeout(timeout);
|
||||
socket.destroy();
|
||||
@@ -71,10 +70,10 @@ export function awaitPort (port, max = 60) {
|
||||
* Pipe the child's stdin and stderr to the parent process.
|
||||
*/
|
||||
export function pipe (child) {
|
||||
child.stdout.on('data', (data) => {
|
||||
child.stdout.on('data', data => {
|
||||
process.stdout.write(data);
|
||||
});
|
||||
child.stderr.on('data', (data) => {
|
||||
child.stderr.on('data', data => {
|
||||
process.stderr.write(data);
|
||||
});
|
||||
}
|
||||
@@ -83,7 +82,7 @@ export function pipe (child) {
|
||||
* Post request to notify configured slack channel
|
||||
*/
|
||||
export function postToSlack (msg, config = {}) {
|
||||
let slackUrl = nconf.get('SLACK_URL');
|
||||
const slackUrl = nconf.get('SLACK_URL');
|
||||
|
||||
if (!slackUrl) {
|
||||
console.error('No slack post url specified. Your message was:'); // eslint-disable-line no-console
|
||||
@@ -99,7 +98,7 @@ export function postToSlack (msg, config = {}) {
|
||||
text: msg,
|
||||
icon_emoji: `:${config.emoji || 'gulp'}:`, // eslint-disable-line camelcase
|
||||
})
|
||||
.end((err) => {
|
||||
.end(err => {
|
||||
if (err) console.error('Unable to post to slack', err); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
@@ -107,15 +106,15 @@ export function postToSlack (msg, config = {}) {
|
||||
export function runMochaTests (files, server, cb) {
|
||||
require('../test/helpers/globals.helper'); // eslint-disable-line global-require
|
||||
|
||||
let mocha = new Mocha({reporter: 'spec'});
|
||||
let tests = glob(files);
|
||||
const mocha = new Mocha({ reporter: 'spec' });
|
||||
const tests = glob(files);
|
||||
|
||||
tests.forEach((test) => {
|
||||
tests.forEach(test => {
|
||||
delete require.cache[resolve(test)];
|
||||
mocha.addFile(test);
|
||||
});
|
||||
|
||||
mocha.run((numberOfFailures) => {
|
||||
mocha.run(numberOfFailures => {
|
||||
if (!process.env.RUN_INTEGRATION_TEST_FOREVER) { // eslint-disable-line no-process-env
|
||||
if (server) kill(server);
|
||||
process.exit(numberOfFailures);
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* directory, and it will automatically be included.
|
||||
*/
|
||||
|
||||
require('babel-register');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
require('@babel/register');
|
||||
|
||||
const gulp = require('gulp');
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"root": false,
|
||||
"rules": {
|
||||
"no-console": 0,
|
||||
"no-use-before-define": ["error", { "functions": false }]
|
||||
}
|
||||
}
|
||||
8
migrations/.eslintrc.js
Normal file
8
migrations/.eslintrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
module.exports = {
|
||||
root: false,
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'no-use-before-define': ['error', { functions: false }]
|
||||
}
|
||||
}
|
||||
104
migrations/archive/2019/20190917_pet_color_achievements.js
Normal file
104
migrations/archive/2019/20190917_pet_color_achievements.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190917_pet_color_achievements';
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set = {
|
||||
migration: MIGRATION_NAME,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.pets) {
|
||||
const pets = user.items.pets;
|
||||
if (pets['Wolf-Base'] > 0
|
||||
&& pets['TigerCub-Base'] > 0
|
||||
&& pets['PandaCub-Base'] > 0
|
||||
&& pets['LionCub-Base'] > 0
|
||||
&& pets['Fox-Base'] > 0
|
||||
&& pets['FlyingPig-Base'] > 0
|
||||
&& pets['Dragon-Base'] > 0
|
||||
&& pets['Cactus-Base'] > 0
|
||||
&& pets['BearCub-Base'] > 0) {
|
||||
set['achievements.backToBasics'] = true;
|
||||
}
|
||||
if (pets['Wolf-Desert'] > 0
|
||||
&& pets['TigerCub-Desert'] > 0
|
||||
&& pets['PandaCub-Desert'] > 0
|
||||
&& pets['LionCub-Desert'] > 0
|
||||
&& pets['Fox-Desert'] > 0
|
||||
&& pets['FlyingPig-Desert'] > 0
|
||||
&& pets['Dragon-Desert'] > 0
|
||||
&& pets['Cactus-Desert'] > 0
|
||||
&& pets['BearCub-Desert'] > 0) {
|
||||
set['achievements.dustDevil'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (user && user.items && user.items.mounts) {
|
||||
const mounts = user.items.mounts;
|
||||
if (mounts['Wolf-Base']
|
||||
&& mounts['TigerCub-Base']
|
||||
&& mounts['PandaCub-Base']
|
||||
&& mounts['LionCub-Base']
|
||||
&& mounts['Fox-Base']
|
||||
&& mounts['FlyingPig-Base']
|
||||
&& mounts['Dragon-Base']
|
||||
&& mounts['Cactus-Base']
|
||||
&& mounts['BearCub-Base'] ) {
|
||||
set['achievements.allYourBase'] = true;
|
||||
}
|
||||
if (mounts['Wolf-Desert']
|
||||
&& mounts['TigerCub-Desert']
|
||||
&& mounts['PandaCub-Desert']
|
||||
&& mounts['LionCub-Desert']
|
||||
&& mounts['Fox-Desert']
|
||||
&& mounts['FlyingPig-Desert']
|
||||
&& mounts['Dragon-Desert']
|
||||
&& mounts['Cactus-Desert']
|
||||
&& mounts['BearCub-Desert'] ) {
|
||||
set['achievements.aridAuthority'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({ _id: user._id }, { $set: set }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2019-09-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1]._id,
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
67
migrations/archive/2019/20190927_kickstarter.js
Normal file
67
migrations/archive/2019/20190927_kickstarter.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190927_kickstarter';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
const set = {};
|
||||
let push = {pinnedItems: {$each: []}};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
set['achievements.ks2019'] = true;
|
||||
|
||||
// set['items.gear.owned.armor_special_ks2019'] = false;
|
||||
// push.pinnedItems.$each.push({type: 'marketGear', path: 'gear.flat.armor_special_ks2019', _id: uuid()});
|
||||
set['items.gear.owned.head_special_ks2019'] = false;
|
||||
push.pinnedItems.$each.push({type: 'marketGear', path: 'gear.flat.head_special_ks2019', _id: uuid()});
|
||||
// set['items.gear.owned.shield_special_ks2019'] = false;
|
||||
// push.pinnedItems.$each.push({type: 'marketGear', path: 'gear.flat.shield_special_ks2019', _id: uuid()});
|
||||
// set['items.gear.owned.weapon_special_ks2019'] = false;
|
||||
// push.pinnedItems.$each.push({type: 'marketGear', path: 'gear.flat.weapon_special_ks2019', _id: uuid()});
|
||||
set['items.gear.owned.eyewear_special_ks2019'] = false;
|
||||
push.pinnedItems.$each.push({type: 'marketGear', path: 'gear.flat.eyewear_special_ks2019', _id: uuid()});
|
||||
// set['items.pets.Gryphon-Gryphatrice'] = 5;
|
||||
// set['items.mounts.Gryphon-Gryphatrice'] = true;
|
||||
|
||||
return await User.update({_id: user._id}, {$set: set, $push: push}).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.local.lowerCaseUsername': {$in: []},
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
82
migrations/archive/2019/20191022_pet_color_achievements.js
Normal file
82
migrations/archive/2019/20191022_pet_color_achievements.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20191022_pet_color_achievements';
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set = {
|
||||
migration: MIGRATION_NAME,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.pets) {
|
||||
const pets = user.items.pets;
|
||||
if (pets['Wolf-Zombie'] > 0
|
||||
&& pets['TigerCub-Zombie'] > 0
|
||||
&& pets['PandaCub-Zombie'] > 0
|
||||
&& pets['LionCub-Zombie'] > 0
|
||||
&& pets['Fox-Zombie'] > 0
|
||||
&& pets['FlyingPig-Zombie'] > 0
|
||||
&& pets['Dragon-Zombie'] > 0
|
||||
&& pets['Cactus-Zombie'] > 0
|
||||
&& pets['BearCub-Zombie'] > 0) {
|
||||
set['achievements.monsterMagus'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (user && user.items && user.items.mounts) {
|
||||
const mounts = user.items.mounts;
|
||||
if (mounts['Wolf-Zombie']
|
||||
&& mounts['TigerCub-Zombie']
|
||||
&& mounts['PandaCub-Zombie']
|
||||
&& mounts['LionCub-Zombie']
|
||||
&& mounts['Fox-Zombie']
|
||||
&& mounts['FlyingPig-Zombie']
|
||||
&& mounts['Dragon-Zombie']
|
||||
&& mounts['Cactus-Zombie']
|
||||
&& mounts['BearCub-Zombie'] ) {
|
||||
set['achievements.undeadUndertaker'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({ _id: user._id }, { $set: set }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2019-10-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1]._id,
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
82
migrations/archive/2019/20191031_habitoween_ladder.js
Normal file
82
migrations/archive/2019/20191031_habitoween_ladder.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Award Habitoween ladder items to participants in this month's Habitoween festivities
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const MIGRATION_NAME = '20191031_habitoween_ladder'; // Update when running in future years
|
||||
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
const set = {};
|
||||
const inc = {
|
||||
'items.food.Candy_Skeleton': 1,
|
||||
'items.food.Candy_Base': 1,
|
||||
'items.food.Candy_CottonCandyBlue': 1,
|
||||
'items.food.Candy_CottonCandyPink': 1,
|
||||
'items.food.Candy_Shade': 1,
|
||||
'items.food.Candy_White': 1,
|
||||
'items.food.Candy_Golden': 1,
|
||||
'items.food.Candy_Zombie': 1,
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Glow']) {
|
||||
set['items.mounts.JackOLantern-Glow'] = true;
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Ghost']) {
|
||||
set['items.pets.JackOLantern-Glow'] = 5;
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Ghost']) {
|
||||
set['items.mounts.JackOLantern-Ghost'] = true;
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Base']) {
|
||||
set['items.pets.JackOLantern-Ghost'] = 5;
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Base']) {
|
||||
set['items.mounts.JackOLantern-Base'] = true;
|
||||
} else {
|
||||
set['items.pets.JackOLantern-Base'] = 5;
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
return await User.update({_id: user._id}, {$inc: inc, $set: set}).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2019-10-01')},
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -2,14 +2,14 @@ import { model as Challenges } from '../../website/server/models/challenge';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
async function syncChallengeToMembers (challenges) {
|
||||
let challengSyncPromises = challenges.map(async (challenge) => {
|
||||
let users = await User.find({
|
||||
const challengSyncPromises = challenges.map(async challenge => {
|
||||
const users = await User.find({
|
||||
// _id: '',
|
||||
challenges: challenge._id,
|
||||
}).exec();
|
||||
|
||||
let promises = [];
|
||||
users.forEach((user) => {
|
||||
const promises = [];
|
||||
users.forEach(user => {
|
||||
promises.push(challenge.syncToUser(user));
|
||||
promises.push(challenge.save());
|
||||
promises.push(user.save());
|
||||
@@ -18,11 +18,11 @@ async function syncChallengeToMembers (challenges) {
|
||||
return Promise.all(promises);
|
||||
});
|
||||
|
||||
return await Promise.all(challengSyncPromises);
|
||||
return Promise.all(challengSyncPromises);
|
||||
}
|
||||
|
||||
async function syncChallenges (lastChallengeDate) {
|
||||
let query = {
|
||||
const query = {
|
||||
// _id: '',
|
||||
};
|
||||
|
||||
@@ -30,16 +30,16 @@ async function syncChallenges (lastChallengeDate) {
|
||||
query.createdOn = { $lte: lastChallengeDate };
|
||||
}
|
||||
|
||||
let challengesFound = await Challenges.find(query)
|
||||
const challengesFound = await Challenges.find(query)
|
||||
.limit(10)
|
||||
.sort('-createdAt')
|
||||
.exec();
|
||||
|
||||
let syncedChallenges = await syncChallengeToMembers(challengesFound)
|
||||
const syncedChallenges = await syncChallengeToMembers(challengesFound)
|
||||
.catch(reason => console.error(reason));
|
||||
let lastChallenge = challengesFound[challengesFound.length - 1];
|
||||
const lastChallenge = challengesFound[challengesFound.length - 1];
|
||||
if (lastChallenge) syncChallenges(lastChallenge.createdAt);
|
||||
return syncedChallenges;
|
||||
}
|
||||
|
||||
module.exports = syncChallenges;
|
||||
export default syncChallenges;
|
||||
|
||||
@@ -1 +1 @@
|
||||
db.users.update({_id: {$in: ['']}}, {$inc: {balance: 0.5}}, {multi: true});
|
||||
db.users.update({ _id: { $in: [''] } }, { $inc: { balance: 0.5 } }, { multi: true });
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// mongo habitrpg ./node_modules/moment/moment.js ./migrations/cancelSubscription.js
|
||||
|
||||
// For some reason people often to contact me to cancel their sub, rather than do it online. Even when I point them to
|
||||
// For some reason people often to contact me to cancel their sub,
|
||||
// rather than do it online. Even when I point them to
|
||||
// the FAQ (http://goo.gl/1uoPGQ) they insist...
|
||||
|
||||
db.users.update(
|
||||
{_id: ''},
|
||||
{$set: {
|
||||
'purchased.plan.dateTerminated': moment().add('month', 1).toDate(),
|
||||
}}
|
||||
);
|
||||
{ _id: '' },
|
||||
{
|
||||
$set: {
|
||||
'purchased.plan.dateTerminated': moment().add('month', 1).toDate(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Give contrib.level 7+ free subscription for life
|
||||
db.users.update(
|
||||
|
||||
{
|
||||
'contributor.level': {$gte: 7},
|
||||
'contributor.level': { $gte: 7 },
|
||||
'purchased.plan.customerId': null,
|
||||
},
|
||||
|
||||
@@ -18,6 +17,6 @@ db.users.update(
|
||||
},
|
||||
},
|
||||
|
||||
{multi: true}
|
||||
{ multi: true },
|
||||
|
||||
);
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// mongo habitrpg ./node_modules/moment/moment.js ./migrations/current_period_end.js
|
||||
db.users.update(
|
||||
{_id: ''},
|
||||
{$set: {'purchased.plan.dateTerminated': moment().add({days: 7}).toDate()}}
|
||||
);
|
||||
{ _id: '' },
|
||||
{ $set: { 'purchased.plan.dateTerminated': moment().add({ days: 7 }).toDate() } },
|
||||
);
|
||||
|
||||
@@ -39,38 +39,52 @@
|
||||
// needed. Do not miss any of them!
|
||||
|
||||
|
||||
let uuid = '30fb2640-7121-4968-ace5-f385e60ea6c5';
|
||||
const uuid = '30fb2640-7121-4968-ace5-f385e60ea6c5';
|
||||
|
||||
db.users.aggregate([
|
||||
{$match: {
|
||||
_id: uuid,
|
||||
}},
|
||||
{$project: {
|
||||
_id: 0, todos: 1,
|
||||
}},
|
||||
{$unwind: '$todos'},
|
||||
{$group: {
|
||||
_id: { taskid: '$todos.id' },
|
||||
count: { $sum: 1 },
|
||||
}},
|
||||
{$match: {
|
||||
count: { $gt: 1 },
|
||||
}},
|
||||
{$project: {
|
||||
'_id.taskid': 1,
|
||||
}},
|
||||
{$group: {
|
||||
_id: { taskid: '$todos.id' },
|
||||
troublesomeIds: { $addToSet: '$_id.taskid' },
|
||||
}},
|
||||
{$project: {
|
||||
_id: 0,
|
||||
troublesomeIds: 1,
|
||||
}},
|
||||
]).forEach((data) => {
|
||||
{
|
||||
$match: {
|
||||
_id: uuid,
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0, todos: 1,
|
||||
},
|
||||
},
|
||||
{ $unwind: '$todos' },
|
||||
{
|
||||
$group: {
|
||||
_id: { taskid: '$todos.id' },
|
||||
count: { $sum: 1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
$match: {
|
||||
count: { $gt: 1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
'_id.taskid': 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: { taskid: '$todos.id' },
|
||||
troublesomeIds: { $addToSet: '$_id.taskid' },
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
troublesomeIds: 1,
|
||||
},
|
||||
},
|
||||
]).forEach(data => {
|
||||
// print( "\n" ); printjson(data);
|
||||
data.troublesomeIds.forEach((taskid) => {
|
||||
print(`non-unique task: ${ taskid}`);
|
||||
data.troublesomeIds.forEach(taskid => {
|
||||
print(`non-unique task: ${taskid}`); // eslint-disable-line no-restricted-globals
|
||||
db.users.update({
|
||||
_id: uuid,
|
||||
todos: { $elemMatch: { id: taskid } },
|
||||
@@ -81,8 +95,7 @@ db.users.aggregate([
|
||||
});
|
||||
|
||||
db.users.update(
|
||||
{_id: uuid},
|
||||
{$pull: { todos: { id: 'de666' } } },
|
||||
{multi: false }
|
||||
{ _id: uuid },
|
||||
{ $pull: { todos: { id: 'de666' } } },
|
||||
{ multi: false },
|
||||
);
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
let oldId = '';
|
||||
let newId = '';
|
||||
let newUser = db.users.findOne({_id: newId});
|
||||
const oldId = '';
|
||||
const newId = '';
|
||||
const newUser = db.users.findOne({ _id: newId });
|
||||
|
||||
db.users.update({_id: oldId}, {$set: {auth: newUser.auth}});
|
||||
db.users.update({ _id: oldId }, { $set: { auth: newUser.auth } });
|
||||
|
||||
// remove the auth on the new user (which is a template account). The account will be preened automatically later,
|
||||
// remove the auth on the new user (which is a template account).
|
||||
// The account will be preened automatically later,
|
||||
// this allows us to keep the account around a few days in case there was a mistake
|
||||
db.users.update({_id: newId}, {$unset: {auth: 1}});
|
||||
|
||||
db.users.update({ _id: newId }, { $unset: { auth: 1 } });
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* Past in the text of a unique habit here to find the user, then you can restore their UUID
|
||||
*/
|
||||
|
||||
db.users.find().forEach((user) => {
|
||||
db.users.find().forEach(user => {
|
||||
user.tasks = user.habits.concat(user.dailys).concat(user.todos).concat(user.rewards);
|
||||
let found = _.some(user.tasks, {text: ''});
|
||||
if (found) printjson({id: user._id, auth: user.auth});
|
||||
});
|
||||
const found = _.some(user.tasks, { text: '' });
|
||||
if (found) printjson({ id: user._id, auth: user.auth });
|
||||
});
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
// mongo habitrpg ./node_modules/moment/moment.js ./migrations/freeMonth.js
|
||||
|
||||
db.users.update(
|
||||
{_id: ''},
|
||||
{$set: {
|
||||
'purchased.plan.customerId': 'temporary',
|
||||
'purchased.plan.paymentMethod': 'Stripe',
|
||||
'purchased.plan.planId': 'basic_earned',
|
||||
'purchased.plan.dateTerminated': moment().add('month', 1).toDate(),
|
||||
}}
|
||||
{ _id: '' },
|
||||
{
|
||||
$set: {
|
||||
'purchased.plan.customerId': 'temporary',
|
||||
'purchased.plan.paymentMethod': 'Stripe',
|
||||
'purchased.plan.planId': 'basic_earned',
|
||||
'purchased.plan.dateTerminated': moment().add('month', 1).toDate(),
|
||||
},
|
||||
},
|
||||
);
|
||||
// var m = 12;
|
||||
// db.users.update(
|
||||
// {_id:''},
|
||||
// {$set:{'purchased.plan':{
|
||||
// planId: 'basic_'+m+'mo',
|
||||
// paymentMethod: 'Paypal',
|
||||
// customerId: 'Gift',
|
||||
// dateCreated: new Date(),
|
||||
// dateTerminated: moment().add('month',m).toDate(),
|
||||
// dateUpdated: new Date(),
|
||||
// extraMonths: 0,
|
||||
// gemsBought: 0,
|
||||
// mysteryItems: [],
|
||||
// consecutive: {
|
||||
// count: 0,
|
||||
// offset: m,
|
||||
// gemCapExtra: m/3*5,
|
||||
// trinkets: m/3
|
||||
// }
|
||||
// planId: 'basic_'+m+'mo',
|
||||
// paymentMethod: 'Paypal',
|
||||
// customerId: 'Gift',
|
||||
// dateCreated: new Date(),
|
||||
// dateTerminated: moment().add('month',m).toDate(),
|
||||
// dateUpdated: new Date(),
|
||||
// extraMonths: 0,
|
||||
// gemsBought: 0,
|
||||
// mysteryItems: [],
|
||||
// consecutive: {
|
||||
// count: 0,
|
||||
// offset: m,
|
||||
// gemCapExtra: m/3*5,
|
||||
// trinkets: m/3
|
||||
// }
|
||||
// }}}
|
||||
// )
|
||||
// )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
db.users.update(
|
||||
{},
|
||||
{$inc: {'achievements.habiticaDays': 1}},
|
||||
{multi: 1}
|
||||
{ $inc: { 'achievements.habiticaDays': 1 } },
|
||||
{ multi: 1 },
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
db.users.update({_id: ''}, {$inc: {balance: 5}});
|
||||
db.users.update({ _id: '' }, { $inc: { balance: 5 } });
|
||||
|
||||
@@ -13,7 +13,7 @@ import { model as Group } from '../../website/server/models/group';
|
||||
|
||||
// @TODO: this should probably be a GroupManager library method
|
||||
async function addUnlimitedSubscription (groupId, dateTerminated) {
|
||||
let group = await Group.findOne({_id: groupId});
|
||||
const group = await Group.findOne({ _id: groupId });
|
||||
|
||||
group.purchased.plan.customerId = 'group-unlimited';
|
||||
group.purchased.plan.dateCreated = new Date();
|
||||
@@ -22,7 +22,7 @@ async function addUnlimitedSubscription (groupId, dateTerminated) {
|
||||
group.purchased.plan.planId = 'group_monthly';
|
||||
group.purchased.plan.dateTerminated = null;
|
||||
if (dateTerminated) {
|
||||
let dateToEnd = moment(dateTerminated).toDate();
|
||||
const dateToEnd = moment(dateTerminated).toDate();
|
||||
group.purchased.plan.dateTerminated = dateToEnd;
|
||||
}
|
||||
// group.purchased.plan.owner = ObjectId();
|
||||
@@ -31,12 +31,12 @@ async function addUnlimitedSubscription (groupId, dateTerminated) {
|
||||
return group.save();
|
||||
}
|
||||
|
||||
module.exports = async function addUnlimitedSubscriptionCreator () {
|
||||
let groupId = process.argv[2];
|
||||
export default async function addUnlimitedSubscriptionCreator () {
|
||||
const groupId = process.argv[2];
|
||||
|
||||
if (!groupId) throw Error('Group ID is required');
|
||||
|
||||
let dateTerminated = process.argv[3];
|
||||
const dateTerminated = process.argv[3];
|
||||
|
||||
await addUnlimitedSubscription(groupId, dateTerminated);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import { model as User } from '../../website/server/models/user';
|
||||
|
||||
// @TODO: this should probably be a GroupManager library method
|
||||
async function createGroup (name, privacy, type, leaderId) {
|
||||
let user = await User.findOne({_id: leaderId});
|
||||
const user = await User.findOne({ _id: leaderId });
|
||||
|
||||
let group = new Group({
|
||||
const group = new Group({
|
||||
name,
|
||||
privacy,
|
||||
type,
|
||||
@@ -17,13 +17,11 @@ async function createGroup (name, privacy, type, leaderId) {
|
||||
return Promise.all([group.save(), user.save()]);
|
||||
}
|
||||
|
||||
module.exports = async function groupCreator () {
|
||||
let name = process.argv[2];
|
||||
let privacy = process.argv[3];
|
||||
let type = process.argv[4];
|
||||
let leaderId = process.argv[5];
|
||||
export default async function groupCreator () {
|
||||
const name = process.argv[2];
|
||||
const privacy = process.argv[3];
|
||||
const type = process.argv[4];
|
||||
const leaderId = process.argv[5];
|
||||
|
||||
await createGroup(name, privacy, type, leaderId);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
/* let migrationName = 'Jackalopes for Unlimited Subscribers'; */
|
||||
|
||||
/*
|
||||
* This migration will find users with unlimited subscriptions who are also eligible for Jackalope mounts, and award them
|
||||
* This migration will find users with unlimited subscriptions who are also eligible
|
||||
* for Jackalope mounts, and award them
|
||||
*/
|
||||
|
||||
import { model as Group } from '../../website/server/models/group';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
async function handOutJackalopes () {
|
||||
let promises = [];
|
||||
let cursor = User.find({
|
||||
const promises = [];
|
||||
const cursor = User.find({
|
||||
'purchased.plan.customerId': 'habitrpg',
|
||||
}).cursor();
|
||||
|
||||
cursor.on('data', async (user) => {
|
||||
console.log(`User: ${ user._id}`);
|
||||
cursor.on('data', async user => {
|
||||
console.log(`User: ${user._id}`);
|
||||
|
||||
let groupList = [];
|
||||
if (user.party._id) groupList.push(user.party._id);
|
||||
groupList = groupList.concat(user.guilds);
|
||||
|
||||
let subscribedGroup =
|
||||
await Group.findOne({
|
||||
_id: {$in: groupList},
|
||||
'purchased.plan.planId': 'group_monthly',
|
||||
'purchased.plan.dateTerminated': null,
|
||||
},
|
||||
{_id: 1}
|
||||
);
|
||||
const subscribedGroup = await Group.findOne({
|
||||
_id: { $in: groupList },
|
||||
'purchased.plan.planId': 'group_monthly',
|
||||
'purchased.plan.dateTerminated': null,
|
||||
},
|
||||
{ _id: 1 });
|
||||
|
||||
if (subscribedGroup) {
|
||||
User.update({_id: user._id}, {$set: {'items.mounts.Jackalope-RoyalPurple': true}}).exec();
|
||||
User.update({ _id: user._id }, { $set: { 'items.mounts.Jackalope-RoyalPurple': true } }).exec();
|
||||
promises.push(user.save());
|
||||
}
|
||||
});
|
||||
|
||||
cursor.on('close', async () => {
|
||||
console.log('done');
|
||||
return await Promise.all(promises);
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = handOutJackalopes;
|
||||
export default handOutJackalopes;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { model as Group } from '../../website/server/models/group';
|
||||
import { model as Chat } from '../../website/server/models/chat';
|
||||
import { chatModel as Chat } from '../../website/server/models/message';
|
||||
|
||||
async function moveGroupChatToModel (skip = 0) {
|
||||
const groups = await Group.find({})
|
||||
@@ -40,7 +40,7 @@ async function moveGroupChatToModel (skip = 0) {
|
||||
|
||||
|
||||
const reducedPromises = promises.reduce((acc, curr) => {
|
||||
acc = acc.concat(curr);
|
||||
acc = acc.concat(curr); // eslint-disable-line no-param-reassign
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
@@ -49,4 +49,4 @@ async function moveGroupChatToModel (skip = 0) {
|
||||
moveGroupChatToModel(skip + 50);
|
||||
}
|
||||
|
||||
module.exports = moveGroupChatToModel;
|
||||
export default moveGroupChatToModel;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import monk from 'monk';
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import nconf from 'nconf';
|
||||
import stripePayments from '../../website/server/libs/payments/stripe';
|
||||
|
||||
@@ -12,8 +12,8 @@ import stripePayments from '../../website/server/libs/payments/stripe';
|
||||
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
|
||||
let dbGroups = monk(CONNECTION_STRING).get('groups', { castIds: false });
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
const dbGroups = monk(CONNECTION_STRING).get('groups', { castIds: false });
|
||||
const dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
async function fixGroupPlanMembers () {
|
||||
console.info('Group ID, Customer ID, Plan ID, Quantity, Recorded Member Count, Actual Member Count');
|
||||
@@ -24,15 +24,15 @@ async function fixGroupPlanMembers () {
|
||||
{
|
||||
$and:
|
||||
[
|
||||
{'purchased.plan.planId': {$ne: null}},
|
||||
{'purchased.plan.planId': {$ne: ''}},
|
||||
{'purchased.plan.customerId': {$ne: 'cus_9f0DV4g7WHRzpM'}}, // Demo groups
|
||||
{'purchased.plan.customerId': {$ne: 'cus_9maalqDOFTrvqx'}},
|
||||
{ 'purchased.plan.planId': { $ne: null } },
|
||||
{ 'purchased.plan.planId': { $ne: '' } },
|
||||
{ 'purchased.plan.customerId': { $ne: 'cus_9f0DV4g7WHRzpM' } }, // Demo groups
|
||||
{ 'purchased.plan.customerId': { $ne: 'cus_9maalqDOFTrvqx' } },
|
||||
],
|
||||
$or:
|
||||
[
|
||||
{'purchased.plan.dateTerminated': null},
|
||||
{'purchased.plan.dateTerminated': ''},
|
||||
{ 'purchased.plan.dateTerminated': null },
|
||||
{ 'purchased.plan.dateTerminated': '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -40,19 +40,19 @@ async function fixGroupPlanMembers () {
|
||||
memberCount: 1,
|
||||
'purchased.plan': 1,
|
||||
},
|
||||
}
|
||||
).each(async (group, {close, pause, resume}) => { // eslint-disable-line no-unused-vars
|
||||
},
|
||||
).each(async (group, { close, pause, resume }) => { // eslint-disable-line no-unused-vars
|
||||
pause();
|
||||
groupPlanCount++;
|
||||
groupPlanCount += 1;
|
||||
|
||||
const canonicalMemberCount = await dbUsers.count(
|
||||
{
|
||||
$or:
|
||||
[
|
||||
{'party._id': group._id},
|
||||
{guilds: group._id},
|
||||
{ 'party._id': group._id },
|
||||
{ guilds: group._id },
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
const incorrectMemberCount = group.memberCount !== canonicalMemberCount;
|
||||
|
||||
@@ -73,24 +73,24 @@ async function fixGroupPlanMembers () {
|
||||
$set: {
|
||||
memberCount: canonicalMemberCount,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!groupUpdate) return;
|
||||
|
||||
fixedGroupCount++;
|
||||
fixedGroupCount += 1;
|
||||
if (group.purchased.plan.paymentMethod === 'Stripe') {
|
||||
await stripePayments.chargeForAdditionalGroupMember(group);
|
||||
await dbGroups.update(
|
||||
{_id: group._id},
|
||||
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
|
||||
{ _id: group._id },
|
||||
{ $set: { 'purchased.plan.quantity': canonicalMemberCount + 2 } },
|
||||
);
|
||||
}
|
||||
|
||||
if (incorrectQuantity) {
|
||||
await dbGroups.update(
|
||||
{_id: group._id},
|
||||
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
|
||||
{ _id: group._id },
|
||||
{ $set: { 'purchased.plan.quantity': canonicalMemberCount + 2 } },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -98,10 +98,10 @@ async function fixGroupPlanMembers () {
|
||||
}).then(() => {
|
||||
console.info(`Fixed ${fixedGroupCount} out of ${groupPlanCount} active Group Plans`);
|
||||
return process.exit(0);
|
||||
}).catch((err) => {
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
return process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = fixGroupPlanMembers;
|
||||
export default fixGroupPlanMembers;
|
||||
|
||||
@@ -5,29 +5,27 @@ let authorUuid = ''; // ... own data is done
|
||||
*/
|
||||
|
||||
/*
|
||||
* This migrations will iterate through all groups with a group plan a subscription and resync the free
|
||||
* subscription to all members
|
||||
* This migrations will iterate through all groups with a group plan
|
||||
* a subscription and resync the free subscription to all members
|
||||
*/
|
||||
|
||||
import { model as Group } from '../../website/server/models/group';
|
||||
import * as payments from '../../website/server/libs/payments';
|
||||
import payments from '../../website/server/libs/payments/payments';
|
||||
|
||||
async function updateGroupsWithGroupPlans () {
|
||||
let cursor = Group.find({
|
||||
const cursor = Group.find({
|
||||
'purchased.plan.planId': 'group_monthly',
|
||||
'purchased.plan.dateTerminated': null,
|
||||
}).cursor();
|
||||
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
cursor.on('data', (group) => {
|
||||
cursor.on('data', group => {
|
||||
promises.push(payments.addSubscriptionToGroupUsers(group));
|
||||
promises.push(group.save());
|
||||
});
|
||||
|
||||
cursor.on('close', async () => {
|
||||
return await Promise.all(promises);
|
||||
});
|
||||
cursor.on('close', async () => Promise.all(promises));
|
||||
}
|
||||
|
||||
module.exports = updateGroupsWithGroupPlans;
|
||||
export default updateGroupsWithGroupPlans;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require('babel-register');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
require('@babel/register'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
// This file must use ES5, everything required can be in ES6
|
||||
|
||||
@@ -17,12 +18,13 @@ function setUpServer () {
|
||||
setUpServer();
|
||||
|
||||
// Replace this with your migration
|
||||
const processUsers = require('');
|
||||
const processUsers = () => {}; // require('').default;
|
||||
|
||||
processUsers()
|
||||
.then(function success () {
|
||||
.then(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch(function failure (err) {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/* let migrationName = 'new_stuff.js'; */
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
const authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* set the newStuff flag in all user accounts so they see a Bailey message
|
||||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
let dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
'flags.newStuff': {$ne: true},
|
||||
const query = {
|
||||
'flags.newStuff': { $ne: true },
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
@@ -23,29 +25,31 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
fields: [], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
// specify fields we are interested in to limit retrieved data
|
||||
// (empty if we're not reading data):
|
||||
fields: [],
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const userPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
@@ -54,30 +58,31 @@ function updateUsers (users) {
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
let set = {'flags.newStuff': true};
|
||||
const set = { 'flags.newStuff': true };
|
||||
|
||||
dbUsers.update({_id: user._id}, {$set: set});
|
||||
dbUsers.update({ _id: user._id }, { $set: set });
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
let migrationName = 'restock_armoire.js';
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const migrationName = 'restock_armoire.js';
|
||||
const authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Remove flag stating that the Enchanted Armoire is empty, for when new equipment is added
|
||||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
let dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
const query = {
|
||||
'flags.armoireEmpty': true,
|
||||
};
|
||||
|
||||
@@ -23,29 +25,31 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
fields: [], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
// specify fields we are interested in to limit retrieved data
|
||||
// (empty if we're not reading data):
|
||||
fields: [],
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const userPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
@@ -54,30 +58,31 @@ function updateUsers (users) {
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
let set = {migration: migrationName, 'flags.armoireEmpty': false};
|
||||
const set = { migration: migrationName, 'flags.armoireEmpty': false };
|
||||
|
||||
dbUsers.update({_id: user._id}, {$set: set});
|
||||
dbUsers.update({ _id: user._id }, { $set: set });
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
let migrationName = 'restock_armoire_for_users_that_need_it.js';
|
||||
let authorName = 'Alys (ALittleYellowSpider)'; // in case script author needs to know when their ...
|
||||
let authorUuid = '3e595299-3d8a-4a10-bfe0-88f555e4aa0c'; // ... own data is done
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const migrationName = 'restock_armoire_for_users_that_need_it.js';
|
||||
const authorName = 'Alys (ALittleYellowSpider)'; // in case script author needs to know when their ...
|
||||
const authorUuid = '3e595299-3d8a-4a10-bfe0-88f555e4aa0c'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Remove flag stating that the Enchanted Armoire is empty,
|
||||
@@ -18,16 +19,17 @@ let authorUuid = '3e595299-3d8a-4a10-bfe0-88f555e4aa0c'; // ... own data is done
|
||||
*
|
||||
*/
|
||||
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
|
||||
let monk = require('monk');
|
||||
let dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2016-01-04')},
|
||||
const query = {
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2016-01-04') },
|
||||
// '_id': authorUuid // FOR TESTING
|
||||
};
|
||||
|
||||
@@ -35,7 +37,7 @@ function processUsers (lastId) {
|
||||
/* let fields = {
|
||||
'flags.armoireEmpty': 1,
|
||||
'items.gear.owned': 1,
|
||||
};*/
|
||||
}; */
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
@@ -44,32 +46,34 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
// specify fields we are interested in to limit retrieved data
|
||||
// (empty if we're not reading data):
|
||||
fields: {
|
||||
'flags.armoireEmpty': 1,
|
||||
'items.gear.owned': 1,
|
||||
}, // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
},
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const userPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
@@ -78,19 +82,69 @@ function updateUsers (users) {
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
let set = {migration: migrationName, 'flags.armoireEmpty': false};
|
||||
const set = { migration: migrationName, 'flags.armoireEmpty': false };
|
||||
|
||||
|
||||
if (user.flags.armoireEmpty) {
|
||||
// this user believes their armoire has no more items in it
|
||||
if (user.items.gear.owned.weapon_armoire_barristerGavel && user.items.gear.owned.armor_armoire_barristerRobes && user.items.gear.owned.head_armoire_jesterCap && user.items.gear.owned.armor_armoire_jesterCostume && user.items.gear.owned.head_armoire_barristerWig && user.items.gear.owned.weapon_armoire_jesterBaton && user.items.gear.owned.weapon_armoire_lunarSceptre && user.items.gear.owned.armor_armoire_gladiatorArmor && user.items.gear.owned.weapon_armoire_basicCrossbow && user.items.gear.owned.head_armoire_gladiatorHelm && user.items.gear.owned.armor_armoire_lunarArmor && user.items.gear.owned.head_armoire_redHairbow && user.items.gear.owned.head_armoire_violetFloppyHat && user.items.gear.owned.head_armoire_rancherHat && user.items.gear.owned.shield_armoire_gladiatorShield && user.items.gear.owned.head_armoire_blueHairbow && user.items.gear.owned.weapon_armoire_mythmakerSword && user.items.gear.owned.head_armoire_royalCrown && user.items.gear.owned.head_armoire_hornedIronHelm && user.items.gear.owned.weapon_armoire_rancherLasso && user.items.gear.owned.armor_armoire_rancherRobes && user.items.gear.owned.armor_armoire_hornedIronArmor && user.items.gear.owned.armor_armoire_goldenToga && user.items.gear.owned.weapon_armoire_ironCrook && user.items.gear.owned.head_armoire_goldenLaurels && user.items.gear.owned.head_armoire_redFloppyHat && user.items.gear.owned.armor_armoire_plagueDoctorOvercoat && user.items.gear.owned.head_armoire_plagueDoctorHat && user.items.gear.owned.weapon_armoire_goldWingStaff && user.items.gear.owned.head_armoire_yellowHairbow && user.items.gear.owned.eyewear_armoire_plagueDoctorMask && user.items.gear.owned.head_armoire_blackCat && user.items.gear.owned.weapon_armoire_batWand && user.items.gear.owned.head_armoire_orangeCat && user.items.gear.owned.shield_armoire_midnightShield && user.items.gear.owned.armor_armoire_royalRobes && user.items.gear.owned.head_armoire_blueFloppyHat && user.items.gear.owned.shield_armoire_royalCane && user.items.gear.owned.weapon_armoire_shepherdsCrook && user.items.gear.owned.armor_armoire_shepherdRobes && user.items.gear.owned.head_armoire_shepherdHeaddress && user.items.gear.owned.weapon_armoire_blueLongbow && user.items.gear.owned.weapon_armoire_crystalCrescentStaff && user.items.gear.owned.head_armoire_crystalCrescentHat && user.items.gear.owned.armor_armoire_dragonTamerArmor && user.items.gear.owned.head_armoire_dragonTamerHelm && user.items.gear.owned.armor_armoire_crystalCrescentRobes && user.items.gear.owned.shield_armoire_dragonTamerShield && user.items.gear.owned.weapon_armoire_glowingSpear) {
|
||||
if (
|
||||
user.items.gear.owned.weapon_armoire_barristerGavel
|
||||
&& user.items.gear.owned.armor_armoire_barristerRobes
|
||||
&& user.items.gear.owned.head_armoire_jesterCap
|
||||
&& user.items.gear.owned.armor_armoire_jesterCostume
|
||||
&& user.items.gear.owned.head_armoire_barristerWig
|
||||
&& user.items.gear.owned.weapon_armoire_jesterBaton
|
||||
&& user.items.gear.owned.weapon_armoire_lunarSceptre
|
||||
&& user.items.gear.owned.armor_armoire_gladiatorArmor
|
||||
&& user.items.gear.owned.weapon_armoire_basicCrossbow
|
||||
&& user.items.gear.owned.head_armoire_gladiatorHelm
|
||||
&& user.items.gear.owned.armor_armoire_lunarArmor
|
||||
&& user.items.gear.owned.head_armoire_redHairbow
|
||||
&& user.items.gear.owned.head_armoire_violetFloppyHat
|
||||
&& user.items.gear.owned.head_armoire_rancherHat
|
||||
&& user.items.gear.owned.shield_armoire_gladiatorShield
|
||||
&& user.items.gear.owned.head_armoire_blueHairbow
|
||||
&& user.items.gear.owned.weapon_armoire_mythmakerSword
|
||||
&& user.items.gear.owned.head_armoire_royalCrown
|
||||
&& user.items.gear.owned.head_armoire_hornedIronHelm
|
||||
&& user.items.gear.owned.weapon_armoire_rancherLasso
|
||||
&& user.items.gear.owned.armor_armoire_rancherRobes
|
||||
&& user.items.gear.owned.armor_armoire_hornedIronArmor
|
||||
&& user.items.gear.owned.armor_armoire_goldenToga
|
||||
&& user.items.gear.owned.weapon_armoire_ironCrook
|
||||
&& user.items.gear.owned.head_armoire_goldenLaurels
|
||||
&& user.items.gear.owned.head_armoire_redFloppyHat
|
||||
&& user.items.gear.owned.armor_armoire_plagueDoctorOvercoat
|
||||
&& user.items.gear.owned.head_armoire_plagueDoctorHat
|
||||
&& user.items.gear.owned.weapon_armoire_goldWingStaff
|
||||
&& user.items.gear.owned.head_armoire_yellowHairbow
|
||||
&& user.items.gear.owned.eyewear_armoire_plagueDoctorMask
|
||||
&& user.items.gear.owned.head_armoire_blackCat
|
||||
&& user.items.gear.owned.weapon_armoire_batWand
|
||||
&& user.items.gear.owned.head_armoire_orangeCat
|
||||
&& user.items.gear.owned.shield_armoire_midnightShield
|
||||
&& user.items.gear.owned.armor_armoire_royalRobes
|
||||
&& user.items.gear.owned.head_armoire_blueFloppyHat
|
||||
&& user.items.gear.owned.shield_armoire_royalCane
|
||||
&& user.items.gear.owned.weapon_armoire_shepherdsCrook
|
||||
&& user.items.gear.owned.armor_armoire_shepherdRobes
|
||||
&& user.items.gear.owned.head_armoire_shepherdHeaddress
|
||||
&& user.items.gear.owned.weapon_armoire_blueLongbow
|
||||
&& user.items.gear.owned.weapon_armoire_crystalCrescentStaff
|
||||
&& user.items.gear.owned.head_armoire_crystalCrescentHat
|
||||
&& user.items.gear.owned.armor_armoire_dragonTamerArmor
|
||||
&& user.items.gear.owned.head_armoire_dragonTamerHelm
|
||||
&& user.items.gear.owned.armor_armoire_crystalCrescentRobes
|
||||
&& user.items.gear.owned.shield_armoire_dragonTamerShield
|
||||
&& user.items.gear.owned.weapon_armoire_glowingSpear
|
||||
) {
|
||||
// this user does have all the armoire items so we don't change the flag
|
||||
// console.log("don't change: " + user._id); // FOR TESTING
|
||||
} else {
|
||||
// console.log("change: " + user._id); // FOR TESTING
|
||||
dbUsers.update({_id: user._id}, {$set: set});
|
||||
dbUsers.update({ _id: user._id }, { $set: set });
|
||||
}
|
||||
} else {
|
||||
// this user already has armoire marked as containing items to be bought
|
||||
@@ -98,24 +152,25 @@ function updateUser (user) {
|
||||
// console.log("DON'T CHANGE: " + user._id); // FOR TESTING
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/* let migrationName = 'restore_profile_data.js'; */
|
||||
let authorName = 'ThehollidayInn'; // in case script author needs to know when their ...
|
||||
let authorUuid = ''; // ... own data is done
|
||||
const authorName = 'ThehollidayInn'; // in case script author needs to know when their ...
|
||||
const authorUuid = ''; // ... own data is done
|
||||
|
||||
/*
|
||||
* Check if users have empty profile data in new database and update it with old database info
|
||||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let connectionString = ''; // FOR TEST DATABASE
|
||||
let dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
let monk2 = require('monk');
|
||||
let oldDbConnectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
let olDbUsers = monk2(oldDbConnectionString).get('users', { castIds: false });
|
||||
const connectionString = ''; // FOR TEST DATABASE
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
const monk2 = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const oldDbConnectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const olDbUsers = monk2(oldDbConnectionString).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
const query = {
|
||||
// 'profile.name': 'profile name not found',
|
||||
'profile.blurb': null,
|
||||
// 'auth.timestamps.loggedin': {$gt: new Date('11/30/2016')},
|
||||
@@ -29,49 +32,47 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
fields: ['_id', 'profile', 'auth.timestamps.loggedin'], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
setTimeout(displayData, 300000);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let userPaymentPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const userPaymentPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPaymentPromises)
|
||||
.then(() => {
|
||||
return processUsers(lastUser._id);
|
||||
});
|
||||
.then(() => processUsers(lastUser._id));
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
if (!user.profile.name || user.profile.name === 'profile name not found' || !user.profile.imageUrl || !user.profile.blurb) {
|
||||
return olDbUsers.findOne({_id: user._id}, '_id profile')
|
||||
.then((oldUserData) => {
|
||||
if (!oldUserData) return;
|
||||
return olDbUsers.findOne({ _id: user._id }, '_id profile')
|
||||
.then(oldUserData => {
|
||||
if (!oldUserData) return null;
|
||||
// specify user data to change:
|
||||
let set = {};
|
||||
const set = {};
|
||||
|
||||
if (oldUserData.profile.name === 'profile name not found') return;
|
||||
if (oldUserData.profile.name === 'profile name not found') return null;
|
||||
|
||||
let userNeedsProfileName = !user.profile.name || user.profile.name === 'profile name not found';
|
||||
const userNeedsProfileName = !user.profile.name || user.profile.name === 'profile name not found';
|
||||
if (userNeedsProfileName && oldUserData.profile.name) {
|
||||
set['profile.name'] = oldUserData.profile.name;
|
||||
}
|
||||
@@ -86,29 +87,34 @@ function updateUser (user) {
|
||||
|
||||
if (Object.keys(set).length !== 0 && set.constructor === Object) {
|
||||
console.log(set);
|
||||
return dbUsers.update({_id: user._id}, {$set: set});
|
||||
return dbUsers.update({ _id: user._id }, { $set: set });
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
let request = require('superagent');
|
||||
let last = require('lodash/last');
|
||||
let AWS = require('aws-sdk');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const request = require('superagent');
|
||||
const last = require('lodash/last');
|
||||
const AWS = require('aws-sdk');
|
||||
|
||||
const config = require('../config');
|
||||
|
||||
let config = require('../config');
|
||||
const S3_DIRECTORY = 'mobileApp/images'; // config.S3.SPRITES_DIRECTORY;
|
||||
|
||||
AWS.config.update({
|
||||
@@ -11,8 +13,8 @@ AWS.config.update({
|
||||
// region: config.get('S3_REGION'),
|
||||
});
|
||||
|
||||
let BUCKET_NAME = config.S3.bucket;
|
||||
let s3 = new AWS.S3();
|
||||
const BUCKET_NAME = config.S3.bucket;
|
||||
const s3 = new AWS.S3();
|
||||
|
||||
// Adapted from http://stackoverflow.com/a/22210077/2601552
|
||||
function uploadFile (buffer, fileName) {
|
||||
@@ -21,7 +23,7 @@ function uploadFile (buffer, fileName) {
|
||||
Body: buffer,
|
||||
Key: fileName,
|
||||
Bucket: BUCKET_NAME,
|
||||
}, (error) => {
|
||||
}, error => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
@@ -33,9 +35,9 @@ function uploadFile (buffer, fileName) {
|
||||
}
|
||||
|
||||
function getFileName (file) {
|
||||
let piecesOfPath = file.split('/');
|
||||
let name = last(piecesOfPath);
|
||||
let fullName = S3_DIRECTORY + name;
|
||||
const piecesOfPath = file.split('/');
|
||||
const name = last(piecesOfPath);
|
||||
const fullName = S3_DIRECTORY + name;
|
||||
|
||||
return fullName;
|
||||
}
|
||||
@@ -44,36 +46,32 @@ function getFileFromUrl (url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get(url).end((err, res) => {
|
||||
if (err) return reject(err);
|
||||
let file = res.body;
|
||||
resolve(file);
|
||||
const file = res.body;
|
||||
return resolve(file);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let commit = '78f94e365c72cc58f66857d5941105638db7d35c';
|
||||
commit = 'df0dbaba636c9ce424cc7040f7bd7fc1aa311015';
|
||||
let gihuburl = `https://api.github.com/repos/HabitRPG/habitica/commits/${commit}`;
|
||||
const gihuburl = `https://api.github.com/repos/HabitRPG/habitica/commits/${commit}`;
|
||||
|
||||
|
||||
let currentIndex = 0;
|
||||
|
||||
function uploadToS3 (start, end, filesUrls) {
|
||||
let urls = filesUrls.slice(start, end);
|
||||
const urls = filesUrls.slice(start, end);
|
||||
|
||||
if (urls.length === 0) {
|
||||
console.log('done');
|
||||
return;
|
||||
}
|
||||
|
||||
let promises = urls.map(fullUrl => {
|
||||
return getFileFromUrl(fullUrl)
|
||||
.then((buffer) => {
|
||||
return uploadFile(buffer, getFileName(fullUrl));
|
||||
});
|
||||
});
|
||||
const promises = urls.map(fullUrl => getFileFromUrl(fullUrl)
|
||||
.then(buffer => uploadFile(buffer, getFileName(fullUrl))));
|
||||
console.log(promises.length);
|
||||
|
||||
return Promise.all(promises)
|
||||
Promise.all(promises)
|
||||
.then(() => {
|
||||
currentIndex += 50;
|
||||
uploadToS3(currentIndex, currentIndex + 50, filesUrls);
|
||||
@@ -86,12 +84,10 @@ function uploadToS3 (start, end, filesUrls) {
|
||||
request.get(gihuburl)
|
||||
.end((err, res) => {
|
||||
console.log(err);
|
||||
let files = res.body.files;
|
||||
const { files } = res.body;
|
||||
|
||||
let filesUrls = [''];
|
||||
filesUrls = files.map(file => {
|
||||
return file.raw_url;
|
||||
});
|
||||
filesUrls = files.map(file => file.raw_url);
|
||||
|
||||
uploadToS3(currentIndex, currentIndex + 50, filesUrls);
|
||||
});
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
// const migrationName = 'habits-one-history-entry-per-day';
|
||||
// const authorName = 'paglias'; // in case script author needs to know when their ...
|
||||
// const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Iterates over all habits and condense multiple history entries for the same day into a single entry
|
||||
* Iterates over all habits and condense multiple history entries for the same day into a single one
|
||||
*/
|
||||
|
||||
const monk = require('monk');
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const _ = require('lodash');
|
||||
const moment = require('moment');
|
||||
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
|
||||
function processChallengeHabits (lastId) {
|
||||
let query = {
|
||||
'challenge.id': {$exists: true},
|
||||
userId: {$exists: false},
|
||||
const query = {
|
||||
'challenge.id': { $exists: true },
|
||||
userId: { $exists: false },
|
||||
type: 'habit',
|
||||
};
|
||||
|
||||
@@ -26,37 +28,35 @@ function processChallengeHabits (lastId) {
|
||||
}
|
||||
|
||||
dbTasks.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 500,
|
||||
})
|
||||
.then(updateChallengeHabits)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateChallengeHabits (habits) {
|
||||
if (!habits || habits.length === 0) {
|
||||
console.warn('All appropriate challenge habits found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let habitsPromises = habits.map(updateChallengeHabit);
|
||||
let lastHabit = habits[habits.length - 1];
|
||||
const habitsPromises = habits.map(updateChallengeHabit);
|
||||
const lastHabit = habits[habits.length - 1];
|
||||
|
||||
return Promise.all(habitsPromises)
|
||||
.then(() => {
|
||||
return processChallengeHabits(lastHabit._id);
|
||||
});
|
||||
.then(() => processChallengeHabits(lastHabit._id));
|
||||
}
|
||||
|
||||
function updateChallengeHabit (habit) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
if (habit && habit.history && habit.history.length > 0) {
|
||||
// First remove missing entries
|
||||
@@ -76,13 +76,12 @@ function updateChallengeHabit (habit) {
|
||||
entry.scoreDirection = entry.value > previousValue ? 'up' : 'down';
|
||||
}
|
||||
})
|
||||
.groupBy(entry => { // group entries by aggregateBy
|
||||
return moment(entry.date).format('YYYYMMDD');
|
||||
})
|
||||
// group entries by aggregateBy
|
||||
.groupBy(entry => moment(entry.date).format('YYYYMMDD'))
|
||||
.toPairs() // [key, entry]
|
||||
.sortBy(([key]) => key) // sort by date
|
||||
.map(keyEntryPair => {
|
||||
let entries = keyEntryPair[1]; // 1 is entry, 0 is key
|
||||
const entries = keyEntryPair[1]; // 1 is entry, 0 is key
|
||||
let scoredUp = 0;
|
||||
let scoredDown = 0;
|
||||
|
||||
@@ -107,32 +106,34 @@ function updateChallengeHabit (habit) {
|
||||
})
|
||||
.value();
|
||||
|
||||
return dbTasks.update({_id: habit._id}, {
|
||||
$set: {history: habit.history},
|
||||
return dbTasks.update({ _id: habit._id }, {
|
||||
$set: { history: habit.history },
|
||||
});
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } habits processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} habits processed`);
|
||||
return null;
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } tasks processed\n`);
|
||||
console.warn(`\n${count} tasks processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processChallengeHabits;
|
||||
export default processChallengeHabits;
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const migrationName = 'habits-one-history-entry-per-day';
|
||||
const authorName = 'paglias'; // in case script author needs to know when their ...
|
||||
const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Iterates over all habits and condense multiple history entries for the same day into a single entry
|
||||
* Iterates over all habits and condense multiple history entries for the same day into a single one
|
||||
*/
|
||||
|
||||
const monk = require('monk');
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const _ = require('lodash');
|
||||
const moment = require('moment');
|
||||
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
let query = {
|
||||
migration: {$ne: migrationName},
|
||||
const query = {
|
||||
migration: { $ne: migrationName },
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
@@ -25,34 +27,32 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 50, // just 50 users per time since we have to process all their habits as well
|
||||
fields: ['_id', 'preferences.timezoneOffset', 'preferences.dayStart'],
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users and their tasks found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let usersPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const usersPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(usersPromises)
|
||||
.then(() => {
|
||||
return processUsers(lastUser._id);
|
||||
});
|
||||
.then(() => processUsers(lastUser._id));
|
||||
}
|
||||
|
||||
function updateHabit (habit, timezoneOffset, dayStart) {
|
||||
@@ -82,7 +82,7 @@ function updateHabit (habit, timezoneOffset, dayStart) {
|
||||
.toPairs() // [key, entry]
|
||||
.sortBy(([key]) => key) // sort by date
|
||||
.map(keyEntryPair => {
|
||||
let entries = keyEntryPair[1]; // 1 is entry, 0 is key
|
||||
const entries = keyEntryPair[1]; // 1 is entry, 0 is key
|
||||
let scoredUp = 0;
|
||||
let scoredDown = 0;
|
||||
|
||||
@@ -107,57 +107,56 @@ function updateHabit (habit, timezoneOffset, dayStart) {
|
||||
})
|
||||
.value();
|
||||
|
||||
return dbTasks.update({_id: habit._id}, {
|
||||
$set: {history: habit.history},
|
||||
return dbTasks.update({ _id: habit._id }, {
|
||||
$set: { history: habit.history },
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
const timezoneOffset = user.preferences.timezoneOffset;
|
||||
const dayStart = user.preferences.dayStart;
|
||||
const { timezoneOffset } = user.preferences;
|
||||
const { dayStart } = user.preferences;
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } being processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} being processed`);
|
||||
|
||||
return dbTasks.find({
|
||||
type: 'habit',
|
||||
userId: user._id,
|
||||
})
|
||||
.then(habits => {
|
||||
return Promise.all(habits.map(habit => updateHabit(habit, timezoneOffset, dayStart)));
|
||||
})
|
||||
.then(() => {
|
||||
return dbUsers.update({_id: user._id}, {
|
||||
$set: {migration: migrationName},
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
.then(habits => Promise.all(habits.map(habit => updateHabit(habit, timezoneOffset, dayStart))))
|
||||
.then(() => dbUsers.update({ _id: user._id }, {
|
||||
$set: { migration: migrationName },
|
||||
}))
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } tasks processed\n`);
|
||||
console.warn(`\n${count} tasks processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
export default processUsers;
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
/* let migrationName = 'tasks-set-everyX'; */
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
const authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Iterates over all tasks and sets invalid everyX values (less than 0 or more than 9999 or not an int) field to 0
|
||||
* Iterates over all tasks and sets invalid everyX values
|
||||
* (less than 0 or more than 9999 or not an int) field to 0
|
||||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true';
|
||||
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true';
|
||||
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
|
||||
function processTasks (lastId) {
|
||||
// specify a query to limit the affected tasks (empty for all tasks):
|
||||
let query = {
|
||||
const query = {
|
||||
type: 'daily',
|
||||
everyX: {
|
||||
$not: {
|
||||
@@ -30,64 +31,63 @@ function processTasks (lastId) {
|
||||
}
|
||||
|
||||
dbTasks.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
fields: [],
|
||||
})
|
||||
.then(updateTasks)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateTasks (tasks) {
|
||||
if (!tasks || tasks.length === 0) {
|
||||
console.warn('All appropriate tasks found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let taskPromises = tasks.map(updatetask);
|
||||
let lasttask = tasks[tasks.length - 1];
|
||||
const taskPromises = tasks.map(updatetask);
|
||||
const lasttask = tasks[tasks.length - 1];
|
||||
|
||||
return Promise.all(taskPromises)
|
||||
.then(() => {
|
||||
return processTasks(lasttask._id);
|
||||
});
|
||||
.then(() => processTasks(lasttask._id));
|
||||
}
|
||||
|
||||
function updatetask (task) {
|
||||
count++;
|
||||
let set = {everyX: 0};
|
||||
count += 1;
|
||||
const set = { everyX: 0 };
|
||||
|
||||
dbTasks.update({_id: task._id}, {$set: set});
|
||||
dbTasks.update({ _id: task._id }, { $set: set });
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ task._id}`);
|
||||
if (task._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${task._id}`);
|
||||
if (task._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } tasks processed\n`);
|
||||
console.warn(`\n${count} tasks processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processTasks;
|
||||
export default processTasks;
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
/* let migrationName = 'tasks-set-yesterdaily'; */
|
||||
let authorName = 'TheHollidayInn'; // in case script author needs to know when their ...
|
||||
let authorUuid = ''; // ... own data is done
|
||||
// ... own data is done
|
||||
|
||||
/*
|
||||
* Iterates over all tasks and sets the yseterDaily field to True
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
const authorName = 'TheHollidayInn'; // in case script author needs to know when their ...
|
||||
const authorUuid = '';
|
||||
|
||||
let progressCount = 1000;
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
const dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
@@ -30,39 +33,37 @@ function exiting (code, msg) {
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } tasks processed\n`);
|
||||
console.warn(`\n${count} tasks processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function updatetask (task) {
|
||||
count++;
|
||||
let set = {yesterDaily: true};
|
||||
count += 1;
|
||||
const set = { yesterDaily: true };
|
||||
|
||||
dbTasks.update({_id: task._id}, {$set: set});
|
||||
dbTasks.update({ _id: task._id }, { $set: set });
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ task._id}`);
|
||||
if (task._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${task._id}`);
|
||||
if (task._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function updateTasks (tasks) {
|
||||
if (!tasks || tasks.length === 0) {
|
||||
console.warn('All appropriate tasks found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let taskPromises = tasks.map(updatetask);
|
||||
let lasttask = tasks[tasks.length - 1];
|
||||
const taskPromises = tasks.map(updatetask);
|
||||
const lasttask = tasks[tasks.length - 1];
|
||||
|
||||
return Promise.all(taskPromises)
|
||||
.then(() => {
|
||||
return processTasks(lasttask._id); // eslint-disable-line no-use-before-define
|
||||
});
|
||||
.then(() => processTasks(lasttask._id)); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
function processTasks (lastId) {
|
||||
// specify a query to limit the affected tasks (empty for all tasks):
|
||||
let query = {
|
||||
const query = {
|
||||
yesterDaily: false,
|
||||
};
|
||||
|
||||
@@ -73,16 +74,18 @@ function processTasks (lastId) {
|
||||
}
|
||||
|
||||
dbTasks.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
fields: [ // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
// specify fields we are interested in to limit retrieved data
|
||||
// (empty if we're not reading data):
|
||||
fields: [
|
||||
],
|
||||
})
|
||||
.then(updateTasks)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = processTasks;
|
||||
export default processTasks;
|
||||
|
||||
@@ -8,29 +8,30 @@ let authorUuid = ''; // ... own data is done
|
||||
* This migraition will copy user data from prod to test
|
||||
*/
|
||||
|
||||
const monk = require('monk');
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const connectionString = '';
|
||||
const Users = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
module.exports = async function accountTransfer () {
|
||||
export default async function accountTransfer () {
|
||||
const fromAccountId = '';
|
||||
const toAccountId = '';
|
||||
|
||||
const fromAccount = await Users.findOne({_id: fromAccountId});
|
||||
const toAccount = await Users.findOne({_id: toAccountId});
|
||||
const fromAccount = await Users.findOne({ _id: fromAccountId });
|
||||
const toAccount = await Users.findOne({ _id: toAccountId });
|
||||
|
||||
const newMounts = Object.assign({}, fromAccount.items.mounts, toAccount.items.mounts);
|
||||
const newPets = Object.assign({}, fromAccount.items.pets, toAccount.items.pets);
|
||||
const newBackgrounds = Object.assign({}, fromAccount.purchased.background, toAccount.purchased.background);
|
||||
const newMounts = { ...fromAccount.items.mounts, ...toAccount.items.mounts };
|
||||
const newPets = { ...fromAccount.items.pets, ...toAccount.items.pets };
|
||||
const newBackgrounds = { ...fromAccount.purchased.background, ...toAccount.purchased.background };
|
||||
|
||||
await Users.update({_id: toAccountId}, {
|
||||
await Users.update({ _id: toAccountId }, {
|
||||
$set: {
|
||||
'items.pets': newPets,
|
||||
'items.mounts': newMounts,
|
||||
'purchased.background': newBackgrounds,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
.then(result => {
|
||||
console.log(result);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ const authorUuid = ''; // ... own data is done
|
||||
* This migraition will copy user data from prod to test
|
||||
*/
|
||||
|
||||
const monk = require('monk');
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const connectionString = 'mongodb://localhost/new-habit';
|
||||
const Users = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
@@ -19,15 +20,17 @@ function getAchievementUpdate (newUser, oldUser) {
|
||||
const oldAchievements = oldUser.achievements;
|
||||
const newAchievements = newUser.achievements;
|
||||
|
||||
let achievementsUpdate = Object.assign({}, newAchievements);
|
||||
const achievementsUpdate = { ...newAchievements };
|
||||
|
||||
// ultimateGearSets
|
||||
if (!achievementsUpdate.ultimateGearSets && oldAchievements.ultimateGearSets) {
|
||||
achievementsUpdate.ultimateGearSets = oldAchievements.ultimateGearSets;
|
||||
} else if (oldAchievements.ultimateGearSets) {
|
||||
for (let index in oldAchievements.ultimateGearSets) {
|
||||
if (oldAchievements.ultimateGearSets[index]) achievementsUpdate.ultimateGearSets[index] = true;
|
||||
}
|
||||
Object.keys(oldAchievements.ultimateGearSets).forEach(index => {
|
||||
if (oldAchievements.ultimateGearSets[index]) {
|
||||
achievementsUpdate.ultimateGearSets[index] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// challenges
|
||||
@@ -37,57 +40,57 @@ function getAchievementUpdate (newUser, oldUser) {
|
||||
|
||||
// Quests
|
||||
if (!achievementsUpdate.quests) achievementsUpdate.quests = {};
|
||||
for (let index in oldAchievements.quests) {
|
||||
Object.keys(oldAchievements.quests).forEach(index => {
|
||||
if (!achievementsUpdate.quests[index]) {
|
||||
achievementsUpdate.quests[index] = oldAchievements.quests[index];
|
||||
} else {
|
||||
achievementsUpdate.quests[index] += oldAchievements.quests[index];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Rebirth level
|
||||
if (achievementsUpdate.rebirthLevel) {
|
||||
achievementsUpdate.rebirthLevel = Math.max(achievementsUpdate.rebirthLevel, oldAchievements.rebirthLevel);
|
||||
achievementsUpdate.rebirthLevel = Math.max(
|
||||
achievementsUpdate.rebirthLevel, oldAchievements.rebirthLevel,
|
||||
);
|
||||
} else if (oldAchievements.rebirthLevel) {
|
||||
achievementsUpdate.rebirthLevel = oldAchievements.rebirthLevel;
|
||||
}
|
||||
|
||||
// All others
|
||||
const indexsToIgnore = ['ultimateGearSets', 'challenges', 'quests', 'rebirthLevel'];
|
||||
for (let index in oldAchievements) {
|
||||
if (indexsToIgnore.indexOf(index) !== -1) continue; // eslint-disable-line no-continue
|
||||
Object.keys(oldAchievements).forEach(index => {
|
||||
if (indexsToIgnore.indexOf(index) !== -1) return;
|
||||
|
||||
if (!achievementsUpdate[index]) {
|
||||
if (!achievementsUpdate[index]) {
|
||||
achievementsUpdate[index] = oldAchievements[index];
|
||||
continue; // eslint-disable-line no-continue
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number.isInteger(oldAchievements[index])) {
|
||||
achievementsUpdate[index] += oldAchievements[index];
|
||||
} else if (oldAchievements[index] === true) achievementsUpdate[index] = true;
|
||||
}
|
||||
});
|
||||
|
||||
return achievementsUpdate;
|
||||
}
|
||||
|
||||
module.exports = async function achievementRestore () {
|
||||
export default async function achievementRestore () {
|
||||
const userIds = [
|
||||
];
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let index in userIds) {
|
||||
const userId = userIds[index];
|
||||
const oldUser = await UsersOld.findOne({_id: userId}, 'achievements');
|
||||
const newUser = await Users.findOne({_id: userId}, 'achievements');
|
||||
await Promise.all(userIds.map(userId => (async () => {
|
||||
const oldUser = await UsersOld.findOne({ _id: userId }, 'achievements');
|
||||
const newUser = await Users.findOne({ _id: userId }, 'achievements');
|
||||
const achievementUpdate = getAchievementUpdate(newUser, oldUser);
|
||||
await Users.update(
|
||||
{_id: userId},
|
||||
{ _id: userId },
|
||||
{
|
||||
$set: {
|
||||
achievements: achievementUpdate,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
console.log(`Updated ${userId}`);
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
};
|
||||
})()));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable no-console */
|
||||
import { sendTxn } from '../../website/server/libs/email';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
import moment from 'moment';
|
||||
import nconf from 'nconf';
|
||||
import { sendTxn } from '../../website/server/libs/email';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
const EMAIL_SLUG = 'mandrill-email-slug'; // Set email template to send
|
||||
const MIGRATION_NAME = 'bulk-email';
|
||||
@@ -11,23 +12,23 @@ const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
sendTxn(
|
||||
user,
|
||||
EMAIL_SLUG,
|
||||
[{name: 'BASE_URL', content: BASE_URL}] // Add variables from template
|
||||
[{ name: 'BASE_URL', content: BASE_URL }], // Add variables from template
|
||||
);
|
||||
|
||||
return await User.update({_id: user._id}, {$set: {migration: MIGRATION_NAME}}).exec();
|
||||
return User.update({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: moment().subtract(2, 'weeks').toDate()}, // customize or remove to target different populations
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: moment().subtract(2, 'weeks').toDate() }, // customize or remove to target different populations
|
||||
};
|
||||
|
||||
const fields = {
|
||||
@@ -41,7 +42,7 @@ module.exports = async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -58,4 +59,4 @@ module.exports = async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = 'full-stable';
|
||||
import each from 'lodash/each';
|
||||
import keys from 'lodash/keys';
|
||||
import content from '../../website/common/script/content/index';
|
||||
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = 'full-stable';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
@@ -14,45 +15,45 @@ let count = 0;
|
||||
*/
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
const set = {};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
each(keys(content.pets), (pet) => {
|
||||
each(keys(content.pets), pet => {
|
||||
set[`items.pets.${pet}`] = 5;
|
||||
});
|
||||
each(keys(content.premiumPets), (pet) => {
|
||||
each(keys(content.premiumPets), pet => {
|
||||
set[`items.pets.${pet}`] = 5;
|
||||
});
|
||||
each(keys(content.questPets), (pet) => {
|
||||
each(keys(content.questPets), pet => {
|
||||
set[`items.pets.${pet}`] = 5;
|
||||
});
|
||||
each(keys(content.specialPets), (pet) => {
|
||||
each(keys(content.specialPets), pet => {
|
||||
set[`items.pets.${pet}`] = 5;
|
||||
});
|
||||
each(keys(content.mounts), (mount) => {
|
||||
each(keys(content.mounts), mount => {
|
||||
set[`items.mounts.${mount}`] = true;
|
||||
});
|
||||
each(keys(content.premiumMounts), (mount) => {
|
||||
each(keys(content.premiumMounts), mount => {
|
||||
set[`items.mounts.${mount}`] = true;
|
||||
});
|
||||
each(keys(content.questMounts), (mount) => {
|
||||
each(keys(content.questMounts), mount => {
|
||||
set[`items.mounts.${mount}`] = true;
|
||||
});
|
||||
each(keys(content.specialMounts), (mount) => {
|
||||
each(keys(content.specialMounts), mount => {
|
||||
set[`items.mounts.${mount}`] = true;
|
||||
});
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({_id: user._id}, {$set: set}).exec();
|
||||
return User.update({ _id: user._id }, { $set: set }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.local.username': 'olson22',
|
||||
};
|
||||
|
||||
@@ -64,7 +65,7 @@ module.exports = async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -81,4 +82,4 @@ module.exports = async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = 'mystery_items_201908';
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201908', 'headAccessory_mystery_201908'];
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
import { model as UserNotification } from '../../website/server/models/userNotification';
|
||||
|
||||
const MIGRATION_NAME = 'mystery_items_201910';
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201910', 'head_mystery_201910'];
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
const addToSet = {
|
||||
'purchased.plan.mysteryItems': {
|
||||
@@ -29,12 +30,12 @@ async function updateUser (user) {
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({_id: user._id}, {$set: set, $push: push, $addToSet: addToSet}).exec();
|
||||
return User.update({ _id: user._id }, { $set: set, $push: push, $addToSet: addToSet }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'purchased.plan.customerId': { $ne: null },
|
||||
$or: [
|
||||
{ 'purchased.plan.dateTerminated': { $gte: new Date() } },
|
||||
@@ -51,7 +52,7 @@ module.exports = async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -68,4 +69,4 @@ module.exports = async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190314_pi_day';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20190314_pi_day';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count *= 1;
|
||||
|
||||
const inc = {
|
||||
'items.food.Pie_Skeleton': 1,
|
||||
@@ -29,19 +30,21 @@ async function updateUser (user) {
|
||||
set['items.gear.owned.head_special_piDay'] = false;
|
||||
set['items.gear.owned.shield_special_piDay'] = false;
|
||||
const push = [
|
||||
{type: 'marketGear', path: 'gear.flat.head_special_piDay', _id: uuid()},
|
||||
{type: 'marketGear', path: 'gear.flat.shield_special_piDay', _id: uuid()},
|
||||
{ type: 'marketGear', path: 'gear.flat.head_special_piDay', _id: uuid() },
|
||||
{ type: 'marketGear', path: 'gear.flat.shield_special_piDay', _id: uuid() },
|
||||
];
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: {pinnedItems: {$each: push}}}).exec();
|
||||
return User
|
||||
.update({ _id: user._id }, { $inc: inc, $set: set, $push: { pinnedItems: { $each: push } } })
|
||||
.exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2019-02-15')},
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2019-02-15') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
@@ -53,7 +56,7 @@ module.exports = async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -70,4 +73,4 @@ module.exports = async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import monk from 'monk'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const migrationName = 'remove-social-users-extra-data.js';
|
||||
const authorName = 'paglias'; // in case script author needs to know when their ...
|
||||
const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is done
|
||||
@@ -7,13 +9,13 @@ const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is do
|
||||
*/
|
||||
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||
|
||||
const monk = require('monk');
|
||||
|
||||
const dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
migration: {$ne: migrationName},
|
||||
const query = {
|
||||
migration: { $ne: migrationName },
|
||||
$or: [
|
||||
{ 'auth.facebook.id': { $exists: true } },
|
||||
{ 'auth.google.id': { $exists: true } },
|
||||
@@ -27,28 +29,28 @@ function processUsers (lastId) {
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
sort: { _id: 1 },
|
||||
limit: 250,
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
const userPromises = users.map(updateUser);
|
||||
const lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
@@ -57,7 +59,7 @@ function updateUsers (users) {
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
count *= 1;
|
||||
|
||||
const isFacebook = user.auth.facebook && user.auth.facebook.id;
|
||||
const isGoogle = user.auth.google && user.auth.google.id;
|
||||
@@ -82,28 +84,29 @@ function updateUser (user) {
|
||||
_id: user._id,
|
||||
}, update);
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
// 0 = success
|
||||
code = code || 0; // eslint-disable-line no-param-reassign
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
msg = 'ERROR!'; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
export default processUsers;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20181203_take_this';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20181203_take_this';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
const set = {};
|
||||
let push;
|
||||
@@ -19,36 +20,35 @@ async function updateUser (user) {
|
||||
push = false;
|
||||
} else if (typeof user.items.gear.owned.body_special_takeThis !== 'undefined') {
|
||||
set['items.gear.owned.back_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.back_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.back_special_takeThis', _id: uuid() } };
|
||||
} else if (typeof user.items.gear.owned.head_special_takeThis !== 'undefined') {
|
||||
set['items.gear.owned.body_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.body_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.body_special_takeThis', _id: uuid() } };
|
||||
} else if (typeof user.items.gear.owned.armor_special_takeThis !== 'undefined') {
|
||||
set['items.gear.owned.head_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.head_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.head_special_takeThis', _id: uuid() } };
|
||||
} else if (typeof user.items.gear.owned.weapon_special_takeThis !== 'undefined') {
|
||||
set['items.gear.owned.armor_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.armor_special_takeThis', _id: uuid() } };
|
||||
} else if (typeof user.items.gear.owned.shield_special_takeThis !== 'undefined') {
|
||||
set['items.gear.owned.weapon_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.weapon_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.weapon_special_takeThis', _id: uuid() } };
|
||||
} else {
|
||||
set['items.gear.owned.shield_special_takeThis'] = false;
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.shield_special_takeThis', _id: uuid()}};
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.shield_special_takeThis', _id: uuid() } };
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
if (push) {
|
||||
return await User.update({_id: user._id}, {$set: set, $push: push}).exec();
|
||||
} else {
|
||||
return await User.update({_id: user._id}, {$set: set}).exec();
|
||||
return User.update({ _id: user._id }, { $set: set, $push: push }).exec();
|
||||
}
|
||||
return User.update({ _id: user._id }, { $set: set }).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
challenges: '00708425-d477-41a5-bf27-6270466e7976',
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ module.exports = async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -78,4 +78,4 @@ module.exports = async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
/*
|
||||
let migrationName = 'UserFromProdToTest';
|
||||
let authorName = 'TheHollidayInn'; // in case script author needs to know when their ...
|
||||
@@ -8,22 +9,24 @@ let authorUuid = ''; // ... own data is done
|
||||
* This migraition will copy user data from prod to test
|
||||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let testConnectionSting = ''; // FOR TEST DATABASE
|
||||
let usersTest = monk(testConnectionSting).get('users', { castIds: false });
|
||||
let groupsTest = monk(testConnectionSting).get('groups', { castIds: false });
|
||||
let challengesTest = monk(testConnectionSting).get('challenges', { castIds: false });
|
||||
let tasksTest = monk(testConnectionSting).get('tasks', { castIds: false });
|
||||
|
||||
let monk2 = require('monk');
|
||||
let liveConnectString = ''; // FOR TEST DATABASE
|
||||
let userLive = monk2(liveConnectString).get('users', { castIds: false });
|
||||
let groupsLive = monk2(liveConnectString).get('groups', { castIds: false });
|
||||
let challengesLive = monk2(liveConnectString).get('challenges', { castIds: false });
|
||||
let tasksLive = monk2(liveConnectString).get('tasks', { castIds: false });
|
||||
|
||||
import uniq from 'lodash/uniq';
|
||||
|
||||
const monk = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const testConnectionSting = ''; // FOR TEST DATABASE
|
||||
const usersTest = monk(testConnectionSting).get('users', { castIds: false });
|
||||
const groupsTest = monk(testConnectionSting).get('groups', { castIds: false });
|
||||
const challengesTest = monk(testConnectionSting).get('challenges', { castIds: false });
|
||||
const tasksTest = monk(testConnectionSting).get('tasks', { castIds: false });
|
||||
|
||||
const monk2 = require('monk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const liveConnectString = ''; // FOR TEST DATABASE
|
||||
const userLive = monk2(liveConnectString).get('users', { castIds: false });
|
||||
const groupsLive = monk2(liveConnectString).get('groups', { castIds: false });
|
||||
const challengesLive = monk2(liveConnectString).get('challenges', { castIds: false });
|
||||
const tasksLive = monk2(liveConnectString).get('tasks', { castIds: false });
|
||||
|
||||
// Variabls for updating
|
||||
/*
|
||||
let userIds = [
|
||||
@@ -36,11 +39,11 @@ let challengeIds = [];
|
||||
let tasksIds = [];
|
||||
|
||||
async function processUsers () {
|
||||
let userPromises = [];
|
||||
const userPromises = [];
|
||||
// {_id: {$in: userIds}}
|
||||
|
||||
return userLive.find({guilds: 'b0764d64-8276-45a1-afa5-5ca9a5c64ca0'})
|
||||
.each((user) => {
|
||||
return userLive.find({ guilds: 'b0764d64-8276-45a1-afa5-5ca9a5c64ca0' })
|
||||
.each(user => {
|
||||
if (user.guilds.length > 0) groupIds = groupIds.concat(user.guilds);
|
||||
if (user.party._id) groupIds.push(user.party._id);
|
||||
if (user.challenges.length > 0) challengeIds = challengeIds.concat(user.challenges);
|
||||
@@ -49,64 +52,56 @@ async function processUsers () {
|
||||
if (user.tasksOrder.dailys.length > 0) tasksIds = tasksIds.concat(user.tasksOrder.dailys);
|
||||
if (user.tasksOrder.habits.length > 0) tasksIds = tasksIds.concat(user.tasksOrder.habits);
|
||||
|
||||
let userPromise = usersTest.update({_id: user._id}, user, {upsert: true});
|
||||
const userPromise = usersTest.update({ _id: user._id }, user, { upsert: true });
|
||||
userPromises.push(userPromise);
|
||||
}).then(() => {
|
||||
return Promise.all(userPromises);
|
||||
})
|
||||
}).then(() => Promise.all(userPromises))
|
||||
.then(() => {
|
||||
console.log('Done User');
|
||||
});
|
||||
}
|
||||
|
||||
function processGroups () {
|
||||
let promises = [];
|
||||
let groupsToQuery = uniq(groupIds);
|
||||
return groupsLive.find({_id: {$in: groupsToQuery}})
|
||||
.each((group) => {
|
||||
let promise = groupsTest.update({_id: group._id}, group, {upsert: true});
|
||||
const promises = [];
|
||||
const groupsToQuery = uniq(groupIds);
|
||||
return groupsLive.find({ _id: { $in: groupsToQuery } })
|
||||
.each(group => {
|
||||
const promise = groupsTest.update({ _id: group._id }, group, { upsert: true });
|
||||
promises.push(promise);
|
||||
}).then(() => {
|
||||
return Promise.all(promises);
|
||||
})
|
||||
}).then(() => Promise.all(promises))
|
||||
.then(() => {
|
||||
console.log('Done Group');
|
||||
});
|
||||
}
|
||||
|
||||
function processChallenges () {
|
||||
let promises = [];
|
||||
let challengesToQuery = uniq(challengeIds);
|
||||
return challengesLive.find({_id: {$in: challengesToQuery}})
|
||||
.each((challenge) => {
|
||||
let promise = challengesTest.update({_id: challenge._id}, challenge, {upsert: true});
|
||||
const promises = [];
|
||||
const challengesToQuery = uniq(challengeIds);
|
||||
return challengesLive.find({ _id: { $in: challengesToQuery } })
|
||||
.each(challenge => {
|
||||
const promise = challengesTest.update({ _id: challenge._id }, challenge, { upsert: true });
|
||||
promises.push(promise);
|
||||
}).then(() => {
|
||||
return Promise.all(promises);
|
||||
})
|
||||
}).then(() => Promise.all(promises))
|
||||
.then(() => {
|
||||
console.log('Done Challenge');
|
||||
});
|
||||
}
|
||||
|
||||
function processTasks () {
|
||||
let promises = [];
|
||||
let tasksToQuery = uniq(tasksIds);
|
||||
return tasksLive.find({_id: {$in: tasksToQuery}})
|
||||
.each((task) => {
|
||||
let promise = tasksTest.update({_id: task._id}, task, {upsert: true});
|
||||
const promises = [];
|
||||
const tasksToQuery = uniq(tasksIds);
|
||||
return tasksLive.find({ _id: { $in: tasksToQuery } })
|
||||
.each(task => {
|
||||
const promise = tasksTest.update({ _id: task._id }, task, { upsert: true });
|
||||
promises.push(promise);
|
||||
}).then(() => {
|
||||
return Promise.all(promises);
|
||||
})
|
||||
}).then(() => Promise.all(promises))
|
||||
.then(() => {
|
||||
console.log('Done Tasks');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = async function prodToTest () {
|
||||
export default async function prodToTest () {
|
||||
await processUsers();
|
||||
await processGroups();
|
||||
await processChallenges();
|
||||
await processTasks();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const MongoClient = require('mongodb').MongoClient;
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const { MongoClient } = require('mongodb'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const logger = require('./logger');
|
||||
|
||||
let dbConnection;
|
||||
@@ -17,7 +16,7 @@ function connectToDb (dbUri) {
|
||||
|
||||
logger.success(`Connected to ${dbUri}`);
|
||||
|
||||
resolve(database);
|
||||
return resolve(database);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const chalk = require('chalk');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const chalk = require('chalk'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
function loggerGenerator (type, color) {
|
||||
return function logger () {
|
||||
let args = Array.from(arguments).map(arg => chalk[color](arg));
|
||||
const args = Array
|
||||
.from(arguments) // eslint-disable-line prefer-rest-params
|
||||
.map(arg => chalk[color](arg));
|
||||
console[type].apply(null, args);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
let logger = require('./logger');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
const logger = require('./logger');
|
||||
|
||||
class Timer {
|
||||
constructor (options) {
|
||||
options = options || {};
|
||||
let warningThreshold = options.minutesWarningThreshold || 10;
|
||||
constructor (options = {}) {
|
||||
const warningThreshold = options.minutesWarningThreshold || 10;
|
||||
|
||||
this.count = 0;
|
||||
this._minutesWarningThreshold = warningThreshold * 60;
|
||||
|
||||
if (!options.disableAutoStart) this.start();
|
||||
}
|
||||
|
||||
start () {
|
||||
this._internalTimer = setInterval(() => {
|
||||
this.count++;
|
||||
this.count *= 1;
|
||||
|
||||
let shouldWarn = this._minutesWarningThreshold < this.count;
|
||||
let logStyle = shouldWarn ? 'error' : 'warn';
|
||||
let dangerMessage = shouldWarn ? 'DANGER: ' : '';
|
||||
const shouldWarn = this._minutesWarningThreshold < this.count;
|
||||
const logStyle = shouldWarn ? 'error' : 'warn';
|
||||
const dangerMessage = shouldWarn ? 'DANGER: ' : '';
|
||||
|
||||
if (this.count % 30 === 0) {
|
||||
logger[logStyle](`${dangerMessage}Process has been running for`, this.count / 60, 'minutes');
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
stop () {
|
||||
if (!this._internalTimer) {
|
||||
throw new Error('Timer has not started');
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable import/no-commonjs */
|
||||
function unique (array) {
|
||||
return Array.from(new Set(array));
|
||||
}
|
||||
|
||||
19819
package-lock.json
generated
19819
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
137
package.json
137
package.json
@@ -1,115 +1,73 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.111.1",
|
||||
"version": "4.119.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@google-cloud/trace-agent": "^4.0.0",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"@babel/register": "^7.6.2",
|
||||
"@google-cloud/trace-agent": "^4.2.2",
|
||||
"@slack/client": "^3.8.1",
|
||||
"accepts": "^1.3.5",
|
||||
"amazon-payments": "^0.2.7",
|
||||
"amplitude": "^3.5.0",
|
||||
"amplitude-js": "^5.2.2",
|
||||
"apidoc": "^0.17.5",
|
||||
"apn": "^2.2.0",
|
||||
"autoprefixer": "^9.4.0",
|
||||
"aws-sdk": "^2.432.0",
|
||||
"axios": "^0.19.0",
|
||||
"axios-progress-bar": "^1.2.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.16.0",
|
||||
"babel-plugin-transform-regenerator": "^6.16.1",
|
||||
"babel-polyfill": "^6.6.1",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-register": "^6.6.0",
|
||||
"babel-runtime": "^6.11.6",
|
||||
"aws-sdk": "^2.556.0",
|
||||
"bcrypt": "^3.0.6",
|
||||
"body-parser": "^1.18.3",
|
||||
"bootstrap": "^4.1.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.18",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-session": "^1.3.3",
|
||||
"coupon-code": "^0.4.5",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"csv-stringify": "^5.1.0",
|
||||
"cwait": "^1.1.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-habitrpg": "^6.2.0",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"express": "^4.16.3",
|
||||
"express-basic-auth": "^1.1.5",
|
||||
"express-validator": "^5.2.0",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"glob": "^7.1.2",
|
||||
"glob": "^7.1.5",
|
||||
"got": "^9.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^7.0.1",
|
||||
"gulp-imagemin": "^6.0.0",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-imagemin": "^6.1.1",
|
||||
"gulp-nodemon": "^2.4.1",
|
||||
"gulp.spritesmith": "^6.9.0",
|
||||
"habitica-markdown": "^1.3.0",
|
||||
"hellojs": "^1.18.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"image-size": "^0.7.0",
|
||||
"helmet": "^3.21.2",
|
||||
"image-size": "^0.8.3",
|
||||
"in-app-purchase": "^1.11.3",
|
||||
"intro.js": "^2.9.3",
|
||||
"jquery": ">=3.0.0",
|
||||
"js2xmlparser": "^4.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash": "^4.17.15",
|
||||
"merge-stream": "^2.0.0",
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.22.1",
|
||||
"moment": "^2.24.0",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.6.9",
|
||||
"mongoose": "^5.7.7",
|
||||
"morgan": "^1.7.0",
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^1.0.2",
|
||||
"node-sass": "^4.12.0",
|
||||
"ora": "^3.2.0",
|
||||
"pageres": "^5.1.0",
|
||||
"passport": "^0.4.0",
|
||||
"passport-facebook": "^2.0.0",
|
||||
"passport-facebook": "^3.0.0",
|
||||
"passport-google-oauth2": "^0.2.0",
|
||||
"passport-google-oauth20": "1.0.0",
|
||||
"paypal-ipn": "3.0.0",
|
||||
"paypal-rest-sdk": "^1.8.1",
|
||||
"popper.js": "^1.14.3",
|
||||
"postcss-easy-import": "^3.0.0",
|
||||
"ps-tree": "^1.0.0",
|
||||
"pug": "^2.0.3",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"rimraf": "^2.4.3",
|
||||
"sass-loader": "^7.0.3",
|
||||
"shelljs": "^0.8.2",
|
||||
"rimraf": "^3.0.0",
|
||||
"short-uuid": "^3.0.0",
|
||||
"smartbanner.js": "^1.11.0",
|
||||
"stripe": "^5.9.0",
|
||||
"stripe": "^7.10.0",
|
||||
"superagent": "^5.0.2",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"svg-url-loader": "^3.0.0",
|
||||
"svgo": "^1.2.0",
|
||||
"svgo-loader": "^2.1.0",
|
||||
"universal-analytics": "^0.4.17",
|
||||
"update": "^0.7.4",
|
||||
"upgrade": "^1.1.0",
|
||||
"url-loader": "^1.0.0",
|
||||
"useragent": "^2.1.9",
|
||||
"uuid": "^3.0.1",
|
||||
"uuid": "^3.3.3",
|
||||
"validator": "^11.0.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"vue": "^2.6.10",
|
||||
"vue-loader": "^14.2.2",
|
||||
"vue-mugen-scroll": "^0.2.1",
|
||||
"vue-router": "^3.0.0",
|
||||
"vue-style-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"vuedraggable": "^2.20.0",
|
||||
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
|
||||
"webpack": "^3.12.0",
|
||||
"webpack-merge": "^4.1.3",
|
||||
"winston": "^2.4.3",
|
||||
"winston-loggly-bulk": "^2.0.2",
|
||||
"xml2js": "^0.4.4"
|
||||
@@ -120,7 +78,8 @@
|
||||
"npm": "^6"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js,.vue .",
|
||||
"lint": "eslint --ext .js --fix . && cd website/client && npm run lint",
|
||||
"lint-no-fix": "eslint --ext .js . && cd website/client && npm run lint --no-fix",
|
||||
"test": "npm run lint && gulp test && gulp apidoc",
|
||||
"test:build": "gulp test:prepare:build",
|
||||
"test:api-v3": "gulp test:api-v3",
|
||||
@@ -135,60 +94,26 @@
|
||||
"test:nodemon": "gulp test:nodemon",
|
||||
"coverage": "COVERAGE=true mocha --require register-handlers.js --reporter html-cov > coverage.html; open coverage.html",
|
||||
"sprites": "gulp sprites:compile",
|
||||
"client:dev": "node webpack/dev-server.js",
|
||||
"client:build": "gulp build:client",
|
||||
"client:unit": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js --single-run",
|
||||
"client:unit:watch": "cross-env NODE_ENV=test karma start test/client/unit/karma.conf.js",
|
||||
"client:e2e": "node test/client/e2e/runner.js",
|
||||
"client:test": "npm run client:unit && npm run client:e2e",
|
||||
"client:dev": "cd website/client && npm run serve",
|
||||
"client:build": "cd website/client && npm run build",
|
||||
"client:unit": "cd website/client && npm run test:unit",
|
||||
"start": "gulp nodemon",
|
||||
"postinstall": "gulp build",
|
||||
"postinstall": "gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/test-utils": "^1.0.0-beta.29",
|
||||
"babel-plugin-istanbul": "^4.1.6",
|
||||
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
|
||||
"axios": "^0.19.0",
|
||||
"chai": "^4.1.2",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chalk": "^2.4.1",
|
||||
"chromedriver": "^76.0.0",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-habitrpg": "^4.0.0",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-loader": "^2.0.0",
|
||||
"eslint-plugin-html": "^4.0.3",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"expect.js": "^0.3.1",
|
||||
"http-proxy-middleware": "^0.19.0",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
"karma": "^4.0.1",
|
||||
"karma-babel-preprocessor": "^7.0.0",
|
||||
"karma-chai-plugins": "^0.9.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-sinon-chai": "^2.0.0",
|
||||
"karma-sinon-stub-promise": "^1.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"karma-webpack": "^3.0.0",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^6.0.6",
|
||||
"nightwatch": "^1.0.16",
|
||||
"puppeteer": "^1.14.0",
|
||||
"monk": "^7.1.1",
|
||||
"require-again": "^2.0.0",
|
||||
"selenium-server": "^3.12.0",
|
||||
"sinon": "^7.2.4",
|
||||
"sinon-chai": "^3.0.0",
|
||||
"sinon-stub-promise": "^4.0.0",
|
||||
"webpack-bundle-analyzer": "^2.12.0",
|
||||
"webpack-dev-middleware": "^2.0.5",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
"sinon-stub-promise": "^4.0.0"
|
||||
},
|
||||
"optionalDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* eslint-disable no-console */
|
||||
import axios from 'axios';
|
||||
import { model as User } from '../website/server/models/user';
|
||||
/* eslint-disable no-console, import/no-commonjs */
|
||||
import axios from 'axios'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import nconf from 'nconf';
|
||||
import { model as User } from '../website/server/models/user';
|
||||
|
||||
const AMPLITUDE_KEY = nconf.get('AMPLITUDE_KEY');
|
||||
const AMPLITUDE_SECRET = nconf.get('AMPLITUDE_SECRET');
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
async function _deleteAmplitudeData (userId, email) {
|
||||
async function deleteAmplitudeData (userId, email) {
|
||||
const response = await axios.post(
|
||||
'https://amplitude.com/api/2/deletions/users',
|
||||
{
|
||||
@@ -19,22 +19,24 @@ async function _deleteAmplitudeData (userId, email) {
|
||||
username: AMPLITUDE_KEY,
|
||||
password: AMPLITUDE_SECRET,
|
||||
},
|
||||
}
|
||||
).catch((err) => {
|
||||
},
|
||||
).catch(err => {
|
||||
console.log(err.response.data);
|
||||
});
|
||||
|
||||
if (response) console.log(`${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
async function _deleteHabiticaData (user, email) {
|
||||
async function deleteHabiticaData (user, email) {
|
||||
await User.update(
|
||||
{_id: user._id},
|
||||
{$set: {
|
||||
'auth.local.email': email,
|
||||
'auth.local.hashed_password': '$2a$10$QDnNh1j1yMPnTXDEOV38xOePEWFd4X8DSYwAM8XTmqmacG5X0DKjW',
|
||||
'auth.local.passwordHashMethod': 'bcrypt',
|
||||
}}
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'auth.local.email': email,
|
||||
'auth.local.hashed_password': '$2a$10$QDnNh1j1yMPnTXDEOV38xOePEWFd4X8DSYwAM8XTmqmacG5X0DKjW',
|
||||
'auth.local.passwordHashMethod': 'bcrypt',
|
||||
},
|
||||
},
|
||||
);
|
||||
const response = await axios.delete(
|
||||
`${BASE_URL}/api/v3/user`,
|
||||
@@ -46,8 +48,8 @@ async function _deleteHabiticaData (user, email) {
|
||||
'x-api-user': user._id,
|
||||
'x-api-key': user.apiToken,
|
||||
},
|
||||
}
|
||||
).catch((err) => {
|
||||
},
|
||||
).catch(err => {
|
||||
console.log(err.response.data);
|
||||
});
|
||||
|
||||
@@ -57,14 +59,15 @@ async function _deleteHabiticaData (user, email) {
|
||||
}
|
||||
}
|
||||
|
||||
async function _processEmailAddress (email) {
|
||||
async function processEmailAddress (email) {
|
||||
const emailRegex = new RegExp(`^${email}$`, 'i');
|
||||
const users = await User.find({
|
||||
$or: [
|
||||
{'auth.local.email': emailRegex},
|
||||
{'auth.facebook.emails.value': emailRegex},
|
||||
{'auth.google.emails.value': emailRegex},
|
||||
]},
|
||||
{ 'auth.local.email': emailRegex },
|
||||
{ 'auth.facebook.emails.value': emailRegex },
|
||||
{ 'auth.google.emails.value': emailRegex },
|
||||
],
|
||||
},
|
||||
{
|
||||
_id: 1,
|
||||
apiToken: 1,
|
||||
@@ -74,15 +77,15 @@ async function _processEmailAddress (email) {
|
||||
if (users.length < 1) {
|
||||
console.log(`No users found with email address ${email}`);
|
||||
} else {
|
||||
for (const user of users) {
|
||||
await _deleteAmplitudeData(user._id, email); // eslint-disable-line no-await-in-loop
|
||||
await _deleteHabiticaData(user, email); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
Promise.all(users.map(user => (async () => {
|
||||
await deleteAmplitudeData(user._id, email); // eslint-disable-line no-await-in-loop
|
||||
await deleteHabiticaData(user, email); // eslint-disable-line no-await-in-loop
|
||||
})()));
|
||||
}
|
||||
}
|
||||
|
||||
function deleteUserData (emails) {
|
||||
const emailPromises = emails.map(_processEmailAddress);
|
||||
const emailPromises = emails.map(processEmailAddress);
|
||||
return Promise.all(emailPromises);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
require('babel-register');
|
||||
/* eslint-disable import/no-commonjs */
|
||||
require('@babel/register'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
// This file is used for creating paypal billing plans. PayPal doesn't have a web interface for setting up recurring
|
||||
// payment plan definitions, instead you have to create it via their REST SDK and keep it updated the same way. So this
|
||||
// file will be used once for initing your billing plan (then you get the resultant plan.id to store in config.json),
|
||||
// This file is used for creating paypal billing plans.
|
||||
// PayPal doesn't have a web interface for setting up recurring
|
||||
// payment plan definitions, instead you have to create it
|
||||
// via their REST SDK and keep it updated the same way. So this
|
||||
// file will be used once for initing your billing plan
|
||||
// (then you get the resultant plan.id to store in config.json),
|
||||
// and once for any time you need to edit the plan thereafter
|
||||
|
||||
/* eslint-disable no-console, camelcase, no-case-declarations */
|
||||
@@ -12,11 +16,12 @@ const nconf = require('nconf');
|
||||
const _ = require('lodash');
|
||||
const paypal = require('paypal-rest-sdk');
|
||||
const blocks = require('../website/common').content.subscriptionBlocks;
|
||||
|
||||
const live = nconf.get('PAYPAL_MODE') === 'live';
|
||||
|
||||
nconf.argv().env().file('user', path.join(path.resolve(__dirname, '../config.json')));
|
||||
|
||||
let OP = 'create'; // list get update create create-webprofile
|
||||
const OP = 'create'; // list get update create create-webprofile
|
||||
|
||||
paypal.configure({
|
||||
mode: nconf.get('PAYPAL_MODE'), // sandbox or live
|
||||
@@ -25,8 +30,8 @@ paypal.configure({
|
||||
});
|
||||
|
||||
// https://developer.paypal.com/docs/api/#billing-plans-and-agreements
|
||||
let billingPlanTitle = 'Habitica Subscription';
|
||||
let billingPlanAttributes = {
|
||||
const billingPlanTitle = 'Habitica Subscription';
|
||||
const billingPlanAttributes = {
|
||||
description: billingPlanTitle,
|
||||
type: 'INFINITE',
|
||||
merchant_preferences: {
|
||||
@@ -41,7 +46,7 @@ let billingPlanAttributes = {
|
||||
}],
|
||||
};
|
||||
|
||||
_.each(blocks, (block) => {
|
||||
_.each(blocks, block => {
|
||||
block.definition = _.cloneDeep(billingPlanAttributes);
|
||||
_.merge(block.definition.payment_definitions[0], {
|
||||
name: `${billingPlanTitle} ($${block.price} every ${block.months} months, recurring)`,
|
||||
@@ -57,17 +62,17 @@ _.each(blocks, (block) => {
|
||||
|
||||
switch (OP) {
|
||||
case 'list':
|
||||
paypal.billingPlan.list({status: 'ACTIVE'}, (err, plans) => {
|
||||
console.log({err, plans});
|
||||
paypal.billingPlan.list({ status: 'ACTIVE' }, (err, plans) => {
|
||||
console.log({ err, plans });
|
||||
});
|
||||
break;
|
||||
case 'get':
|
||||
paypal.billingPlan.get(nconf.get('PAYPAL_BILLING_PLANS_basic_12mo'), (err, plan) => {
|
||||
console.log({err, plan});
|
||||
console.log({ err, plan });
|
||||
});
|
||||
break;
|
||||
case 'update':
|
||||
let updatePayload = {
|
||||
const updatePayload = {
|
||||
op: 'replace',
|
||||
path: '/merchant_preferences',
|
||||
value: {
|
||||
@@ -75,7 +80,7 @@ switch (OP) {
|
||||
},
|
||||
};
|
||||
paypal.billingPlan.update(nconf.get('PAYPAL_BILLING_PLANS_basic_12mo'), updatePayload, (err, res) => {
|
||||
console.log({err, plan: res});
|
||||
console.log({ err, plan: res });
|
||||
});
|
||||
break;
|
||||
case 'create':
|
||||
@@ -83,10 +88,10 @@ switch (OP) {
|
||||
if (err) return console.log(err);
|
||||
|
||||
if (plan.state === 'ACTIVE') {
|
||||
return console.log({err, plan});
|
||||
return console.log({ err, plan });
|
||||
}
|
||||
|
||||
let billingPlanUpdateAttributes = [{
|
||||
const billingPlanUpdateAttributes = [{
|
||||
op: 'replace',
|
||||
path: '/',
|
||||
value: {
|
||||
@@ -96,12 +101,14 @@ switch (OP) {
|
||||
|
||||
// Activate the plan by changing status to Active
|
||||
paypal.billingPlan.update(plan.id, billingPlanUpdateAttributes, (err2, response) => {
|
||||
console.log({err: err2, response, id: plan.id});
|
||||
console.log({ err: err2, response, id: plan.id });
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
break;
|
||||
case 'create-webprofile':
|
||||
let webexpinfo = {
|
||||
const webexpinfo = {
|
||||
name: 'HabiticaProfile',
|
||||
input_fields: {
|
||||
no_shipping: 1,
|
||||
@@ -112,4 +119,6 @@ switch (OP) {
|
||||
console.log(error, result);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid op');
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"habitrpg/mocha",
|
||||
"habitrpg/esnext"
|
||||
],
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
"globals": {
|
||||
"_": true,
|
||||
}
|
||||
}
|
||||
12
test/.eslintrc.js
Normal file
12
test/.eslintrc.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'habitrpg/lib/mocha',
|
||||
],
|
||||
globals: {
|
||||
_: true,
|
||||
chai: true,
|
||||
expect: true,
|
||||
sinon: true,
|
||||
sandbox: true
|
||||
},
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable camelcase */
|
||||
import analyticsService from '../../../../website/server/libs/analyticsService';
|
||||
import Amplitude from 'amplitude';
|
||||
import { Visitor } from 'universal-analytics';
|
||||
import * as analyticsService from '../../../../website/server/libs/analyticsService';
|
||||
|
||||
describe('analyticsService', () => {
|
||||
beforeEach(() => {
|
||||
@@ -16,7 +16,8 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
describe('#track', () => {
|
||||
let eventType, data;
|
||||
let eventType; let
|
||||
data;
|
||||
|
||||
beforeEach(() => {
|
||||
Visitor.prototype.event.yields();
|
||||
@@ -35,12 +36,10 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
context('Amplitude', () => {
|
||||
it('calls out to amplitude', () => {
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
it('calls out to amplitude', () => analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledOnce;
|
||||
}));
|
||||
|
||||
it('uses a dummy user id if none is provided', () => {
|
||||
delete data.uuid;
|
||||
@@ -55,7 +54,7 @@ describe('analyticsService', () => {
|
||||
|
||||
context('platform', () => {
|
||||
it('logs web platform', () => {
|
||||
data.headers = {'x-client': 'habitica-web'};
|
||||
data.headers = { 'x-client': 'habitica-web' };
|
||||
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
@@ -66,7 +65,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs iOS platform', () => {
|
||||
data.headers = {'x-client': 'habitica-ios'};
|
||||
data.headers = { 'x-client': 'habitica-ios' };
|
||||
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
@@ -77,7 +76,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs Android platform', () => {
|
||||
data.headers = {'x-client': 'habitica-android'};
|
||||
data.headers = { 'x-client': 'habitica-android' };
|
||||
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
@@ -88,7 +87,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs 3rd Party platform', () => {
|
||||
data.headers = {'x-client': 'some-third-party'};
|
||||
data.headers = { 'x-client': 'some-third-party' };
|
||||
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
@@ -169,18 +168,16 @@ describe('analyticsService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('sends details about event', () => {
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledWithMatch({
|
||||
event_properties: {
|
||||
category: 'behavior',
|
||||
resting: true,
|
||||
cronCount: 5,
|
||||
},
|
||||
});
|
||||
it('sends details about event', () => analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledWithMatch({
|
||||
event_properties: {
|
||||
category: 'behavior',
|
||||
resting: true,
|
||||
cronCount: 5,
|
||||
},
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('sends english item name for gear if itemKey is provided', () => {
|
||||
data.itemKey = 'headAccessory_special_foxEars';
|
||||
@@ -267,16 +264,18 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('sends user data if provided', () => {
|
||||
let stats = { class: 'wizard', exp: 5, gp: 23, hp: 10, lvl: 4, mp: 30 };
|
||||
let user = {
|
||||
const stats = {
|
||||
class: 'wizard', exp: 5, gp: 23, hp: 10, lvl: 4, mp: 30,
|
||||
};
|
||||
const user = {
|
||||
stats,
|
||||
contributor: { level: 1 },
|
||||
purchased: { plan: { planId: 'foo-plan' } },
|
||||
flags: {tour: {intro: -2}},
|
||||
habits: [{_id: 'habit'}],
|
||||
dailys: [{_id: 'daily'}],
|
||||
todos: [{_id: 'todo'}],
|
||||
rewards: [{_id: 'reward'}],
|
||||
flags: { tour: { intro: -2 } },
|
||||
habits: [{ _id: 'habit' }],
|
||||
dailys: [{ _id: 'daily' }],
|
||||
todos: [{ _id: 'todo' }],
|
||||
rewards: [{ _id: 'reward' }],
|
||||
balance: 12,
|
||||
loginIncentives: 1,
|
||||
};
|
||||
@@ -312,27 +311,24 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
context('GA', () => {
|
||||
it('calls out to GA', () => {
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
it('calls out to GA', () => analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledOnce;
|
||||
}));
|
||||
|
||||
it('sends details about event', () => {
|
||||
return analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledWith({
|
||||
ea: 'Cron',
|
||||
ec: 'behavior',
|
||||
});
|
||||
it('sends details about event', () => analyticsService.track(eventType, data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledWith({
|
||||
ea: 'Cron',
|
||||
ec: 'behavior',
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#trackPurchase', () => {
|
||||
let data, itemSpy;
|
||||
let data; let
|
||||
itemSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
Visitor.prototype.event.yields();
|
||||
@@ -361,12 +357,10 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
context('Amplitude', () => {
|
||||
it('calls out to amplitude', () => {
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
it('calls out to amplitude', () => analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledOnce;
|
||||
}));
|
||||
|
||||
it('uses a dummy user id if none is provided', () => {
|
||||
delete data.uuid;
|
||||
@@ -381,7 +375,7 @@ describe('analyticsService', () => {
|
||||
|
||||
context('platform', () => {
|
||||
it('logs web platform', () => {
|
||||
data.headers = {'x-client': 'habitica-web'};
|
||||
data.headers = { 'x-client': 'habitica-web' };
|
||||
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
@@ -392,7 +386,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs iOS platform', () => {
|
||||
data.headers = {'x-client': 'habitica-ios'};
|
||||
data.headers = { 'x-client': 'habitica-ios' };
|
||||
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
@@ -403,7 +397,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs Android platform', () => {
|
||||
data.headers = {'x-client': 'habitica-android'};
|
||||
data.headers = { 'x-client': 'habitica-android' };
|
||||
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
@@ -414,7 +408,7 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
it('logs 3rd Party platform', () => {
|
||||
data.headers = {'x-client': 'some-third-party'};
|
||||
data.headers = { 'x-client': 'some-third-party' };
|
||||
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
@@ -495,33 +489,33 @@ describe('analyticsService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('sends details about purchase', () => {
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledWithMatch({
|
||||
event_properties: {
|
||||
gift: false,
|
||||
itemPurchased: 'Gems',
|
||||
paymentMethod: 'PayPal',
|
||||
purchaseType: 'checkout',
|
||||
quantity: 1,
|
||||
sku: 'paypal-checkout',
|
||||
},
|
||||
});
|
||||
it('sends details about purchase', () => analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Amplitude.prototype.track).to.be.calledWithMatch({
|
||||
event_properties: {
|
||||
gift: false,
|
||||
itemPurchased: 'Gems',
|
||||
paymentMethod: 'PayPal',
|
||||
purchaseType: 'checkout',
|
||||
quantity: 1,
|
||||
sku: 'paypal-checkout',
|
||||
},
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('sends user data if provided', () => {
|
||||
let stats = { class: 'wizard', exp: 5, gp: 23, hp: 10, lvl: 4, mp: 30 };
|
||||
let user = {
|
||||
const stats = {
|
||||
class: 'wizard', exp: 5, gp: 23, hp: 10, lvl: 4, mp: 30,
|
||||
};
|
||||
const user = {
|
||||
stats,
|
||||
contributor: { level: 1 },
|
||||
purchased: { plan: { planId: 'foo-plan' } },
|
||||
flags: {tour: {intro: -2}},
|
||||
habits: [{_id: 'habit'}],
|
||||
dailys: [{_id: 'daily'}],
|
||||
todos: [{_id: 'todo'}],
|
||||
rewards: [{_id: 'reward'}],
|
||||
flags: { tour: { intro: -2 } },
|
||||
habits: [{ _id: 'habit' }],
|
||||
dailys: [{ _id: 'daily' }],
|
||||
todos: [{ _id: 'todo' }],
|
||||
rewards: [{ _id: 'reward' }],
|
||||
};
|
||||
|
||||
data.user = user;
|
||||
@@ -552,27 +546,23 @@ describe('analyticsService', () => {
|
||||
});
|
||||
|
||||
context('GA', () => {
|
||||
it('calls out to GA', () => {
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledOnce;
|
||||
expect(Visitor.prototype.transaction).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
it('calls out to GA', () => analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledOnce;
|
||||
expect(Visitor.prototype.transaction).to.be.calledOnce;
|
||||
}));
|
||||
|
||||
it('sends details about purchase', () => {
|
||||
return analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledWith({
|
||||
ea: 'checkout',
|
||||
ec: 'commerce',
|
||||
el: 'PayPal',
|
||||
ev: 8,
|
||||
});
|
||||
expect(Visitor.prototype.transaction).to.be.calledWith('user-id', 8);
|
||||
expect(itemSpy).to.be.calledWith(8, 1, 'paypal-checkout', 'Gems', 'checkout');
|
||||
it('sends details about purchase', () => analyticsService.trackPurchase(data)
|
||||
.then(() => {
|
||||
expect(Visitor.prototype.event).to.be.calledWith({
|
||||
ea: 'checkout',
|
||||
ec: 'commerce',
|
||||
el: 'PayPal',
|
||||
ev: 8,
|
||||
});
|
||||
});
|
||||
expect(Visitor.prototype.transaction).to.be.calledWith('user-id', 8);
|
||||
expect(itemSpy).to.be.calledWith(8, 1, 'paypal-checkout', 'Gems', 'checkout');
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ describe('API Messages', () => {
|
||||
});
|
||||
|
||||
it('clones the passed variables', () => {
|
||||
let vars = {a: 1};
|
||||
const vars = { a: 1 };
|
||||
sandbox.stub(_, 'clone').returns({});
|
||||
apiError('guildsOnlyPaginate', vars);
|
||||
expect(_.clone).to.have.been.calledOnce;
|
||||
@@ -19,8 +19,8 @@ describe('API Messages', () => {
|
||||
});
|
||||
|
||||
it('pass the message through _.template', () => {
|
||||
let vars = {a: 1};
|
||||
let stub = sinon.stub().returns('string');
|
||||
const vars = { a: 1 };
|
||||
const stub = sinon.stub().returns('string');
|
||||
sandbox.stub(_, 'template').returns(stub);
|
||||
apiError('guildsOnlyPaginate', vars);
|
||||
expect(_.template).to.have.been.calledOnce;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import baseModel from '../../../../website/server/libs/baseModel';
|
||||
import mongoose from 'mongoose';
|
||||
import baseModel from '../../../../website/server/libs/baseModel';
|
||||
|
||||
describe('Base model plugin', () => {
|
||||
let schema;
|
||||
@@ -25,7 +25,7 @@ describe('Base model plugin', () => {
|
||||
});
|
||||
|
||||
it('can add timestamps fields', () => {
|
||||
schema.plugin(baseModel, {timestamps: true});
|
||||
schema.plugin(baseModel, { timestamps: true });
|
||||
|
||||
expect(schema.add).to.be.calledTwice;
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe('Base model plugin', () => {
|
||||
});
|
||||
|
||||
expect(schema.statics.sanitize).to.exist;
|
||||
let sanitized = schema.statics.sanitize({ok: true, noUpdateForMe: true});
|
||||
const sanitized = schema.statics.sanitize({ ok: true, noUpdateForMe: true });
|
||||
|
||||
expect(sanitized).to.have.property('ok');
|
||||
expect(sanitized).not.to.have.property('noUpdateForMe');
|
||||
@@ -49,7 +49,7 @@ describe('Base model plugin', () => {
|
||||
});
|
||||
|
||||
expect(schema.statics.sanitize).to.exist;
|
||||
let sanitized = schema.statics.sanitize({ok: true, noUpdateForMe: true, usuallySettable: true}, ['usuallySettable']);
|
||||
const sanitized = schema.statics.sanitize({ ok: true, noUpdateForMe: true, usuallySettable: true }, ['usuallySettable']);
|
||||
|
||||
expect(sanitized).to.have.property('ok');
|
||||
expect(sanitized).not.to.have.property('noUpdateForMe');
|
||||
@@ -63,31 +63,31 @@ describe('Base model plugin', () => {
|
||||
});
|
||||
|
||||
expect(schema.options.toJSON.transform).to.exist;
|
||||
let objToTransform = {ok: true, amPrivate: true};
|
||||
let privatized = schema.options.toJSON.transform({}, objToTransform);
|
||||
const objToTransform = { ok: true, amPrivate: true };
|
||||
const privatized = schema.options.toJSON.transform({}, objToTransform);
|
||||
|
||||
expect(privatized).to.have.property('ok');
|
||||
expect(privatized).not.to.have.property('amPrivate');
|
||||
});
|
||||
|
||||
it('accepts a further transform function for toJSON', () => {
|
||||
let options = {
|
||||
const options = {
|
||||
private: ['amPrivate'],
|
||||
toJSONTransform: sandbox.stub().returns(true),
|
||||
};
|
||||
|
||||
schema.plugin(baseModel, options);
|
||||
|
||||
let objToTransform = {ok: true, amPrivate: true};
|
||||
let doc = {doc: true};
|
||||
let privatized = schema.options.toJSON.transform(doc, objToTransform);
|
||||
const objToTransform = { ok: true, amPrivate: true };
|
||||
const doc = { doc: true };
|
||||
const privatized = schema.options.toJSON.transform(doc, objToTransform);
|
||||
|
||||
expect(privatized).to.equals(true);
|
||||
expect(options.toJSONTransform).to.be.calledWith(objToTransform, doc);
|
||||
});
|
||||
|
||||
it('accepts a transform function for sanitize', () => {
|
||||
let options = {
|
||||
const options = {
|
||||
private: ['amPrivate'],
|
||||
sanitizeTransform: sandbox.stub().returns(true),
|
||||
};
|
||||
@@ -95,8 +95,8 @@ describe('Base model plugin', () => {
|
||||
schema.plugin(baseModel, options);
|
||||
|
||||
expect(schema.options.toJSON.transform).to.exist;
|
||||
let objToSanitize = {ok: true, noUpdateForMe: true};
|
||||
let sanitized = schema.statics.sanitize(objToSanitize);
|
||||
const objToSanitize = { ok: true, noUpdateForMe: true };
|
||||
const sanitized = schema.statics.sanitize(objToSanitize);
|
||||
|
||||
expect(sanitized).to.equals(true);
|
||||
expect(options.sanitizeTransform).to.be.calledWith(objToSanitize);
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
describe('Collection Manipulators', () => {
|
||||
describe('removeFromArray', () => {
|
||||
it('removes element from array', () => {
|
||||
let array = ['a', 'b', 'c', 'd'];
|
||||
const array = ['a', 'b', 'c', 'd'];
|
||||
|
||||
removeFromArray(array, 'c');
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('Collection Manipulators', () => {
|
||||
});
|
||||
|
||||
it('removes object from array', () => {
|
||||
let array = [
|
||||
const array = [
|
||||
{ id: 'a', foo: 'bar' },
|
||||
{ id: 'b', foo: 'bar' },
|
||||
{ id: 'c', foo: 'bar' },
|
||||
@@ -28,7 +28,7 @@ describe('Collection Manipulators', () => {
|
||||
});
|
||||
|
||||
it('does not change array if value is not found', () => {
|
||||
let array = ['a', 'b', 'c', 'd'];
|
||||
const array = ['a', 'b', 'c', 'd'];
|
||||
|
||||
removeFromArray(array, 'z');
|
||||
|
||||
@@ -40,15 +40,15 @@ describe('Collection Manipulators', () => {
|
||||
});
|
||||
|
||||
it('returns the removed element', () => {
|
||||
let array = ['a', 'b', 'c'];
|
||||
const array = ['a', 'b', 'c'];
|
||||
|
||||
let result = removeFromArray(array, 'b');
|
||||
const result = removeFromArray(array, 'b');
|
||||
|
||||
expect(result).to.eql('b');
|
||||
});
|
||||
|
||||
it('returns the removed object element', () => {
|
||||
let array = [
|
||||
const array = [
|
||||
{ id: 'a', foo: 'bar' },
|
||||
{ id: 'b', foo: 'bar' },
|
||||
{ id: 'c', foo: 'bar' },
|
||||
@@ -56,31 +56,31 @@ describe('Collection Manipulators', () => {
|
||||
{ id: 'e', foo: 'bar' },
|
||||
];
|
||||
|
||||
let result = removeFromArray(array, { id: 'c' });
|
||||
const result = removeFromArray(array, { id: 'c' });
|
||||
|
||||
expect(result).to.eql({ id: 'c', foo: 'bar' });
|
||||
});
|
||||
|
||||
it('returns false if item is not found', () => {
|
||||
let array = ['a', 'b', 'c'];
|
||||
const array = ['a', 'b', 'c'];
|
||||
|
||||
let result = removeFromArray(array, 'z');
|
||||
const result = removeFromArray(array, 'z');
|
||||
|
||||
expect(result).to.eql(false);
|
||||
});
|
||||
|
||||
it('persists removal of element when mongoose document is saved', async () => {
|
||||
let schema = new mongoose.Schema({
|
||||
const schema = new mongoose.Schema({
|
||||
array: Array,
|
||||
});
|
||||
let Model = mongoose.model('ModelToTestRemoveFromArray', schema);
|
||||
let model = await new Model({
|
||||
const Model = mongoose.model('ModelToTestRemoveFromArray', schema);
|
||||
const model = await new Model({
|
||||
array: ['a', 'b', 'c'],
|
||||
}).save(); // Initial creation
|
||||
|
||||
removeFromArray(model.array, 'b');
|
||||
|
||||
let savedModel = await model.save();
|
||||
const savedModel = await model.save();
|
||||
|
||||
expect(savedModel.array).to.not.include('b');
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,20 +31,20 @@ function getUser () {
|
||||
}
|
||||
|
||||
describe('emails', () => {
|
||||
let pathToEmailLib = '../../../../website/server/libs/email';
|
||||
const pathToEmailLib = '../../../../website/server/libs/email';
|
||||
|
||||
describe('getUserInfo', () => {
|
||||
it('returns an empty object if no field request', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let getUserInfo = attachEmail.getUserInfo;
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
expect(getUserInfo({}, [])).to.be.empty;
|
||||
});
|
||||
|
||||
it('returns correct user data', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let getUserInfo = attachEmail.getUserInfo;
|
||||
let user = getUser();
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.local.email);
|
||||
@@ -53,13 +53,13 @@ describe('emails', () => {
|
||||
});
|
||||
|
||||
it('returns correct user data [facebook users]', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let getUserInfo = attachEmail.getUserInfo;
|
||||
let user = getUser();
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
delete user.profile.name;
|
||||
delete user.auth.local.email;
|
||||
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.facebook.emails[0].value);
|
||||
@@ -68,13 +68,13 @@ describe('emails', () => {
|
||||
});
|
||||
|
||||
it('has fallbacks for missing data', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let getUserInfo = attachEmail.getUserInfo;
|
||||
let user = getUser();
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const { getUserInfo } = attachEmail;
|
||||
const user = getUser();
|
||||
delete user.auth.local.email;
|
||||
delete user.auth.facebook;
|
||||
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).not.to.have.property('email');
|
||||
@@ -85,18 +85,18 @@ describe('emails', () => {
|
||||
|
||||
describe('getGroupUrl', () => {
|
||||
it('returns correct url if group is the tavern', () => {
|
||||
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
||||
expect(getGroupUrl({_id: TAVERN_ID, type: 'guild'})).to.eql('/groups/tavern');
|
||||
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
|
||||
expect(getGroupUrl({ _id: TAVERN_ID, type: 'guild' })).to.eql('/groups/tavern');
|
||||
});
|
||||
|
||||
it('returns correct url if group is a guild', () => {
|
||||
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
||||
expect(getGroupUrl({_id: 'random _id', type: 'guild'})).to.eql('/groups/guild/random _id');
|
||||
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
|
||||
expect(getGroupUrl({ _id: 'random _id', type: 'guild' })).to.eql('/groups/guild/random _id');
|
||||
});
|
||||
|
||||
it('returns correct url if group is a party', () => {
|
||||
let getGroupUrl = require(pathToEmailLib).getGroupUrl;
|
||||
expect(getGroupUrl({_id: 'random _id', type: 'party'})).to.eql('party');
|
||||
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
|
||||
expect(getGroupUrl({ _id: 'random _id', type: 'party' })).to.eql('party');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,10 +111,10 @@ describe('emails', () => {
|
||||
|
||||
it('can send a txn email to one recipient', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let sendTxnEmail = attachEmail.sendTxn;
|
||||
let emailType = 'an email type';
|
||||
let mailingInfo = {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const sendTxnEmail = attachEmail.sendTxn;
|
||||
const emailType = 'an email type';
|
||||
const mailingInfo = {
|
||||
name: 'my name',
|
||||
email: 'my@email',
|
||||
};
|
||||
@@ -125,9 +125,7 @@ describe('emails', () => {
|
||||
body: {
|
||||
data: {
|
||||
emailType: sinon.match.same(emailType),
|
||||
to: sinon.match((value) => {
|
||||
return Array.isArray(value) && value[0].name === mailingInfo.name;
|
||||
}, 'matches mailing info array'),
|
||||
to: sinon.match(value => Array.isArray(value) && value[0].name === mailingInfo.name, 'matches mailing info array'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
@@ -135,10 +133,10 @@ describe('emails', () => {
|
||||
|
||||
it('does not send email if address is missing', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let sendTxnEmail = attachEmail.sendTxn;
|
||||
let emailType = 'an email type';
|
||||
let mailingInfo = {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const sendTxnEmail = attachEmail.sendTxn;
|
||||
const emailType = 'an email type';
|
||||
const mailingInfo = {
|
||||
name: 'my name',
|
||||
// email: 'my@email',
|
||||
};
|
||||
@@ -149,10 +147,10 @@ describe('emails', () => {
|
||||
|
||||
it('uses getUserInfo in case of user data', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let sendTxnEmail = attachEmail.sendTxn;
|
||||
let emailType = 'an email type';
|
||||
let mailingInfo = getUser();
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const sendTxnEmail = attachEmail.sendTxn;
|
||||
const emailType = 'an email type';
|
||||
const mailingInfo = getUser();
|
||||
|
||||
sendTxnEmail(mailingInfo, emailType);
|
||||
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||
@@ -168,28 +166,24 @@ describe('emails', () => {
|
||||
|
||||
it('sends email with some default variables', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
let sendTxnEmail = attachEmail.sendTxn;
|
||||
let emailType = 'an email type';
|
||||
let mailingInfo = {
|
||||
const attachEmail = requireAgain(pathToEmailLib);
|
||||
const sendTxnEmail = attachEmail.sendTxn;
|
||||
const emailType = 'an email type';
|
||||
const mailingInfo = {
|
||||
name: 'my name',
|
||||
email: 'my@email',
|
||||
};
|
||||
let variables = [1, 2, 3];
|
||||
const variables = [1, 2, 3];
|
||||
|
||||
sendTxnEmail(mailingInfo, emailType, variables);
|
||||
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||
json: true,
|
||||
body: {
|
||||
data: {
|
||||
variables: sinon.match((value) => {
|
||||
return value[0].name === 'BASE_URL';
|
||||
}, 'matches variables'),
|
||||
personalVariables: sinon.match((value) => {
|
||||
return value[0].rcpt === mailingInfo.email &&
|
||||
value[0].vars[0].name === 'RECIPIENT_NAME' &&
|
||||
value[0].vars[1].name === 'RECIPIENT_UNSUB_URL';
|
||||
}, 'matches personal variables'),
|
||||
variables: sinon.match(value => value[0].name === 'BASE_URL', 'matches variables'),
|
||||
personalVariables: sinon.match(value => value[0].rcpt === mailingInfo.email
|
||||
&& value[0].vars[0].name === 'RECIPIENT_NAME'
|
||||
&& value[0].vars[1].name === 'RECIPIENT_UNSUB_URL', 'matches personal variables'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
|
||||
describe('encryption', () => {
|
||||
it('can encrypt and decrypt', () => {
|
||||
let data = 'some secret text';
|
||||
let encrypted = encrypt(data);
|
||||
let decrypted = decrypt(encrypted);
|
||||
const data = 'some secret text';
|
||||
const encrypted = encrypt(data);
|
||||
const decrypted = decrypt(encrypted);
|
||||
|
||||
expect(encrypted).not.to.equal(data);
|
||||
expect(data).to.equal(decrypted);
|
||||
|
||||
@@ -12,7 +12,7 @@ import i18n from '../../../../website/common/script/i18n';
|
||||
describe('Custom Errors', () => {
|
||||
describe('CustomError', () => {
|
||||
it('is an instance of Error', () => {
|
||||
let customError = new CustomError();
|
||||
const customError = new CustomError();
|
||||
|
||||
expect(customError).to.be.an.instanceOf(Error);
|
||||
});
|
||||
@@ -20,25 +20,25 @@ describe('Custom Errors', () => {
|
||||
|
||||
describe('NotAuthorized', () => {
|
||||
it('is an instance of CustomError', () => {
|
||||
let notAuthorizedError = new NotAuthorized();
|
||||
const notAuthorizedError = new NotAuthorized();
|
||||
|
||||
expect(notAuthorizedError).to.be.an.instanceOf(CustomError);
|
||||
});
|
||||
|
||||
it('it returns an http code of 401', () => {
|
||||
let notAuthorizedError = new NotAuthorized();
|
||||
const notAuthorizedError = new NotAuthorized();
|
||||
|
||||
expect(notAuthorizedError.httpCode).to.eql(401);
|
||||
});
|
||||
|
||||
it('returns a default message', () => {
|
||||
let notAuthorizedError = new NotAuthorized();
|
||||
const notAuthorizedError = new NotAuthorized();
|
||||
|
||||
expect(notAuthorizedError.message).to.eql('Not authorized.');
|
||||
});
|
||||
|
||||
it('allows a custom message', () => {
|
||||
let notAuthorizedError = new NotAuthorized('Custom Error Message');
|
||||
const notAuthorizedError = new NotAuthorized('Custom Error Message');
|
||||
|
||||
expect(notAuthorizedError.message).to.eql('Custom Error Message');
|
||||
});
|
||||
@@ -46,25 +46,25 @@ describe('Custom Errors', () => {
|
||||
|
||||
describe('NotFound', () => {
|
||||
it('is an instance of CustomError', () => {
|
||||
let notAuthorizedError = new NotFound();
|
||||
const notAuthorizedError = new NotFound();
|
||||
|
||||
expect(notAuthorizedError).to.be.an.instanceOf(CustomError);
|
||||
});
|
||||
|
||||
it('it returns an http code of 404', () => {
|
||||
let notAuthorizedError = new NotFound();
|
||||
const notAuthorizedError = new NotFound();
|
||||
|
||||
expect(notAuthorizedError.httpCode).to.eql(404);
|
||||
});
|
||||
|
||||
it('returns a default message', () => {
|
||||
let notAuthorizedError = new NotFound();
|
||||
const notAuthorizedError = new NotFound();
|
||||
|
||||
expect(notAuthorizedError.message).to.eql('Not found.');
|
||||
});
|
||||
|
||||
it('allows a custom message', () => {
|
||||
let notAuthorizedError = new NotFound('Custom Error Message');
|
||||
const notAuthorizedError = new NotFound('Custom Error Message');
|
||||
|
||||
expect(notAuthorizedError.message).to.eql('Custom Error Message');
|
||||
});
|
||||
@@ -89,25 +89,25 @@ describe('Custom Errors', () => {
|
||||
|
||||
describe('BadRequest', () => {
|
||||
it('is an instance of CustomError', () => {
|
||||
let badRequestError = new BadRequest();
|
||||
const badRequestError = new BadRequest();
|
||||
|
||||
expect(badRequestError).to.be.an.instanceOf(CustomError);
|
||||
});
|
||||
|
||||
it('it returns an http code of 401', () => {
|
||||
let badRequestError = new BadRequest();
|
||||
const badRequestError = new BadRequest();
|
||||
|
||||
expect(badRequestError.httpCode).to.eql(400);
|
||||
});
|
||||
|
||||
it('returns a default message', () => {
|
||||
let badRequestError = new BadRequest();
|
||||
const badRequestError = new BadRequest();
|
||||
|
||||
expect(badRequestError.message).to.eql('Bad request.');
|
||||
});
|
||||
|
||||
it('allows a custom message', () => {
|
||||
let badRequestError = new BadRequest('Custom Error Message');
|
||||
const badRequestError = new BadRequest('Custom Error Message');
|
||||
|
||||
expect(badRequestError.message).to.eql('Custom Error Message');
|
||||
});
|
||||
@@ -115,25 +115,25 @@ describe('Custom Errors', () => {
|
||||
|
||||
describe('InternalServerError', () => {
|
||||
it('is an instance of CustomError', () => {
|
||||
let internalServerError = new InternalServerError();
|
||||
const internalServerError = new InternalServerError();
|
||||
|
||||
expect(internalServerError).to.be.an.instanceOf(CustomError);
|
||||
});
|
||||
|
||||
it('it returns an http code of 500', () => {
|
||||
let internalServerError = new InternalServerError();
|
||||
const internalServerError = new InternalServerError();
|
||||
|
||||
expect(internalServerError.httpCode).to.eql(500);
|
||||
});
|
||||
|
||||
it('returns a default message', () => {
|
||||
let internalServerError = new InternalServerError();
|
||||
const internalServerError = new InternalServerError();
|
||||
|
||||
expect(internalServerError.message).to.eql('An unexpected error occurred.');
|
||||
});
|
||||
|
||||
it('allows a custom message', () => {
|
||||
let internalServerError = new InternalServerError('Custom Error Message');
|
||||
const internalServerError = new InternalServerError('Custom Error Message');
|
||||
|
||||
expect(internalServerError.message).to.eql('Custom Error Message');
|
||||
});
|
||||
|
||||
60
test/api/unit/libs/highlightMentions.js
Normal file
60
test/api/unit/libs/highlightMentions.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
highlightMentions,
|
||||
} from '../../../../website/server/libs/highlightMentions';
|
||||
|
||||
describe('highlightMentions', () => {
|
||||
beforeEach(() => {
|
||||
const mockFind = {
|
||||
select () {
|
||||
return this;
|
||||
},
|
||||
lean () {
|
||||
return this;
|
||||
},
|
||||
exec () {
|
||||
return Promise.resolve([{
|
||||
auth: { local: { username: 'user' } }, _id: '111',
|
||||
}, { auth: { local: { username: 'user2' } }, _id: '222' }, { auth: { local: { username: 'user3' } }, _id: '333' }, { auth: { local: { username: 'user-dash' } }, _id: '444' }, { auth: { local: { username: 'user_underscore' } }, _id: '555' },
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
sinon.stub(mongoose.Model, 'find').returns(mockFind);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('doesn\'t change text without mentions', async () => {
|
||||
const text = 'some chat text';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal(text);
|
||||
});
|
||||
it('highlights existing users', async () => {
|
||||
const text = '@user: message';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal('[@user](/profile/111): message');
|
||||
});
|
||||
it('highlights special characters', async () => {
|
||||
const text = '@user-dash: message @user_underscore';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal('[@user-dash](/profile/444): message [@user_underscore](/profile/555)');
|
||||
});
|
||||
it('doesn\'t highlight nonexisting users', async () => {
|
||||
const text = '@nouser message';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal('@nouser message');
|
||||
});
|
||||
it('highlights multiple existing users', async () => {
|
||||
const text = '@user message (@user2) @user3 @user';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal('[@user](/profile/111) message ([@user2](/profile/222)) [@user3](/profile/333) [@user](/profile/111)');
|
||||
});
|
||||
it('doesn\'t highlight more than 5 users', async () => {
|
||||
const text = '@user @user2 @user3 @user4 @user5 @user6';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal(text);
|
||||
});
|
||||
});
|
||||
@@ -1,31 +1,15 @@
|
||||
import {
|
||||
translations,
|
||||
localePath,
|
||||
langCodes,
|
||||
approvedLanguages,
|
||||
} from '../../../../website/server/libs/i18n';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
describe('i18n', () => {
|
||||
let listOfLocales = [];
|
||||
|
||||
before((done) => {
|
||||
fs.readdir(localePath, (err, files) => {
|
||||
if (err) return done(err);
|
||||
|
||||
files.forEach((file) => {
|
||||
if (fs.statSync(path.join(localePath, file)).isDirectory() === false) return;
|
||||
listOfLocales.push(file);
|
||||
});
|
||||
|
||||
listOfLocales = listOfLocales.sort();
|
||||
done();
|
||||
});
|
||||
});
|
||||
const listOfLocales = approvedLanguages.sort();
|
||||
|
||||
describe('translations', () => {
|
||||
it('includes a translation object for each locale', () => {
|
||||
listOfLocales.forEach((locale) => {
|
||||
listOfLocales.forEach(locale => {
|
||||
expect(translations[locale]).to.be.an('object');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -100,14 +100,23 @@ describe('Items Utils', () => {
|
||||
});
|
||||
|
||||
it('converts values for mounts paths to numbers', () => {
|
||||
expect(castItemVal('items.mounts.Cactus-Base', '5')).to.equal(5);
|
||||
expect(castItemVal('items.mounts.Aether-Invisible', '5')).to.equal(5);
|
||||
expect(castItemVal('items.mounts.Aether-Invalid', '5')).to.equal(5);
|
||||
expect(castItemVal('items.mounts.Cactus-Base', 'true')).to.equal(true);
|
||||
expect(castItemVal('items.mounts.Aether-Invisible', 'false')).to.equal(false);
|
||||
expect(castItemVal('items.mounts.Aether-Invalid', 'true')).to.equal(true);
|
||||
expect(castItemVal('items.mounts.Aether-Invalid', 'truish')).to.equal(true);
|
||||
expect(castItemVal('items.mounts.Aether-Invalid', 0)).to.equal(false);
|
||||
});
|
||||
|
||||
it('converts values for quests paths to numbers', () => {
|
||||
expect(castItemVal('items.quests.atom3', '5')).to.equal(5);
|
||||
expect(castItemVal('items.quests.invalid', '5')).to.equal(5);
|
||||
});
|
||||
|
||||
it('converts values for owned gear', () => {
|
||||
expect(castItemVal('items.gear.owned.shield_warrior_0', 'true')).to.equal(true);
|
||||
expect(castItemVal('items.gear.owned.invalid', 'false')).to.equal(false);
|
||||
expect(castItemVal('items.gear.owned.invalid', 'thruthy')).to.equal(true);
|
||||
expect(castItemVal('items.gear.owned.invalid', 0)).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import winston from 'winston';
|
||||
import logger from '../../../../website/server/libs/logger';
|
||||
import {
|
||||
NotFound,
|
||||
} from '../../../../website/server/libs//errors';
|
||||
} from '../../../../website/server/libs/errors';
|
||||
|
||||
describe('logger', () => {
|
||||
let logSpy;
|
||||
@@ -34,7 +34,7 @@ describe('logger', () => {
|
||||
|
||||
context('error object', () => {
|
||||
it('logs the stack and the err data', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
logger.error(errInstance, {
|
||||
data: 1,
|
||||
}, 2, 3);
|
||||
@@ -45,13 +45,13 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
{ data: 1, fullError: errInstance },
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs the stack and the err data with it\'s own fullError property', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
let anotherError = new Error('another error');
|
||||
const errInstance = new Error('An error.');
|
||||
const anotherError = new Error('another error');
|
||||
|
||||
logger.error(errInstance, {
|
||||
data: 1,
|
||||
@@ -64,12 +64,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
{ data: 1, fullError: anotherError },
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs the error when errorData is null', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
|
||||
logger.error(errInstance, null, 2, 3);
|
||||
|
||||
@@ -79,12 +79,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
null,
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs the error when errorData is not an object', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
|
||||
logger.error(errInstance, true, 2, 3);
|
||||
|
||||
@@ -94,12 +94,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
true,
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs the error when errorData does not include isHandledError property', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
|
||||
logger.error(errInstance, { httpCode: 400 }, 2, 3);
|
||||
|
||||
@@ -109,12 +109,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
{ httpCode: 400, fullError: errInstance },
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs the error when errorData includes isHandledError property but is a 500 error', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
|
||||
logger.error(errInstance, {
|
||||
isHandledError: true,
|
||||
@@ -127,12 +127,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
{ httpCode: 502, isHandledError: true, fullError: errInstance },
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs a warning when errorData includes isHandledError property and is not a 500 error', () => {
|
||||
let errInstance = new Error('An error.');
|
||||
const errInstance = new Error('An error.');
|
||||
|
||||
logger.error(errInstance, {
|
||||
isHandledError: true,
|
||||
@@ -145,12 +145,12 @@ describe('logger', () => {
|
||||
errInstance.stack,
|
||||
{ httpCode: 403, isHandledError: true, fullError: errInstance },
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
it('logs additional data from a CustomError', () => {
|
||||
let errInstance = new NotFound('An error.');
|
||||
const errInstance = new NotFound('An error.');
|
||||
|
||||
errInstance.customField = 'Some interesting data';
|
||||
|
||||
@@ -166,7 +166,7 @@ describe('logger', () => {
|
||||
},
|
||||
},
|
||||
2,
|
||||
3
|
||||
3,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
import moment from 'moment';
|
||||
import {
|
||||
encrypt,
|
||||
} from '../../../../website/server/libs/encryption';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
generateUser,
|
||||
} from '../../../helpers/api-integration/v3';
|
||||
@@ -20,11 +20,11 @@ import {
|
||||
describe('Password Utilities', () => {
|
||||
describe('compare', () => {
|
||||
it('can compare a correct password hashed with SHA1', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const salt = sha1MakeSalt();
|
||||
const hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -34,16 +34,16 @@ describe('Password Utilities', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let isValidPassword = await compare(user, textPassword);
|
||||
const isValidPassword = await compare(user, textPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
it('can compare an invalid password hashed with SHA1', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const salt = sha1MakeSalt();
|
||||
const hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -53,15 +53,15 @@ describe('Password Utilities', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let isValidPassword = await compare(user, 'wrongPassword');
|
||||
const isValidPassword = await compare(user, 'wrongPassword');
|
||||
expect(isValidPassword).to.eql(false);
|
||||
});
|
||||
|
||||
it('can compare a correct password hashed with bcrypt', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -70,15 +70,15 @@ describe('Password Utilities', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let isValidPassword = await compare(user, textPassword);
|
||||
const isValidPassword = await compare(user, textPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
it('can compare an invalid password hashed with bcrypt', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -87,7 +87,7 @@ describe('Password Utilities', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let isValidPassword = await compare(user, 'wrongPassword');
|
||||
const isValidPassword = await compare(user, 'wrongPassword');
|
||||
expect(isValidPassword).to.eql(false);
|
||||
});
|
||||
|
||||
@@ -101,18 +101,18 @@ describe('Password Utilities', () => {
|
||||
|
||||
it('throws an error if passwordToCheck is missing', async () => {
|
||||
try {
|
||||
await compare({a: true});
|
||||
await compare({ a: true });
|
||||
} catch (e) {
|
||||
expect(e.toString()).to.equal('Error: user and passwordToCheck are required parameters.');
|
||||
}
|
||||
});
|
||||
|
||||
it('defaults to SHA1 encryption if salt is provided', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const salt = sha1MakeSalt();
|
||||
const hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -122,7 +122,7 @@ describe('Password Utilities', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let isValidPassword = await compare(user, textPassword);
|
||||
const isValidPassword = await compare(user, textPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
@@ -141,29 +141,29 @@ describe('Password Utilities', () => {
|
||||
});
|
||||
|
||||
it('returns true if comparing the same password', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let isValidPassword = await bcryptCompare(textPassword, hashedPassword);
|
||||
const isValidPassword = await bcryptCompare(textPassword, hashedPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
it('returns true if comparing a different password', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let isValidPassword = await bcryptCompare('anotherPassword', hashedPassword);
|
||||
const isValidPassword = await bcryptCompare('anotherPassword', hashedPassword);
|
||||
expect(isValidPassword).to.eql(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertToBcrypt', () => {
|
||||
it('converts an user password hashed with sha1 to bcrypt', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const salt = sha1MakeSalt();
|
||||
const hashedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
let user = {
|
||||
const user = {
|
||||
auth: {
|
||||
local: {
|
||||
hashed_password: hashedPassword,
|
||||
@@ -178,7 +178,7 @@ describe('Password Utilities', () => {
|
||||
expect(user.auth.local.passwordHashMethod).to.equal('bcrypt');
|
||||
expect(user.auth.local.hashed_password).to.be.a.string;
|
||||
|
||||
let isValidPassword = await compare(user, textPassword);
|
||||
const isValidPassword = await compare(user, textPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
@@ -192,7 +192,7 @@ describe('Password Utilities', () => {
|
||||
|
||||
it('throws an error if plainTextPassword is missing', async () => {
|
||||
try {
|
||||
await convertToBcrypt({a: true});
|
||||
await convertToBcrypt({ a: true });
|
||||
} catch (e) {
|
||||
expect(e.toString()).to.equal('Error: user and plainTextPassword are required parameters.');
|
||||
}
|
||||
@@ -201,18 +201,18 @@ describe('Password Utilities', () => {
|
||||
|
||||
describe('validatePasswordResetCodeAndFindUser', () => {
|
||||
it('returns false if the code is missing', async () => {
|
||||
let res = await validatePasswordResetCodeAndFindUser();
|
||||
const res = await validatePasswordResetCodeAndFindUser();
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns false if the code is invalid json', async () => {
|
||||
let res = await validatePasswordResetCodeAndFindUser('invalid json');
|
||||
const res = await validatePasswordResetCodeAndFindUser('invalid json');
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns false if the code cannot be decrypted', async () => {
|
||||
let user = await generateUser();
|
||||
let res = await validatePasswordResetCodeAndFindUser(JSON.stringify({ // not encrypted
|
||||
const user = await generateUser();
|
||||
const res = await validatePasswordResetCodeAndFindUser(JSON.stringify({ // not encrypted
|
||||
userId: user._id,
|
||||
expiresAt: new Date(),
|
||||
}));
|
||||
@@ -220,71 +220,71 @@ describe('Password Utilities', () => {
|
||||
});
|
||||
|
||||
it('returns false if the code is expired', async () => {
|
||||
let user = await generateUser();
|
||||
const user = await generateUser();
|
||||
|
||||
let code = encrypt(JSON.stringify({
|
||||
const code = encrypt(JSON.stringify({
|
||||
userId: user._id,
|
||||
expiresAt: moment().subtract({minutes: 1}),
|
||||
expiresAt: moment().subtract({ minutes: 1 }),
|
||||
}));
|
||||
|
||||
await user.update({
|
||||
'auth.local.passwordResetCode': code,
|
||||
});
|
||||
|
||||
let res = await validatePasswordResetCodeAndFindUser(code);
|
||||
const res = await validatePasswordResetCodeAndFindUser(code);
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns false if the user does not exist', async () => {
|
||||
let res = await validatePasswordResetCodeAndFindUser(encrypt(JSON.stringify({
|
||||
const res = await validatePasswordResetCodeAndFindUser(encrypt(JSON.stringify({
|
||||
userId: Date.now().toString(),
|
||||
expiresAt: moment().add({days: 1}),
|
||||
expiresAt: moment().add({ days: 1 }),
|
||||
})));
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns false if the user has no local auth', async () => {
|
||||
let user = await generateUser({
|
||||
const user = await generateUser({
|
||||
auth: {
|
||||
facebook: {},
|
||||
},
|
||||
});
|
||||
let res = await validatePasswordResetCodeAndFindUser(encrypt(JSON.stringify({
|
||||
const res = await validatePasswordResetCodeAndFindUser(encrypt(JSON.stringify({
|
||||
userId: user._id,
|
||||
expiresAt: moment().add({days: 1}),
|
||||
expiresAt: moment().add({ days: 1 }),
|
||||
})));
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns false if the code doesn\'t match the one saved at user.auth.passwordResetCode', async () => {
|
||||
let user = await generateUser();
|
||||
const user = await generateUser();
|
||||
|
||||
let code = encrypt(JSON.stringify({
|
||||
const code = encrypt(JSON.stringify({
|
||||
userId: user._id,
|
||||
expiresAt: moment().add({days: 1}),
|
||||
expiresAt: moment().add({ days: 1 }),
|
||||
}));
|
||||
|
||||
await user.update({
|
||||
'auth.local.passwordResetCode': 'invalid',
|
||||
});
|
||||
|
||||
let res = await validatePasswordResetCodeAndFindUser(code);
|
||||
const res = await validatePasswordResetCodeAndFindUser(code);
|
||||
expect(res).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns the user if the password reset code is valid', async () => {
|
||||
let user = await generateUser();
|
||||
const user = await generateUser();
|
||||
|
||||
let code = encrypt(JSON.stringify({
|
||||
const code = encrypt(JSON.stringify({
|
||||
userId: user._id,
|
||||
expiresAt: moment().add({days: 1}),
|
||||
expiresAt: moment().add({ days: 1 }),
|
||||
}));
|
||||
|
||||
await user.update({
|
||||
'auth.local.passwordResetCode': code,
|
||||
});
|
||||
|
||||
let res = await validatePasswordResetCodeAndFindUser(code);
|
||||
const res = await validatePasswordResetCodeAndFindUser(code);
|
||||
expect(res).not.to.equal(false);
|
||||
expect(res._id).to.equal(user._id);
|
||||
});
|
||||
@@ -293,8 +293,8 @@ describe('Password Utilities', () => {
|
||||
describe('bcrypt', () => {
|
||||
describe('Hash', () => {
|
||||
it('returns a hashed string', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
expect(hashedPassword).to.be.a.string;
|
||||
});
|
||||
@@ -302,18 +302,18 @@ describe('Password Utilities', () => {
|
||||
|
||||
describe('Compare', () => {
|
||||
it('returns true if comparing the same password', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let isValidPassword = await bcryptCompare(textPassword, hashedPassword);
|
||||
const isValidPassword = await bcryptCompare(textPassword, hashedPassword);
|
||||
expect(isValidPassword).to.eql(true);
|
||||
});
|
||||
|
||||
it('returns true if comparing a different password', async () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let hashedPassword = await bcryptHash(textPassword);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const hashedPassword = await bcryptHash(textPassword);
|
||||
|
||||
let isValidPassword = await bcryptCompare('anotherPassword', hashedPassword);
|
||||
const isValidPassword = await bcryptCompare('anotherPassword', hashedPassword);
|
||||
expect(isValidPassword).to.eql(false);
|
||||
});
|
||||
});
|
||||
@@ -322,19 +322,19 @@ describe('Password Utilities', () => {
|
||||
describe('SHA1', () => {
|
||||
describe('Encrypt', () => {
|
||||
it('always encrypt the same password to the same value when using the same salt', () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let salt = sha1MakeSalt();
|
||||
let encryptedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const salt = sha1MakeSalt();
|
||||
const encryptedPassword = sha1EncryptPassword(textPassword, salt);
|
||||
|
||||
expect(sha1EncryptPassword(textPassword, salt)).to.eql(encryptedPassword);
|
||||
});
|
||||
|
||||
it('never encrypt the same password to the same value when using a different salt', () => {
|
||||
let textPassword = 'mySecretPassword';
|
||||
let aSalt = sha1MakeSalt();
|
||||
let anotherSalt = sha1MakeSalt();
|
||||
let anEncryptedPassword = sha1EncryptPassword(textPassword, aSalt);
|
||||
let anotherEncryptedPassword = sha1EncryptPassword(textPassword, anotherSalt);
|
||||
const textPassword = 'mySecretPassword';
|
||||
const aSalt = sha1MakeSalt();
|
||||
const anotherSalt = sha1MakeSalt();
|
||||
const anEncryptedPassword = sha1EncryptPassword(textPassword, aSalt);
|
||||
const anotherEncryptedPassword = sha1EncryptPassword(textPassword, anotherSalt);
|
||||
|
||||
expect(anEncryptedPassword).not.to.eql(anotherEncryptedPassword);
|
||||
});
|
||||
@@ -342,14 +342,14 @@ describe('Password Utilities', () => {
|
||||
|
||||
describe('Make Salt', () => {
|
||||
it('creates a salt with length 10 by default', () => {
|
||||
let salt = sha1MakeSalt();
|
||||
const salt = sha1MakeSalt();
|
||||
|
||||
expect(salt.length).to.eql(10);
|
||||
});
|
||||
|
||||
it('can create a salt of any length', () => {
|
||||
let length = 24;
|
||||
let salt = sha1MakeSalt(length);
|
||||
const length = 24;
|
||||
const salt = sha1MakeSalt(length);
|
||||
|
||||
expect(salt.length).to.eql(length);
|
||||
});
|
||||
|
||||
@@ -2,19 +2,20 @@ import moment from 'moment';
|
||||
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../../helpers/api-unit.helper';
|
||||
import { model as User } from '../../../../../../website/server/models/user';
|
||||
import amzLib from '../../../../../../website/server/libs/payments/amazon';
|
||||
import payments from '../../../../../../website/server/libs/payments/payments';
|
||||
import common from '../../../../../../website/common';
|
||||
import { createNonLeaderGroupMember } from '../paymentHelpers';
|
||||
|
||||
const i18n = common.i18n;
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Amazon Payments - Cancel Subscription', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
|
||||
let user, group, headers, billingAgreementId, subscriptionBlock, subscriptionLength;
|
||||
let user; let group; let headers; let billingAgreementId; let subscriptionBlock; let
|
||||
subscriptionLength;
|
||||
let getBillingAgreementDetailsSpy;
|
||||
let paymentCancelSubscriptionSpy;
|
||||
|
||||
@@ -50,7 +51,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Open'},
|
||||
BillingAgreementStatus: { State: 'Open' },
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -81,7 +82,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
getBillingAgreementDetailsSpy = sinon.stub(amzLib, 'getBillingAgreementDetails');
|
||||
getBillingAgreementDetailsSpy.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
BillingAgreementStatus: { State: 'Closed' },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -89,7 +90,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
paymentCancelSubscriptionSpy.resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(() => {
|
||||
amzLib.getBillingAgreementDetails.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
@@ -97,7 +98,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should throw an error if we are missing a subscription', async () => {
|
||||
user.purchased.plan.customerId = undefined;
|
||||
|
||||
await expect(amzLib.cancelSubscription({user}))
|
||||
await expect(amzLib.cancelSubscription({ user }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -108,7 +109,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should cancel a user subscription', async () => {
|
||||
billingAgreementId = user.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, headers});
|
||||
await amzLib.cancelSubscription({ user, headers });
|
||||
|
||||
expectAmazonCancelUserSubscriptionSpy();
|
||||
expectAmazonStubs();
|
||||
@@ -117,10 +118,10 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should close a user subscription if amazon not closed', async () => {
|
||||
amzLib.getBillingAgreementDetails.restore();
|
||||
expectBillingAggreementDetailSpy();
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
const closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
billingAgreementId = user.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, headers});
|
||||
await amzLib.cancelSubscription({ user, headers });
|
||||
|
||||
expectAmazonStubs();
|
||||
expect(closeBillingAgreementSpy).to.be.calledOnce;
|
||||
@@ -132,7 +133,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if group is not found', async () => {
|
||||
await expect(amzLib.cancelSubscription({user, groupId: 'fake-id'}))
|
||||
await expect(amzLib.cancelSubscription({ user, groupId: 'fake-id' }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 404,
|
||||
name: 'NotFound',
|
||||
@@ -141,9 +142,9 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if user is not group leader', async () => {
|
||||
let nonLeader = await createNonLeaderGroupMember(group);
|
||||
const nonLeader = await createNonLeaderGroupMember(group);
|
||||
|
||||
await expect(amzLib.cancelSubscription({user: nonLeader, groupId: group._id}))
|
||||
await expect(amzLib.cancelSubscription({ user: nonLeader, groupId: group._id }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -154,7 +155,7 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should cancel a group subscription', async () => {
|
||||
billingAgreementId = group.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, groupId: group._id, headers});
|
||||
await amzLib.cancelSubscription({ user, groupId: group._id, headers });
|
||||
|
||||
expectAmazonCancelGroupSubscriptionSpy(group._id);
|
||||
expectAmazonStubs();
|
||||
@@ -163,10 +164,10 @@ describe('Amazon Payments - Cancel Subscription', () => {
|
||||
it('should close a group subscription if amazon not closed', async () => {
|
||||
amzLib.getBillingAgreementDetails.restore();
|
||||
expectBillingAggreementDetailSpy();
|
||||
let closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
const closeBillingAgreementSpy = sinon.stub(amzLib, 'closeBillingAgreement').resolves({});
|
||||
billingAgreementId = group.purchased.plan.customerId;
|
||||
|
||||
await amzLib.cancelSubscription({user, groupId: group._id, headers});
|
||||
await amzLib.cancelSubscription({ user, groupId: group._id, headers });
|
||||
|
||||
expectAmazonStubs();
|
||||
expect(closeBillingAgreementSpy).to.be.calledOnce;
|
||||
|
||||
@@ -3,11 +3,12 @@ import amzLib from '../../../../../../website/server/libs/payments/amazon';
|
||||
import payments from '../../../../../../website/server/libs/payments/payments';
|
||||
import common from '../../../../../../website/common';
|
||||
|
||||
const i18n = common.i18n;
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Amazon Payments - Checkout', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
let user, orderReferenceId, headers;
|
||||
let user; let orderReferenceId; let
|
||||
headers;
|
||||
let setOrderReferenceDetailsSpy;
|
||||
let confirmOrderReferenceSpy;
|
||||
let authorizeSpy;
|
||||
@@ -62,7 +63,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
expect(closeOrderReferenceSpy).to.be.calledWith({ AmazonOrderReferenceId: orderReferenceId });
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
headers = {};
|
||||
orderReferenceId = 'orderReferenceId';
|
||||
@@ -88,7 +89,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(() => {
|
||||
amzLib.setOrderReferenceDetails.restore();
|
||||
amzLib.confirmOrderReference.restore();
|
||||
amzLib.authorize.restore();
|
||||
@@ -101,7 +102,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
function expectBuyGemsStub (paymentMethod, gift) {
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
|
||||
let expectedArgs = {
|
||||
const expectedArgs = {
|
||||
user,
|
||||
paymentMethod,
|
||||
headers,
|
||||
@@ -112,7 +113,7 @@ describe('Amazon Payments - Checkout', () => {
|
||||
|
||||
it('should purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await amzLib.checkout({user, orderReferenceId, headers});
|
||||
await amzLib.checkout({ user, orderReferenceId, headers });
|
||||
|
||||
expectBuyGemsStub(amzLib.constants.PAYMENT_METHOD);
|
||||
expectAmazonStubs();
|
||||
@@ -121,9 +122,9 @@ describe('Amazon Payments - Checkout', () => {
|
||||
});
|
||||
|
||||
it('should error if gem amount is too low', async () => {
|
||||
let receivingUser = new User();
|
||||
const receivingUser = new User();
|
||||
receivingUser.save();
|
||||
let gift = {
|
||||
const gift = {
|
||||
type: 'gems',
|
||||
gems: {
|
||||
amount: 0,
|
||||
@@ -131,7 +132,9 @@ describe('Amazon Payments - Checkout', () => {
|
||||
},
|
||||
};
|
||||
|
||||
await expect(amzLib.checkout({gift, user, orderReferenceId, headers}))
|
||||
await expect(amzLib.checkout({
|
||||
gift, user, orderReferenceId, headers,
|
||||
}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 400,
|
||||
message: 'Amount must be at least 1.',
|
||||
@@ -141,18 +144,19 @@ describe('Amazon Payments - Checkout', () => {
|
||||
|
||||
it('should error if user cannot get gems gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
await expect(amzLib.checkout({user, orderReferenceId, headers})).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
await expect(amzLib.checkout({ user, orderReferenceId, headers }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('should gift gems', async () => {
|
||||
let receivingUser = new User();
|
||||
const receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
let gift = {
|
||||
const gift = {
|
||||
type: 'gems',
|
||||
uuid: receivingUser._id,
|
||||
gems: {
|
||||
@@ -160,16 +164,18 @@ describe('Amazon Payments - Checkout', () => {
|
||||
},
|
||||
};
|
||||
amount = 16 / 4;
|
||||
await amzLib.checkout({gift, user, orderReferenceId, headers});
|
||||
await amzLib.checkout({
|
||||
gift, user, orderReferenceId, headers,
|
||||
});
|
||||
|
||||
expectBuyGemsStub(amzLib.constants.PAYMENT_METHOD_GIFT, gift);
|
||||
expectAmazonStubs();
|
||||
});
|
||||
|
||||
it('should gift a subscription', async () => {
|
||||
let receivingUser = new User();
|
||||
const receivingUser = new User();
|
||||
receivingUser.save();
|
||||
let gift = {
|
||||
const gift = {
|
||||
type: 'subscription',
|
||||
subscription: {
|
||||
key: subKey,
|
||||
@@ -178,7 +184,9 @@ describe('Amazon Payments - Checkout', () => {
|
||||
};
|
||||
amount = common.content.subscriptionBlocks[subKey].price;
|
||||
|
||||
await amzLib.checkout({user, orderReferenceId, headers, gift});
|
||||
await amzLib.checkout({
|
||||
user, orderReferenceId, headers, gift,
|
||||
});
|
||||
|
||||
gift.member = receivingUser;
|
||||
expect(paymentCreateSubscritionStub).to.be.calledOnce;
|
||||
|
||||
@@ -2,18 +2,19 @@ import cc from 'coupon-code';
|
||||
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../../helpers/api-unit.helper';
|
||||
import { model as User } from '../../../../../../website/server/models/user';
|
||||
import { model as Coupon } from '../../../../../../website/server/models/coupon';
|
||||
import amzLib from '../../../../../../website/server/libs/payments/amazon';
|
||||
import payments from '../../../../../../website/server/libs/payments/payments';
|
||||
import common from '../../../../../../website/common';
|
||||
|
||||
const i18n = common.i18n;
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Amazon Payments - Subscribe', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
let user, group, amount, billingAgreementId, sub, coupon, groupId, headers;
|
||||
let user; let group; let amount; let billingAgreementId; let sub; let coupon; let groupId; let
|
||||
headers;
|
||||
let amazonSetBillingAgreementDetailsSpy;
|
||||
let amazonConfirmBillingAgreementSpy;
|
||||
let amazonAuthorizeOnBillingAgreementSpy;
|
||||
@@ -60,7 +61,7 @@ describe('Amazon Payments - Subscribe', () => {
|
||||
sinon.stub(common, 'uuid').returns('uuid-generated');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(() => {
|
||||
amzLib.setBillingAgreementDetails.restore();
|
||||
amzLib.confirmBillingAgreement.restore();
|
||||
amzLib.authorizeOnBillingAgreement.restore();
|
||||
@@ -168,7 +169,7 @@ describe('Amazon Payments - Subscribe', () => {
|
||||
sub.key = 'google_6mo';
|
||||
coupon = 'example-coupon';
|
||||
|
||||
let couponModel = new Coupon();
|
||||
const couponModel = new Coupon();
|
||||
couponModel.event = 'google_6mo';
|
||||
await couponModel.save();
|
||||
|
||||
@@ -195,9 +196,9 @@ describe('Amazon Payments - Subscribe', () => {
|
||||
sub.key = 'google_6mo';
|
||||
coupon = 'example-coupon';
|
||||
|
||||
let couponModel = new Coupon();
|
||||
const couponModel = new Coupon();
|
||||
couponModel.event = 'google_6mo';
|
||||
let updatedCouponModel = await couponModel.save();
|
||||
const updatedCouponModel = await couponModel.save();
|
||||
|
||||
sinon.stub(cc, 'validate').returns(updatedCouponModel._id);
|
||||
|
||||
|
||||
@@ -2,16 +2,17 @@ import uuid from 'uuid';
|
||||
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../../helpers/api-unit.helper';
|
||||
import { model as User } from '../../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../../website/server/models/group';
|
||||
import amzLib from '../../../../../../website/server/libs/payments/amazon';
|
||||
import payments from '../../../../../../website/server/libs/payments/payments';
|
||||
|
||||
describe('#upgradeGroupPlan', () => {
|
||||
let spy, data, user, group, uuidString;
|
||||
let spy; let data; let user; let group; let
|
||||
uuidString;
|
||||
|
||||
beforeEach(async function () {
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
|
||||
@@ -46,7 +47,7 @@ describe('#upgradeGroupPlan', () => {
|
||||
data.sub.quantity = 3;
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(() => {
|
||||
amzLib.authorizeOnBillingAgreement.restore();
|
||||
uuid.v4.restore();
|
||||
});
|
||||
@@ -55,7 +56,7 @@ describe('#upgradeGroupPlan', () => {
|
||||
data.paymentMethod = amzLib.constants.PAYMENT_METHOD;
|
||||
await payments.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
updatedGroup.memberCount += 1;
|
||||
await updatedGroup.save();
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/* eslint-disable camelcase */
|
||||
import iapModule from '../../../../../website/server/libs/inAppPurchases';
|
||||
import moment from 'moment';
|
||||
import payments from '../../../../../website/server/libs/payments/payments';
|
||||
import applePayments from '../../../../../website/server/libs/payments/apple';
|
||||
import iap from '../../../../../website/server/libs/inAppPurchases';
|
||||
import {model as User} from '../../../../../website/server/models/user';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import common from '../../../../../website/common';
|
||||
import moment from 'moment';
|
||||
import {mockFindById, restoreFindById} from '../../../../helpers/mongoose.helper';
|
||||
import { mockFindById, restoreFindById } from '../../../../helpers/mongoose.helper';
|
||||
|
||||
const i18n = common.i18n;
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Apple Payments', () => {
|
||||
let subKey = 'basic_3mo';
|
||||
describe('Apple Payments', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
|
||||
describe('verifyGemPurchase', () => {
|
||||
let sku, user, token, receipt, headers;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, paymentBuyGemsStub, iapGetPurchaseDataStub;
|
||||
let sku; let user; let token; let receipt; let
|
||||
headers;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let paymentBuyGemsStub; let
|
||||
iapGetPurchaseDataStub;
|
||||
|
||||
beforeEach(() => {
|
||||
token = 'testToken';
|
||||
@@ -24,33 +25,34 @@ describe('Apple Payments', () => {
|
||||
receipt = `{"token": "${token}", "productId": "${sku}"}`;
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: 'com.habitrpg.ios.Habitica.21gems',
|
||||
transactionId: token,
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
productId: 'com.habitrpg.ios.Habitica.21gems',
|
||||
transactionId: token,
|
||||
}]);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iapModule.getPurchaseData.restore();
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.buyGems.restore();
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
await expect(applePayments.verifyGemPurchase({ user, receipt, headers }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -60,9 +62,9 @@ describe('Apple Payments', () => {
|
||||
|
||||
it('should throw an error if getPurchaseData is invalid', async () => {
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData').returns([]);
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData').returns([]);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
await expect(applePayments.verifyGemPurchase({ user, receipt, headers }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -72,7 +74,7 @@ describe('Apple Payments', () => {
|
||||
|
||||
it('errors if the user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
await expect(applePayments.verifyGemPurchase({ user, receipt, headers }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -85,12 +87,13 @@ describe('Apple Payments', () => {
|
||||
it('errors if amount does not exist', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: 'badProduct',
|
||||
transactionId: token,
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
productId: 'badProduct',
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
await expect(applePayments.verifyGemPurchase({ user, receipt, headers }))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -126,13 +129,14 @@ describe('Apple Payments', () => {
|
||||
gemsCanPurchase.forEach(gemTest => {
|
||||
it(`purchases ${gemTest.productId} gems`, async () => {
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: gemTest.productId,
|
||||
transactionId: token,
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
productId: gemTest.productId,
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await applePayments.verifyGemPurchase({user, receipt, headers});
|
||||
await applePayments.verifyGemPurchase({ user, receipt, headers });
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -160,13 +164,16 @@ describe('Apple Payments', () => {
|
||||
mockFindById(receivingUser);
|
||||
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: gemsCanPurchase[0].productId,
|
||||
transactionId: token,
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
productId: gemsCanPurchase[0].productId,
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
const gift = {uuid: receivingUser._id};
|
||||
await applePayments.verifyGemPurchase({user, gift, receipt, headers});
|
||||
const gift = { uuid: receivingUser._id };
|
||||
await applePayments.verifyGemPurchase({
|
||||
user, gift, receipt, headers,
|
||||
});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -187,8 +194,11 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
describe('subscribe', () => {
|
||||
let sub, sku, user, token, receipt, headers, nextPaymentProcessing;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, paymentsCreateSubscritionStub, iapGetPurchaseDataStub;
|
||||
let sub; let sku; let user; let token; let receipt; let headers; let
|
||||
nextPaymentProcessing;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub;
|
||||
let paymentsCreateSubscritionStub; let
|
||||
iapGetPurchaseDataStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sub = common.content.subscriptionBlocks[subKey];
|
||||
@@ -197,25 +207,25 @@ describe('Apple Payments', () => {
|
||||
token = 'test-token';
|
||||
headers = {};
|
||||
receipt = `{"token": "${token}"}`;
|
||||
nextPaymentProcessing = moment.utc().add({days: 2});
|
||||
nextPaymentProcessing = moment.utc().add({ days: 2 });
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
expirationDate: moment.utc().subtract({day: 1}).toDate(),
|
||||
expirationDate: moment.utc().subtract({ day: 1 }).toDate(),
|
||||
productId: sku,
|
||||
transactionId: token,
|
||||
}, {
|
||||
expirationDate: moment.utc().add({day: 1}).toDate(),
|
||||
expirationDate: moment.utc().add({ day: 1 }).toDate(),
|
||||
productId: 'wrongsku',
|
||||
transactionId: token,
|
||||
}, {
|
||||
expirationDate: moment.utc().add({day: 1}).toDate(),
|
||||
expirationDate: moment.utc().add({ day: 1 }).toDate(),
|
||||
productId: sku,
|
||||
transactionId: token,
|
||||
}]);
|
||||
@@ -223,10 +233,10 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iapModule.getPurchaseData.restore();
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
if (payments.createSubscription.restore) payments.createSubscription.restore();
|
||||
});
|
||||
|
||||
@@ -240,8 +250,8 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing))
|
||||
@@ -272,10 +282,10 @@ describe('Apple Payments', () => {
|
||||
];
|
||||
subOptions.forEach(option => {
|
||||
it(`creates a user subscription for ${option.sku}`, async () => {
|
||||
iapModule.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
expirationDate: moment.utc().add({day: 1}).toDate(),
|
||||
expirationDate: moment.utc().add({ day: 1 }).toDate(),
|
||||
productId: option.sku,
|
||||
transactionId: token,
|
||||
}]);
|
||||
@@ -319,8 +329,10 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
describe('cancelSubscribe ', () => {
|
||||
let user, token, receipt, headers, customerId, expirationDate;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, iapGetPurchaseDataStub, paymentCancelSubscriptionSpy;
|
||||
let user; let token; let receipt; let headers; let customerId; let
|
||||
expirationDate;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let iapGetPurchaseDataStub; let
|
||||
paymentCancelSubscriptionSpy;
|
||||
|
||||
beforeEach(async () => {
|
||||
token = 'test-token';
|
||||
@@ -329,15 +341,15 @@ describe('Apple Payments', () => {
|
||||
customerId = 'test-customerId';
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({
|
||||
expirationDate,
|
||||
});
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{expirationDate: expirationDate.toDate()}]);
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.toDate() }]);
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
|
||||
user = new User();
|
||||
@@ -350,11 +362,11 @@ describe('Apple Payments', () => {
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iapModule.getPurchaseData.restore();
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
|
||||
@@ -370,9 +382,9 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if subscription is still valid', async () => {
|
||||
iapModule.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{expirationDate: expirationDate.add({day: 1}).toDate()}]);
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.add({ day: 1 }).toDate() }]);
|
||||
|
||||
await expect(applePayments.cancelSubscribe(user, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
@@ -383,8 +395,8 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(applePayments.cancelSubscribe(user, headers))
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/* eslint-disable camelcase */
|
||||
import iapModule from '../../../../../website/server/libs/inAppPurchases';
|
||||
import moment from 'moment';
|
||||
import payments from '../../../../../website/server/libs/payments/payments';
|
||||
import googlePayments from '../../../../../website/server/libs/payments/google';
|
||||
import iap from '../../../../../website/server/libs/inAppPurchases';
|
||||
import {model as User} from '../../../../../website/server/models/user';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import common from '../../../../../website/common';
|
||||
import moment from 'moment';
|
||||
import {mockFindById, restoreFindById} from '../../../../helpers/mongoose.helper';
|
||||
import { mockFindById, restoreFindById } from '../../../../helpers/mongoose.helper';
|
||||
|
||||
const i18n = common.i18n;
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Google Payments', () => {
|
||||
let subKey = 'basic_3mo';
|
||||
describe('Google Payments', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
|
||||
describe('verifyGemPurchase', () => {
|
||||
let sku, user, token, receipt, signature, headers;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, paymentBuyGemsStub;
|
||||
let sku; let user; let token; let receipt; let signature; let
|
||||
headers;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let
|
||||
paymentBuyGemsStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sku = 'com.habitrpg.android.habitica.iap.21gems';
|
||||
@@ -24,28 +25,30 @@ describe('Google Payments', () => {
|
||||
signature = '';
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
payments.buyGems.restore();
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
await expect(googlePayments.verifyGemPurchase({
|
||||
user, receipt, signature, headers,
|
||||
}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -56,7 +59,9 @@ describe('Google Payments', () => {
|
||||
it('should throw an error if productId is invalid', async () => {
|
||||
receipt = `{"token": "${token}", "productId": "invalid"}`;
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
await expect(googlePayments.verifyGemPurchase({
|
||||
user, receipt, signature, headers,
|
||||
}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -67,7 +72,9 @@ describe('Google Payments', () => {
|
||||
it('should throw an error if user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
await expect(googlePayments.verifyGemPurchase({
|
||||
user, receipt, signature, headers,
|
||||
}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -79,7 +86,9 @@ describe('Google Payments', () => {
|
||||
|
||||
it('purchases gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await googlePayments.verifyGemPurchase({user, receipt, signature, headers});
|
||||
await googlePayments.verifyGemPurchase({
|
||||
user, receipt, signature, headers,
|
||||
});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -107,8 +116,10 @@ describe('Google Payments', () => {
|
||||
|
||||
mockFindById(receivingUser);
|
||||
|
||||
const gift = {uuid: receivingUser._id};
|
||||
await googlePayments.verifyGemPurchase({user, gift, receipt, signature, headers});
|
||||
const gift = { uuid: receivingUser._id };
|
||||
await googlePayments.verifyGemPurchase({
|
||||
user, gift, receipt, signature, headers,
|
||||
});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -131,8 +142,10 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
describe('subscribe', () => {
|
||||
let sub, sku, user, token, receipt, signature, headers, nextPaymentProcessing;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, paymentsCreateSubscritionStub;
|
||||
let sub; let sku; let user; let token; let receipt; let signature; let headers; let
|
||||
nextPaymentProcessing;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let
|
||||
paymentsCreateSubscritionStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sub = common.content.subscriptionBlocks[subKey];
|
||||
@@ -142,30 +155,31 @@ describe('Google Payments', () => {
|
||||
headers = {};
|
||||
receipt = `{"token": "${token}"}`;
|
||||
signature = '';
|
||||
nextPaymentProcessing = moment.utc().add({days: 2});
|
||||
nextPaymentProcessing = moment.utc().add({ days: 2 });
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
payments.createSubscription.restore();
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(googlePayments.subscribe(sku, user, receipt, signature, headers, nextPaymentProcessing))
|
||||
await expect(googlePayments
|
||||
.subscribe(sku, user, receipt, signature, headers, nextPaymentProcessing))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -176,7 +190,8 @@ describe('Google Payments', () => {
|
||||
it('should throw an error if sku is invalid', async () => {
|
||||
sku = 'invalid';
|
||||
|
||||
await expect(googlePayments.subscribe(sku, user, receipt, signature, headers, nextPaymentProcessing))
|
||||
await expect(googlePayments
|
||||
.subscribe(sku, user, receipt, signature, headers, nextPaymentProcessing))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -203,15 +218,17 @@ describe('Google Payments', () => {
|
||||
paymentMethod: googlePayments.constants.PAYMENT_METHOD_GOOGLE,
|
||||
sub,
|
||||
headers,
|
||||
additionalData: {data: receipt, signature},
|
||||
additionalData: { data: receipt, signature },
|
||||
nextPaymentProcessing,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelSubscribe ', () => {
|
||||
let user, token, receipt, signature, headers, customerId, expirationDate;
|
||||
let iapSetupStub, iapValidateStub, iapIsValidatedStub, iapGetPurchaseDataStub, paymentCancelSubscriptionSpy;
|
||||
let user; let token; let receipt; let signature; let headers; let customerId; let
|
||||
expirationDate;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let iapGetPurchaseDataStub; let
|
||||
paymentCancelSubscriptionSpy;
|
||||
|
||||
beforeEach(async () => {
|
||||
token = 'test-token';
|
||||
@@ -221,15 +238,15 @@ describe('Google Payments', () => {
|
||||
customerId = 'test-customerId';
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapSetupStub = sinon.stub(iapModule, 'setup')
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iapModule, 'validate')
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({
|
||||
expirationDate,
|
||||
});
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{expirationDate: expirationDate.toDate()}]);
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.toDate() }]);
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
|
||||
user = new User();
|
||||
@@ -237,16 +254,16 @@ describe('Google Payments', () => {
|
||||
user.purchased.plan.customerId = customerId;
|
||||
user.purchased.plan.paymentMethod = googlePayments.constants.PAYMENT_METHOD_GOOGLE;
|
||||
user.purchased.plan.planId = subKey;
|
||||
user.purchased.plan.additionalData = {data: receipt, signature};
|
||||
user.purchased.plan.additionalData = { data: receipt, signature };
|
||||
|
||||
paymentCancelSubscriptionSpy = sinon.stub(payments, 'cancelSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
iapModule.setup.restore();
|
||||
iapModule.validate.restore();
|
||||
iapModule.isValidated.restore();
|
||||
iapModule.getPurchaseData.restore();
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
|
||||
@@ -262,9 +279,9 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if subscription is still valid', async () => {
|
||||
iapModule.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{expirationDate: expirationDate.add({day: 1}).toDate()}]);
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.add({ day: 1 }).toDate() }]);
|
||||
|
||||
await expect(googlePayments.cancelSubscribe(user, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
@@ -275,8 +292,8 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
iapModule.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
iap.isValidated.restore();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(googlePayments.cancelSubscribe(user, headers))
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import * as sender from '../../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../../website/server/libs/payments/payments';
|
||||
import api from '../../../../../../website/server/libs/payments/payments';
|
||||
import { model as User } from '../../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../../website/server/models/group';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../../helpers/api-unit.helper';
|
||||
import i18n from '../../../../../../website/common/script/i18n';
|
||||
|
||||
describe('Canceling a subscription for group', () => {
|
||||
let plan, group, user, data;
|
||||
let plan; let group; let user; let
|
||||
data;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
@@ -67,9 +68,9 @@ describe('Canceling a subscription for group', () => {
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
const daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(29, 30); // 1 month +/- 1 days
|
||||
});
|
||||
@@ -81,9 +82,9 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
const daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(89, 90); // 3 months +/- 1 days
|
||||
});
|
||||
@@ -95,9 +96,9 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
const daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(38, 39); // should be about 1 month + 1/3 month
|
||||
});
|
||||
@@ -108,9 +109,9 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
const daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(13, 15);
|
||||
});
|
||||
@@ -122,7 +123,7 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
@@ -134,12 +135,12 @@ describe('Canceling a subscription for group', () => {
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(user._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-cancel-subscription');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
]);
|
||||
});
|
||||
|
||||
it('prevents non group leader from managing subscription', async () => {
|
||||
let groupMember = new User();
|
||||
const groupMember = new User();
|
||||
data.user = groupMember;
|
||||
data.groupId = group._id;
|
||||
|
||||
@@ -160,7 +161,7 @@ describe('Canceling a subscription for group', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let newLeader = new User();
|
||||
const newLeader = new User();
|
||||
updatedGroup.leader = newLeader._id;
|
||||
await updatedGroup.save();
|
||||
|
||||
@@ -192,15 +193,15 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
let daysTillTermination = moment(updatedLeader.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const updatedLeader = await User.findById(user._id).exec();
|
||||
const daysTillTermination = moment(updatedLeader.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
expect(daysTillTermination).to.be.within(2, 3); // only a few days
|
||||
});
|
||||
|
||||
it('sends an email to members of group', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
@@ -214,8 +215,8 @@ describe('Canceling a subscription for group', () => {
|
||||
expect(sender.sendTxn.thirdCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.thirdCall.args[1]).to.equal('group-member-cancel');
|
||||
expect(sender.sendTxn.thirdCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{ name: 'LEADER', content: user.profile.name },
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -223,7 +224,7 @@ describe('Canceling a subscription for group', () => {
|
||||
plan.key = 'basic_earned';
|
||||
plan.customerId = api.constants.UNLIMITED_CUSTOMER_ID;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -233,12 +234,12 @@ describe('Canceling a subscription for group', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
const updatedLeader = await User.findById(user._id).exec();
|
||||
expect(updatedLeader.purchased.plan.dateTerminated).to.not.exist;
|
||||
});
|
||||
|
||||
it('does not cancel a user subscription if they are still in another active group plan', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
@@ -252,10 +253,10 @@ describe('Canceling a subscription for group', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
const firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
const extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
const group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
@@ -291,10 +292,10 @@ describe('Canceling a subscription for group', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
const firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
const extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
const group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
|
||||
@@ -3,7 +3,7 @@ import stripeModule from 'stripe';
|
||||
import nconf from 'nconf';
|
||||
|
||||
import * as sender from '../../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../../website/server/libs/payments/payments';
|
||||
import api from '../../../../../../website/server/libs/payments/payments';
|
||||
import amzLib from '../../../../../../website/server/libs/payments/amazon';
|
||||
import paypalPayments from '../../../../../../website/server/libs/payments/paypal';
|
||||
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
|
||||
@@ -11,7 +11,7 @@ import { model as User } from '../../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../../website/server/models/group';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../../helpers/api-unit.helper';
|
||||
|
||||
describe('Purchasing a group plan for group', () => {
|
||||
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE = 'Google_subscription';
|
||||
@@ -19,10 +19,11 @@ describe('Purchasing a group plan for group', () => {
|
||||
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL = 'normal_subscription';
|
||||
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE = 'no_subscription';
|
||||
|
||||
let plan, group, user, data;
|
||||
let stripe = stripeModule('test');
|
||||
let groupLeaderName = 'sender';
|
||||
let groupName = 'test group';
|
||||
let plan; let group; let user; let
|
||||
data;
|
||||
const stripe = stripeModule('test');
|
||||
const groupLeaderName = 'sender';
|
||||
const groupName = 'test group';
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
@@ -68,14 +69,17 @@ describe('Purchasing a group plan for group', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let subscriptionId = 'subId';
|
||||
const subscriptionId = 'subId';
|
||||
sinon.stub(stripe.customers, 'del').resolves({});
|
||||
|
||||
let currentPeriodEndTimeStamp = moment().add(3, 'months').unix();
|
||||
const currentPeriodEndTimeStamp = moment().add(3, 'months').unix();
|
||||
sinon.stub(stripe.customers, 'retrieve')
|
||||
.resolves({
|
||||
subscriptions: {
|
||||
data: [{id: subscriptionId, current_period_end: currentPeriodEndTimeStamp}], // eslint-disable-line camelcase
|
||||
data: [{
|
||||
id: subscriptionId,
|
||||
current_period_end: currentPeriodEndTimeStamp,
|
||||
}], // eslint-disable-line camelcase
|
||||
},
|
||||
});
|
||||
|
||||
@@ -95,7 +99,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
expect(updatedGroup.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedGroup.purchased.plan.customerId).to.eql('customer-id');
|
||||
@@ -126,7 +130,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.within(1.9, 2);
|
||||
});
|
||||
|
||||
@@ -139,7 +143,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
@@ -150,7 +154,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
const updatedLeader = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedLeader.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedLeader.purchased.plan.customerId).to.eql('group-plan');
|
||||
@@ -166,7 +170,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('sends an email to member of group who was not a subscriber', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
@@ -179,9 +183,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE},
|
||||
{ name: 'LEADER', content: user.profile.name },
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE },
|
||||
]);
|
||||
// confirm that the other email sent is appropriate:
|
||||
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
|
||||
@@ -189,7 +193,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('sends one email to subscribed member of group, stating subscription is cancelled (Stripe)', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -205,9 +209,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL},
|
||||
{ name: 'LEADER', content: user.profile.name },
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
|
||||
]);
|
||||
// confirm that the other email sent is not a cancel-subscription email:
|
||||
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
|
||||
@@ -218,11 +222,11 @@ describe('Purchasing a group plan for group', () => {
|
||||
sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
BillingAgreementStatus: { State: 'Closed' },
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = amzLib.constants.PAYMENT_METHOD;
|
||||
@@ -238,9 +242,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL},
|
||||
{ name: 'LEADER', content: user.profile.name },
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
|
||||
]);
|
||||
// confirm that the other email sent is not a cancel-subscription email:
|
||||
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
|
||||
@@ -259,7 +263,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = paypalPayments.constants.PAYMENT_METHOD;
|
||||
@@ -275,9 +279,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL},
|
||||
{ name: 'LEADER', content: user.profile.name },
|
||||
{ name: 'GROUP_NAME', content: group.name },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
|
||||
]);
|
||||
// confirm that the other email sent is not a cancel-subscription email:
|
||||
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
|
||||
@@ -292,7 +296,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.customerId = 'random';
|
||||
plan.paymentMethod = api.constants.GOOGLE_PAYMENT_METHOD;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -310,9 +314,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.args[1][0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.args[1][1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.args[1][2]).to.eql([
|
||||
{name: 'LEADER', content: groupLeaderName},
|
||||
{name: 'GROUP_NAME', content: groupName},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE},
|
||||
{ name: 'LEADER', content: groupLeaderName },
|
||||
{ name: 'GROUP_NAME', content: groupName },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE },
|
||||
]);
|
||||
expect(sender.sendTxn.args[2][0]._id).to.equal(group.leader);
|
||||
expect(sender.sendTxn.args[2][1]).to.equal('group-member-join');
|
||||
@@ -325,7 +329,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.customerId = 'random';
|
||||
plan.paymentMethod = api.constants.IOS_PAYMENT_METHOD;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -343,9 +347,9 @@ describe('Purchasing a group plan for group', () => {
|
||||
expect(sender.sendTxn.args[1][0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.args[1][1]).to.equal('group-member-join');
|
||||
expect(sender.sendTxn.args[1][2]).to.eql([
|
||||
{name: 'LEADER', content: groupLeaderName},
|
||||
{name: 'GROUP_NAME', content: groupName},
|
||||
{name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_IOS},
|
||||
{ name: 'LEADER', content: groupLeaderName },
|
||||
{ name: 'GROUP_NAME', content: groupName },
|
||||
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_IOS },
|
||||
]);
|
||||
expect(sender.sendTxn.args[2][0]._id).to.equal(group.leader);
|
||||
expect(sender.sendTxn.args[2][1]).to.equal('group-member-join');
|
||||
@@ -354,7 +358,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('adds months to members with existing gift subscription', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -378,7 +382,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
@@ -392,7 +396,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('adds months to members with existing multi-month gift subscription', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -414,7 +418,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
@@ -428,7 +432,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Stripe)', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -450,11 +454,11 @@ describe('Purchasing a group plan for group', () => {
|
||||
sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
BillingAgreementStatus: { State: 'Closed' },
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = amzLib.constants.PAYMENT_METHOD;
|
||||
@@ -470,7 +474,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(3, 5);
|
||||
});
|
||||
@@ -485,7 +489,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = paypalPayments.constants.PAYMENT_METHOD;
|
||||
@@ -500,7 +504,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
paypalPayments.paypalBillingAgreementGet.restore();
|
||||
@@ -511,7 +515,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
it('adds months to members with existing recurring subscription (iOS)');
|
||||
|
||||
it('adds months to members who already cancelled but not yet terminated recurring subscription', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -527,13 +531,13 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
});
|
||||
|
||||
it('adds months to members who already cancelled but not yet terminated group plan subscription', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = api.constants.GROUP_PLAN_PAYMENT_METHOD;
|
||||
@@ -550,12 +554,12 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(3, 4);
|
||||
});
|
||||
|
||||
it('resets date terminated if user has old subscription', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -570,13 +574,13 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.not.exist;
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription and includes existing extraMonths', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -591,13 +595,13 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(7, 9);
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription and ignores existing negative extraMonths', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
@@ -612,23 +616,23 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
});
|
||||
|
||||
it('does not override gemsBought, mysteryItems, dateCreated, and consective fields', async () => {
|
||||
let planCreatedDate = moment().toDate();
|
||||
let mysteryItem = {title: 'item'};
|
||||
let mysteryItems = [mysteryItem];
|
||||
let consecutive = {
|
||||
const planCreatedDate = moment().toDate();
|
||||
const mysteryItem = { title: 'item' };
|
||||
const mysteryItems = [mysteryItem];
|
||||
const consecutive = {
|
||||
trinkets: 3,
|
||||
gemCapExtra: 20,
|
||||
offset: 1,
|
||||
count: 13,
|
||||
};
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
|
||||
plan.key = 'basic_earned';
|
||||
@@ -647,7 +651,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.equal(3);
|
||||
expect(updatedUser.purchased.plan.mysteryItems[0]).to.eql(mysteryItem);
|
||||
@@ -659,7 +663,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('does not modify a user with a group subscription when they join another group', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
@@ -673,10 +677,10 @@ describe('Purchasing a group plan for group', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
const firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
const extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
const group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
@@ -703,7 +707,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
});
|
||||
|
||||
it('does not remove a user who is in two groups plans and leaves one', async () => {
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
@@ -717,10 +721,10 @@ describe('Purchasing a group plan for group', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
const firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
const extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
const group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
@@ -733,7 +737,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
const updatedGroup = await Group.findById(group._id).exec();
|
||||
await updatedGroup.leave(recipient);
|
||||
|
||||
updatedUser = await User.findById(recipient._id).exec();
|
||||
@@ -753,7 +757,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.key = 'basic_earned';
|
||||
plan.customerId = api.constants.UNLIMITED_CUSTOMER_ID;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -765,7 +769,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql(api.constants.UNLIMITED_CUSTOMER_ID);
|
||||
@@ -782,7 +786,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.customerId = 'random';
|
||||
plan.paymentMethod = api.constants.GOOGLE_PAYMENT_METHOD;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -794,7 +798,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('random');
|
||||
@@ -811,7 +815,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.customerId = 'random';
|
||||
plan.paymentMethod = api.constants.IOS_PAYMENT_METHOD;
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -823,7 +827,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('random');
|
||||
@@ -841,7 +845,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
plan.customerId = api.constants.GROUP_PLAN_CUSTOMER_ID;
|
||||
plan.dateTerminated = moment().add(1, 'months');
|
||||
|
||||
let recipient = new User();
|
||||
const recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
@@ -853,7 +857,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
const updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql(api.constants.GROUP_PLAN_CUSTOMER_ID);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
|
||||
export async function createNonLeaderGroupMember (group) {
|
||||
let nonLeader = new User();
|
||||
export async function createNonLeaderGroupMember (group) { // eslint-disable-line import/prefer-default-export, max-len
|
||||
const nonLeader = new User();
|
||||
nonLeader.guilds.push(group._id);
|
||||
return await nonLeader.save();
|
||||
return nonLeader.save();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import * as sender from '../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../website/server/libs/payments/payments';
|
||||
import analytics from '../../../../../website/server/libs/analyticsService';
|
||||
import notifications from '../../../../../website/server/libs/pushNotifications';
|
||||
import api from '../../../../../website/server/libs/payments/payments';
|
||||
import * as analytics from '../../../../../website/server/libs/analyticsService';
|
||||
import * as notifications from '../../../../../website/server/libs/pushNotifications';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { translate as t } from '../../../../helpers/api-integration/v3';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../helpers/api-unit.helper.js';
|
||||
} from '../../../../helpers/api-unit.helper';
|
||||
|
||||
describe('payments/index', () => {
|
||||
let user, group, data, plan;
|
||||
let user; let group; let data; let
|
||||
plan;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
@@ -102,7 +103,7 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('does not set negative extraMonths if plan has past dateTerminated date', async () => {
|
||||
let dateTerminated = moment().subtract(2, 'months').toDate();
|
||||
const dateTerminated = moment().subtract(2, 'months').toDate();
|
||||
recipient.purchased.plan.dateTerminated = dateTerminated;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -120,7 +121,7 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('adds to date terminated for an existing plan with a future terminated date', async () => {
|
||||
let dateTerminated = moment().add(1, 'months').toDate();
|
||||
const dateTerminated = moment().add(1, 'months').toDate();
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.dateTerminated = dateTerminated;
|
||||
|
||||
@@ -130,7 +131,7 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('replaces date terminated for an account with a past terminated date', async () => {
|
||||
let dateTerminated = moment().subtract(1, 'months').toDate();
|
||||
const dateTerminated = moment().subtract(1, 'months').toDate();
|
||||
recipient.purchased.plan.dateTerminated = dateTerminated;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -208,18 +209,21 @@ describe('payments/index', () => {
|
||||
|
||||
it('sends a private message about the gift', async () => {
|
||||
await api.createSubscription(data);
|
||||
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`';
|
||||
const msg = '`Hello recipient, sender has sent you 3 months of subscription!`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledOnce;
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
expect(user.sendMessage).to.be.calledWith(
|
||||
recipient,
|
||||
{ receiverMsg: msg, senderMsg: msg, save: false },
|
||||
);
|
||||
});
|
||||
|
||||
it('sends an email about the gift', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.calledWith(recipient, 'gifted-subscription', [
|
||||
{name: 'GIFTER', content: 'sender'},
|
||||
{name: 'X_MONTHS_SUBSCRIPTION', content: 3},
|
||||
{ name: 'GIFTER', content: 'sender' },
|
||||
{ name: 'X_MONTHS_SUBSCRIPTION', content: 3 },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -416,8 +420,8 @@ describe('payments/index', () => {
|
||||
|
||||
context('Mystery Items', () => {
|
||||
it('awards mystery items when within the timeframe for a mystery item', async () => {
|
||||
let mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
let fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
const mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
const fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
|
||||
@@ -437,7 +441,7 @@ describe('payments/index', () => {
|
||||
|
||||
it('does not awards mystery items when not within the timeframe for a mystery item', async () => {
|
||||
const noMysteryItemTimeframe = 1462183920000; // May 2nd 2016
|
||||
let fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
const fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -449,7 +453,7 @@ describe('payments/index', () => {
|
||||
|
||||
it('does not add a notification for mystery items if none was awarded', async () => {
|
||||
const noMysteryItemTimeframe = 1462183920000; // May 2nd 2016
|
||||
let fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
const fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -461,9 +465,9 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('does not award mystery item when user already owns the item', async () => {
|
||||
let mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
let fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
let mayMysteryItem = 'armor_mystery_201605';
|
||||
const mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
const fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
const mayMysteryItem = 'armor_mystery_201605';
|
||||
user.items.gear.owned[mayMysteryItem] = true;
|
||||
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
@@ -477,9 +481,9 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('does not award mystery item when user already has the item in the mystery box', async () => {
|
||||
let mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
let fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
let mayMysteryItem = 'armor_mystery_201605';
|
||||
const mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
const fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
const mayMysteryItem = 'armor_mystery_201605';
|
||||
user.purchased.plan.mysteryItems = [mayMysteryItem];
|
||||
|
||||
sandbox.spy(user.purchased.plan.mysteryItems, 'push');
|
||||
@@ -504,8 +508,8 @@ describe('payments/index', () => {
|
||||
it('adds a month termination date by default', async () => {
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(29, 30); // 1 month +/- 1 days
|
||||
});
|
||||
@@ -515,8 +519,8 @@ describe('payments/index', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(89, 90); // 3 months +/- 1 days
|
||||
});
|
||||
@@ -526,8 +530,8 @@ describe('payments/index', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(38, 39); // should be about 1 month + 1/3 month
|
||||
});
|
||||
@@ -537,8 +541,8 @@ describe('payments/index', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(13, 15);
|
||||
});
|
||||
@@ -549,8 +553,8 @@ describe('payments/index', () => {
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
const now = new Date();
|
||||
const daysTillTermination = moment(user.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(13, 15);
|
||||
});
|
||||
@@ -641,9 +645,10 @@ describe('payments/index', () => {
|
||||
|
||||
it('sends a message from purchaser to recipient', async () => {
|
||||
await api.buyGems(data);
|
||||
let msg = '\`Hello recipient, sender has sent you 4 gems!\`';
|
||||
const msg = '`Hello recipient, sender has sent you 4 gems!`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
expect(user.sendMessage).to.be
|
||||
.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
});
|
||||
|
||||
it('sends a message from purchaser to recipient wtih custom message', async () => {
|
||||
@@ -652,7 +657,8 @@ describe('payments/index', () => {
|
||||
await api.buyGems(data);
|
||||
|
||||
const msg = `\`Hello recipient, sender has sent you 4 gems!\` ${data.gift.message}`;
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
expect(user.sendMessage).to.be
|
||||
.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
});
|
||||
|
||||
it('sends a push notification if user did not gift to self', async () => {
|
||||
@@ -671,8 +677,8 @@ describe('payments/index', () => {
|
||||
});
|
||||
await api.buyGems(data);
|
||||
|
||||
let [recipientsMessageContent, sendersMessageContent] = ['en', 'en'].map((lang) => {
|
||||
let messageContent = t('giftedGemsFull', {
|
||||
const [recipientsMessageContent, sendersMessageContent] = ['en', 'en'].map(lang => {
|
||||
const messageContent = t('giftedGemsFull', {
|
||||
username: recipient.profile.name,
|
||||
sender: user.profile.name,
|
||||
gemAmount: data.gift.gems.amount,
|
||||
@@ -681,7 +687,10 @@ describe('payments/index', () => {
|
||||
return `\`${messageContent}\``;
|
||||
});
|
||||
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: recipientsMessageContent, senderMsg: sendersMessageContent, save: false });
|
||||
expect(user.sendMessage).to.be.calledWith(
|
||||
recipient,
|
||||
{ receiverMsg: recipientsMessageContent, senderMsg: sendersMessageContent, save: false },
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -693,7 +702,7 @@ describe('payments/index', () => {
|
||||
|
||||
await api.addSubToGroupUser(user, group);
|
||||
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
const updatedUser = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
@@ -709,17 +718,17 @@ describe('payments/index', () => {
|
||||
it('awards the Royal Purple Jackalope pet', async () => {
|
||||
await api.addSubToGroupUser(user, group);
|
||||
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
const updatedUser = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedUser.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
});
|
||||
|
||||
it('saves previously unused Mystery Items and Hourglasses for an expired subscription', async () => {
|
||||
let planExpirationDate = new Date();
|
||||
const planExpirationDate = new Date();
|
||||
planExpirationDate.setDate(planExpirationDate.getDate() - 2);
|
||||
let mysteryItem = 'item';
|
||||
let mysteryItems = [mysteryItem];
|
||||
let consecutive = {
|
||||
const mysteryItem = 'item';
|
||||
const mysteryItems = [mysteryItem];
|
||||
const consecutive = {
|
||||
trinkets: 3,
|
||||
};
|
||||
|
||||
@@ -735,7 +744,7 @@ describe('payments/index', () => {
|
||||
await user.save();
|
||||
await api.addSubToGroupUser(user, group);
|
||||
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
const updatedUser = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.mysteryItems[0]).to.eql(mysteryItem);
|
||||
expect(updatedUser.purchased.plan.consecutive.trinkets).to.equal(consecutive.trinkets);
|
||||
|
||||
@@ -5,8 +5,10 @@ import { model as User } from '../../../../../../website/server/models/user';
|
||||
|
||||
describe('checkout success', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
let user, gift, customerId, paymentId;
|
||||
let paypalPaymentExecuteStub, paymentBuyGemsStub, paymentsCreateSubscritionStub;
|
||||
let user; let gift; let customerId; let
|
||||
paymentId;
|
||||
let paypalPaymentExecuteStub; let paymentBuyGemsStub; let
|
||||
paymentsCreateSubscritionStub;
|
||||
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
@@ -25,7 +27,9 @@ describe('checkout success', () => {
|
||||
});
|
||||
|
||||
it('purchases gems', async () => {
|
||||
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||
await paypalPayments.checkoutSuccess({
|
||||
user, gift, paymentId, customerId,
|
||||
});
|
||||
|
||||
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||
@@ -38,7 +42,7 @@ describe('checkout success', () => {
|
||||
});
|
||||
|
||||
it('gifts gems', async () => {
|
||||
let receivingUser = new User();
|
||||
const receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
gift = {
|
||||
type: 'gems',
|
||||
@@ -48,7 +52,9 @@ describe('checkout success', () => {
|
||||
},
|
||||
};
|
||||
|
||||
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||
await paypalPayments.checkoutSuccess({
|
||||
user, gift, paymentId, customerId,
|
||||
});
|
||||
|
||||
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||
@@ -62,7 +68,7 @@ describe('checkout success', () => {
|
||||
});
|
||||
|
||||
it('gifts subscription', async () => {
|
||||
let receivingUser = new User();
|
||||
const receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
gift = {
|
||||
type: 'subscription',
|
||||
@@ -72,7 +78,9 @@ describe('checkout success', () => {
|
||||
},
|
||||
};
|
||||
|
||||
await paypalPayments.checkoutSuccess({user, gift, paymentId, customerId});
|
||||
await paypalPayments.checkoutSuccess({
|
||||
user, gift, paymentId, customerId,
|
||||
});
|
||||
|
||||
expect(paypalPaymentExecuteStub).to.be.calledOnce;
|
||||
expect(paypalPaymentExecuteStub).to.be.calledWith(paymentId, { payer_id: customerId });
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user