From a0e28f7db4d90afea37b32a5df5041ec0be7c773 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:00:34 -0500 Subject: [PATCH 01/30] build(deps): bump superagent from 8.0.2 to 8.0.3 (#14351) Bumps [superagent](https://github.com/visionmedia/superagent) from 8.0.2 to 8.0.3. - [Release notes](https://github.com/visionmedia/superagent/releases) - [Changelog](https://github.com/visionmedia/superagent/blob/master/HISTORY.md) - [Commits](https://github.com/visionmedia/superagent/compare/v8.0.2...v8.0.3) --- updated-dependencies: - dependency-name: superagent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 227295a879..260ae8b3e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3067,7 +3067,7 @@ "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "asn1": { "version": "0.2.4", @@ -5485,7 +5485,7 @@ "dezalgo": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -14283,9 +14283,9 @@ "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==" }, "superagent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.2.tgz", - "integrity": "sha512-QtYZ9uaNAMexI7XWl2vAXAh0j4q9H7T0WVEI/y5qaUB3QLwxo+voUgCQ217AokJzUTIVOp0RTo7fhZrwhD7A2Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.3.tgz", + "integrity": "sha512-oBC+aNsCjzzjmO5AOPBPFS+Z7HPzlx+DQr/aHwM08kI+R24gsDmAS1LMfza1fK+P+SKlTAoNZpOvooE/pRO1HA==", "requires": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.3", @@ -14296,7 +14296,7 @@ "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "dependencies": { "debug": { diff --git a/package.json b/package.json index abd7e3d727..8522578946 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "rimraf": "^3.0.2", "short-uuid": "^4.2.2", "stripe": "^10.13.0", - "superagent": "^8.0.2", + "superagent": "^8.0.3", "universal-analytics": "^0.5.3", "useragent": "^2.1.9", "uuid": "^8.3.2", From 02b11a61bc7a933b015d8ee290ec3cde42053c6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:00:51 -0500 Subject: [PATCH 02/30] build(deps): bump dompurify from 2.4.0 to 2.4.1 in /website/client (#14352) Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/2.4.0...2.4.1) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/client/package-lock.json | 27 +++++++++------------------ website/client/package.json | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/website/client/package-lock.json b/website/client/package-lock.json index b80407f8ae..5e74b91056 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -17072,9 +17072,9 @@ } }, "dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", + "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==" }, "domutils": { "version": "1.7.0", @@ -28824,7 +28824,6 @@ "version": "npm:vue-loader@16.8.3", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz", "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==", - "optional": true, "requires": { "chalk": "^4.1.0", "hash-sum": "^2.0.0", @@ -28835,7 +28834,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "optional": true, "requires": { "color-convert": "^2.0.1" } @@ -28844,7 +28842,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -28854,7 +28851,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, "requires": { "color-name": "~1.1.4" } @@ -28862,26 +28858,22 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "optional": true + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", - "optional": true, + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -28892,7 +28884,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, "requires": { "has-flag": "^4.0.0" } diff --git a/website/client/package.json b/website/client/package.json index 512d23fa0d..ac50e3b9a2 100644 --- a/website/client/package.json +++ b/website/client/package.json @@ -33,7 +33,7 @@ "bootstrap-vue": "^2.22.0", "chai": "^4.3.6", "core-js": "^3.26.0", - "dompurify": "^2.4.0", + "dompurify": "^2.4.1", "eslint": "^6.8.0", "eslint-config-habitrpg": "^6.2.0", "eslint-plugin-mocha": "^5.3.0", From 837c1c20a34277e8de390c30b309741dad936743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:01:06 -0500 Subject: [PATCH 03/30] build(deps-dev): bump sinon from 14.0.1 to 14.0.2 (#14353) Bumps [sinon](https://github.com/sinonjs/sinon) from 14.0.1 to 14.0.2. - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v14.0.1...v14.0.2) --- updated-dependencies: - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 71 ++++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 260ae8b3e1..aedc37bc01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2038,9 +2038,9 @@ "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" }, "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -2053,15 +2053,26 @@ "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", + "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } } }, "@sinonjs/samsam": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz", - "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.6.0", + "@sinonjs/commons": "^2.0.0", "lodash.get": "^4.4.2", "type-detect": "^4.0.8" } @@ -10130,7 +10141,7 @@ "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, "lodash.includes": { @@ -11397,22 +11408,42 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "nise": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz", - "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.2.tgz", + "integrity": "sha512-+gQjFi8v+tkfCuSCxfURHLhRhniE/+IaYbIphxAN2JRR9SHKhY8hgXpaXiYfHdw+gcGe4buxgbprBQFab9FkhA==", "dev": true, "requires": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": ">=5", + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^7.0.4", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "path-to-regexp": "^1.7.0" }, "dependencies": { + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", + "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "path-to-regexp": { @@ -13595,16 +13626,16 @@ } }, "sinon": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.1.tgz", - "integrity": "sha512-JhJ0jCiyBWVAHDS+YSjgEbDn7Wgz9iIjA1/RK+eseJN0vAAWIWiXBdrnb92ELPyjsfreCYntD1ORtLSfIrlvSQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.2.tgz", + "integrity": "sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w==", "dev": true, "requires": { - "@sinonjs/commons": "^1.8.3", + "@sinonjs/commons": "^2.0.0", "@sinonjs/fake-timers": "^9.1.2", - "@sinonjs/samsam": "^6.1.1", + "@sinonjs/samsam": "^7.0.1", "diff": "^5.0.0", - "nise": "^5.1.1", + "nise": "^5.1.2", "supports-color": "^7.2.0" }, "dependencies": { diff --git a/package.json b/package.json index 8522578946..805b0e800b 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "monk": "^7.3.4", "require-again": "^2.0.0", "run-rs": "^0.7.7", - "sinon": "^14.0.1", + "sinon": "^14.0.2", "sinon-chai": "^3.7.0", "sinon-stub-promise": "^4.0.0" }, From 25c7d52d6aa6b4cb3ea6cafacaa6f210b0501875 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:01:23 -0500 Subject: [PATCH 04/30] build(deps-dev): bump chai from 4.3.6 to 4.3.7 (#14354) Bumps [chai](https://github.com/chaijs/chai) from 4.3.6 to 4.3.7. - [Release notes](https://github.com/chaijs/chai/releases) - [Changelog](https://github.com/chaijs/chai/blob/4.x.x/History.md) - [Commits](https://github.com/chaijs/chai/compare/v4.3.6...v4.3.7) --- updated-dependencies: - dependency-name: chai dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 22 +++++++++++----------- package.json | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index aedc37bc01..f32e964fc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4288,14 +4288,14 @@ "integrity": "sha512-z0R4cT5357OEAVkP1CEFTHz1egpu2gYiWm2WJOY/sQDhojEXUYL4m3v2kYi5wER3PkMRL+GgfDhed2kGzrHSZA==" }, "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", - "deep-eql": "^3.0.1", + "deep-eql": "^4.1.2", "get-func-name": "^2.0.0", "loupe": "^2.3.1", "pathval": "^1.1.1", @@ -5340,9 +5340,9 @@ } }, "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", + "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -7581,7 +7581,7 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true }, "get-intrinsic": { @@ -10244,9 +10244,9 @@ } }, "loupe": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.1.tgz", - "integrity": "sha512-EN1D3jyVmaX4tnajVlfbREU4axL647hLec1h/PXAb8CPDMJiYitcWF2UeLVNttRqaIqQs4x+mRvXf+d+TlDrCA==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dev": true, "requires": { "get-func-name": "^2.0.0" diff --git a/package.json b/package.json index 805b0e800b..733e862d4a 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ }, "devDependencies": { "axios": "^0.27.2", - "chai": "^4.3.6", + "chai": "^4.3.7", "chai-as-promised": "^7.1.1", "chai-moment": "^0.1.0", "chalk": "^5.1.2", From febffb3f0774d279e411dadb714ed9a736ad2136 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 14:26:49 -0600 Subject: [PATCH 05/30] Revert "Fix double subscriptions, second attempt (#14345)" This reverts commit 1a5cba57b7e45cc14fa2a4bc752fa2826e21bc58. --- test/api/unit/libs/payments/apple.test.js | 3 -- test/api/unit/libs/payments/payments.test.js | 13 ------ website/server/libs/payments/subscriptions.js | 40 +++++++++++++++---- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/test/api/unit/libs/payments/apple.test.js b/test/api/unit/libs/payments/apple.test.js index a086677292..1aefe2cb51 100644 --- a/test/api/unit/libs/payments/apple.test.js +++ b/test/api/unit/libs/payments/apple.test.js @@ -326,12 +326,9 @@ describe('Apple Payments', () => { it('errors when a user is already subscribed', async () => { payments.createSubscription.restore(); user = new User(); - user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await user.save(); await applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing); - user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - await user.save(); await expect(applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing)) .to.eventually.be.rejected.and.to.eql({ diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 7e306f94fd..48d6325546 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -350,10 +350,6 @@ describe('payments/index', () => { }); context('Purchasing a subscription for self', () => { - beforeEach(() => { - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - }); - it('creates a subscription', async () => { expect(user.purchased.plan.planId).to.not.exist; @@ -380,7 +376,6 @@ describe('payments/index', () => { user.purchased.plan = plan; user.purchased.plan.dateTerminated = moment(new Date()).add(2, 'months'); expect(user.purchased.plan.extraMonths).to.eql(0); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -391,7 +386,6 @@ describe('payments/index', () => { user.purchased.plan = plan; user.purchased.plan.dateTerminated = moment(new Date()).subtract(2, 'months'); expect(user.purchased.plan.extraMonths).to.eql(0); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -401,7 +395,6 @@ describe('payments/index', () => { it('does not reset Gold-to-Gems cap on additional subscription', async () => { user.purchased.plan = plan; user.purchased.plan.gemsBought = 10; - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -455,10 +448,6 @@ describe('payments/index', () => { }); context('Block subscription perks', () => { - beforeEach(() => { - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - }); - it('adds block months to plan.consecutive.offset', async () => { await api.createSubscription(data); @@ -497,7 +486,6 @@ describe('payments/index', () => { data.sub.key = 'basic_12mo'; await api.createSubscription(data); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25); @@ -536,7 +524,6 @@ describe('payments/index', () => { now: mayMysteryItemTimeframe, toFake: ['Date'], }); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); }); afterEach(() => { diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 1387d4b5c8..80401f21de 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -11,10 +11,10 @@ import { // eslint-disable-line import/no-cycle model as Group, basicFields as basicGroupFields, } from '../../models/group'; +import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle import { NotAuthorized, NotFound, - TooManyRequests, } from '../errors'; import shared from '../../../common'; import { sendNotification as sendPushNotification } from '../pushNotifications'; // eslint-disable-line import/no-cycle @@ -80,9 +80,19 @@ async function createSubscription (data) { let emailType = 'subscription-begins'; let recipientIsSubscribed = recipient.isSubscribed(); - if (data.user && !data.gift && !data.groupId && data.customerId !== 'group-plan') { - if (moment().diff(data.user.purchased.plan.dateUpdated, 'minutes') < 3) { - throw new TooManyRequests('Subscription already processed, likely duplicate request'); + if (data.user && !data.gift && !data.groupId) { + const unlockedUser = await User.findOneAndUpdate( + { + _id: data.user._id, + $or: [ + { _subSignature: 'NOT_RUNNING' }, + { _subSignature: { $exists: false } }, + ], + }, + { $set: { _subSignature: 'SUB_IN_PROGRESS' } }, + ); + if (!unlockedUser) { + throw new NotFound('User not found or subscription already processing.'); } } @@ -289,10 +299,6 @@ async function createSubscription (data) { } } - if (group) await group.save(); - if (data.user && data.user.isModified()) await data.user.save(); - if (data.gift) await data.gift.member.save(); - slack.sendSubscriptionNotification({ buyer: { id: data.user._id, @@ -309,6 +315,24 @@ async function createSubscription (data) { groupId, autoRenews, }); + + if (group) { + await group.save(); + } + if (data.user) { + if (data.user.isModified()) { + await data.user.save(); + } + if (!data.gift && !data.groupId) { + await User.findOneAndUpdate( + { _id: data.user._id }, + { $set: { _subSignature: 'NOT_RUNNING' } }, + ); + } + } + if (data.gift) { + await data.gift.member.save(); + } } // Cancels a subscription or group plan, setting termination to happen later From 15353eba8a179c2a25f0c3fa4189f63aa94fdd95 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 15:12:14 -0600 Subject: [PATCH 06/30] fix(subs): roll all the way back, didn't work :( --- website/server/libs/payments/subscriptions.js | 39 ++----------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 80401f21de..2052dc4c9a 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -11,7 +11,6 @@ import { // eslint-disable-line import/no-cycle model as Group, basicFields as basicGroupFields, } from '../../models/group'; -import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle import { NotAuthorized, NotFound, @@ -80,22 +79,6 @@ async function createSubscription (data) { let emailType = 'subscription-begins'; let recipientIsSubscribed = recipient.isSubscribed(); - if (data.user && !data.gift && !data.groupId) { - const unlockedUser = await User.findOneAndUpdate( - { - _id: data.user._id, - $or: [ - { _subSignature: 'NOT_RUNNING' }, - { _subSignature: { $exists: false } }, - ], - }, - { $set: { _subSignature: 'SUB_IN_PROGRESS' } }, - ); - if (!unlockedUser) { - throw new NotFound('User not found or subscription already processing.'); - } - } - // If we are buying a group subscription if (data.groupId) { const groupFields = basicGroupFields.concat(' purchased'); @@ -299,6 +282,10 @@ async function createSubscription (data) { } } + if (group) await group.save(); + if (data.user && data.user.isModified()) await data.user.save(); + if (data.gift) await data.gift.member.save(); + slack.sendSubscriptionNotification({ buyer: { id: data.user._id, @@ -315,24 +302,6 @@ async function createSubscription (data) { groupId, autoRenews, }); - - if (group) { - await group.save(); - } - if (data.user) { - if (data.user.isModified()) { - await data.user.save(); - } - if (!data.gift && !data.groupId) { - await User.findOneAndUpdate( - { _id: data.user._id }, - { $set: { _subSignature: 'NOT_RUNNING' } }, - ); - } - } - if (data.gift) { - await data.gift.member.save(); - } } // Cancels a subscription or group plan, setting termination to happen later From 06a8d2bbd76fae8af38d5d81ea0cd3e593c81c00 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 15:12:32 -0600 Subject: [PATCH 07/30] 4.249.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f920e8ad51..ced5cdd9f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.249.3", + "version": "4.249.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dc545955ac..1076507d4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.249.3", + "version": "4.249.4", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.19.6", From 116068effa3700cf698739fe77358791f36e1d54 Mon Sep 17 00:00:00 2001 From: Natalie L <78037386+CuriousMagpie@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:21:03 -0500 Subject: [PATCH 08/30] fix(apiDescription): remove incorrect information (#14367) --- website/server/controllers/top-level/dataexport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/server/controllers/top-level/dataexport.js b/website/server/controllers/top-level/dataexport.js index aaae4f411d..942ec67274 100644 --- a/website/server/controllers/top-level/dataexport.js +++ b/website/server/controllers/top-level/dataexport.js @@ -276,7 +276,7 @@ api.exportUserAvatarPng = { /** * @api {get} /export/inbox.html Export user private messages as HTML document * @apiName ExportUserPrivateMessages - * @apiDescription This HTML export feature is not currently working (https://github.com/HabitRPG/habitica/issues/9489). + * * @apiGroup DataExport * * @apiSuccess {HTML} File An html page of the user's private messages. From 1d8e3d45a14f8a740a9bfbc943d7b6defb7dfc16 Mon Sep 17 00:00:00 2001 From: Sky Chrastina Date: Fri, 18 Nov 2022 15:29:43 -0700 Subject: [PATCH 09/30] new check asset + css in shop, task, and buy gems (#14340) --- website/client/src/assets/svg/check.svg | 4 ++-- website/client/src/components/payments/buyGemsModal.vue | 4 ++-- website/client/src/components/shops/shopItem.vue | 9 ++++----- website/client/src/components/tasks/task.vue | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/website/client/src/assets/svg/check.svg b/website/client/src/assets/svg/check.svg index 2ae3d23949..0d9eb368fc 100644 --- a/website/client/src/assets/svg/check.svg +++ b/website/client/src/assets/svg/check.svg @@ -1,3 +1,3 @@ - - + + \ No newline at end of file diff --git a/website/client/src/components/payments/buyGemsModal.vue b/website/client/src/components/payments/buyGemsModal.vue index 53647ebff8..3c4c0ff568 100644 --- a/website/client/src/components/payments/buyGemsModal.vue +++ b/website/client/src/components/payments/buyGemsModal.vue @@ -359,8 +359,8 @@ .svg-icon.check { color: $purple-400; - width: 0.77rem; - height: 0.615rem; + width: 16px; + height: 16px; } .text-leadin { diff --git a/website/client/src/components/shops/shopItem.vue b/website/client/src/components/shops/shopItem.vue index 2fdfd6cba4..f6aeaeb9fb 100644 --- a/website/client/src/components/shops/shopItem.vue +++ b/website/client/src/components/shops/shopItem.vue @@ -206,12 +206,11 @@ } span.svg-icon.inline.check { - height: 12px; - width: 10px; + height: 16px; + width: 16px; position: absolute; - left: 8px; - top: 8px; - margin-top: 0; + left: 4px; + top: 4px; color: $gray-200; } diff --git a/website/client/src/components/tasks/task.vue b/website/client/src/components/tasks/task.vue index fdc429eac2..7d424711be 100644 --- a/website/client/src/components/tasks/task.vue +++ b/website/client/src/components/tasks/task.vue @@ -773,9 +773,9 @@ } .check.svg-icon { - width: 12.3px; - height: 9.8px; - margin: 9px 8px; + width: 16px; + height: 16px; + margin: 5px; } .challenge.broken { From 4b4f07308917eda30ea128e8364f19d86ce642f0 Mon Sep 17 00:00:00 2001 From: Sky Chrastina Date: Fri, 18 Nov 2022 15:38:28 -0700 Subject: [PATCH 10/30] Fix az sort (#14347) * add stopword package * sort pet and potion quests by stopword-ized text * chore(package): revert package lock Will update after merge * fix(package): Friday brain Co-authored-by: SabreCat --- website/client/package.json | 1 + .../src/components/shops/quests/index.vue | 56 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/website/client/package.json b/website/client/package.json index ac50e3b9a2..58fd3cfa79 100644 --- a/website/client/package.json +++ b/website/client/package.json @@ -49,6 +49,7 @@ "sass": "^1.34.0", "sass-loader": "^8.0.2", "smartbanner.js": "^1.19.1", + "stopword": "^2.0.5", "svg-inline-loader": "^0.8.2", "svg-url-loader": "^7.1.1", "svgo": "^1.3.2", diff --git a/website/client/src/components/shops/quests/index.vue b/website/client/src/components/shops/quests/index.vue index e1a9134278..49cf3eb4ff 100644 --- a/website/client/src/components/shops/quests/index.vue +++ b/website/client/src/components/shops/quests/index.vue @@ -402,6 +402,8 @@ import _sortBy from 'lodash/sortBy'; import _throttle from 'lodash/throttle'; import _groupBy from 'lodash/groupBy'; import _map from 'lodash/map'; +import _each from 'lodash/each'; +import * as stopword from 'stopword/dist/stopword.esm.mjs'; import { mapState } from '@/libs/store'; import ShopItem from '../shopItem'; @@ -426,6 +428,51 @@ import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTrans import QuestPopover from './questPopover'; import { worldStateMixin } from '@/mixins/worldState'; +function splitMultipleDelims (text, delims) { + const omniDelim = 'θνι'; + let workingText = text; + for (const delim of delims) { + workingText = workingText.replace(new RegExp(delim, 'g'), omniDelim); + } + return workingText.split(omniDelim); +} + +function removeStopwordsFromText (text, language) { + // list of supported languages https://www.npmjs.com/package/stopword + const langs = { + bg: stopword.bul, + cs: stopword.ces, + da: stopword.dan, + de: stopword.deu, + en: stopword.eng, + en_GB: stopword.eng, + 'en@pirate': stopword.eng.concat(["th'"]), + es: stopword.spa, + es_419: stopword.spa, + fr: stopword.fra, + he: stopword.heb, + hu: stopword.hun, + id: stopword.ind, + it: stopword.ita, + ja: stopword.jpn, + nl: stopword.nld, + pl: stopword.pol, + pt: stopword.por, + pt_BR: stopword.porBr, + ro: stopword.ron, + ru: stopword.rus, + sk: stopword.slv, + // sr: stopword., + sv: stopword.swe, + tr: stopword.tur, + uk: stopword.ukr, + zh: stopword.zho, + zh_TW: stopword.zho, + }; + const splitText = splitMultipleDelims(text, [' ', "'"]); + return stopword.removeStopwords(splitText, langs[language] || stopword.eng).join(' ').toLowerCase(); +} + export default { components: { QuestPopover, @@ -539,7 +586,14 @@ export default { switch (sortBy) { // eslint-disable-line default-case case 'AZ': { - result = _sortBy(result, ['text']); + if (category.identifier === 'pet' || category.identifier === 'hatchingPotion') { + _each(result, item => { + item.sortText = removeStopwordsFromText(item.text, this.user.preferences.language); + }); + result = _sortBy(result, ['sortText']); + } else { + result = _sortBy(result, ['text']); + } break; } From 300c2bb0a81ede285077d4860521f6e0e26a8dc4 Mon Sep 17 00:00:00 2001 From: Adam Fitzgibbon Date: Fri, 18 Nov 2022 14:43:14 -0800 Subject: [PATCH 11/30] change currency to gold if the gear is owned (#14326) * change currency to gold if the gear is owned * fix linting error --- website/common/script/libs/shops.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/common/script/libs/shops.js b/website/common/script/libs/shops.js index 662f461750..63a7515afb 100644 --- a/website/common/script/libs/shops.js +++ b/website/common/script/libs/shops.js @@ -419,6 +419,11 @@ shops.getSeasonalGearBySet = function getSeasonalGearBySet ( const itemInfo = getItemInfo(null, currentSet ? 'marketGear' : 'gear', gear, officialPinnedItems, language); itemInfo.locked = currentSet && user.stats.class !== gear.specialClass; + // gear that has previously been owned should be repurchaseable with gold + if (user.items.gear.owned[gear.key] !== undefined) { + itemInfo.currency = 'gold'; + } + return itemInfo; }); }; From 4f70a6fbf4d6a488d7c8b259157fc2a04b17f86e Mon Sep 17 00:00:00 2001 From: Adam Fitzgibbon Date: Fri, 18 Nov 2022 14:44:58 -0800 Subject: [PATCH 12/30] now grouping the stable A-Z sortBy option by first letter so that Show More functionality works like the other sort types (#14304) --- .../src/components/inventory/stable/index.vue | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/website/client/src/components/inventory/stable/index.vue b/website/client/src/components/inventory/stable/index.vue index 9e1cedc34c..18f4ef1a6e 100644 --- a/website/client/src/components/inventory/stable/index.vue +++ b/website/client/src/components/inventory/stable/index.vue @@ -787,18 +787,15 @@ export default { if (sortBy === 'sortByColor') { groupKey = 'potionKey'; } else if (sortBy === 'AZ') { - groupKey = ''; + groupKey = i => i.eggName[0]; } else if (sortBy === 'sortByHatchable') { groupKey = i => (i.isHatchable() ? 0 : 1); } const groupedPets = groupBy(pets, groupKey); // Pets are rendered as grouped "rows". Count helps decide if show more button is necessary. - if (sortBy === 'AZ') { - this.petRowCount[animalGroup.key] = 1; - } else { - this.petRowCount[animalGroup.key] = Object.keys(groupedPets).length; - } + this.petRowCount[animalGroup.key] = Object.keys(groupedPets).length; + return groupedPets; }, mounts (animalGroup, hideMissing, sortBy, searchText) { @@ -814,14 +811,12 @@ export default { if (sortBy === 'sortByColor') { groupKey = 'potionKey'; } else if (sortBy === 'AZ') { - groupKey = ''; + groupKey = i => i.eggName[0]; } const groupedMounts = groupBy(mounts, groupKey); - if (sortBy === 'AZ') { - this.mountRowCount[animalGroup.key] = 1; - } else { - this.mountRowCount[animalGroup.key] = Object.keys(groupedMounts).length; - } + + this.mountRowCount[animalGroup.key] = Object.keys(groupedMounts).length; + return groupedMounts; }, // Actions From 6b27e186996099741e6af4ea19fa8730f8dec5e5 Mon Sep 17 00:00:00 2001 From: Adam Fitzgibbon Date: Fri, 18 Nov 2022 14:48:34 -0800 Subject: [PATCH 13/30] add prop to task-wrapper so that the cursor remains consistant (#14302) --- website/client/src/components/tasks/task.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/client/src/components/tasks/task.vue b/website/client/src/components/tasks/task.vue index 7d424711be..520c51568c 100644 --- a/website/client/src/components/tasks/task.vue +++ b/website/client/src/components/tasks/task.vue @@ -1,5 +1,5 @@
+
Date: Fri, 18 Nov 2022 17:52:09 -0500 Subject: [PATCH 15/30] fix(content): quality of life change for staff and moderators (#14245) * fix(content): quality of life change for staff and moderators * fix(content): quality of life change for staff and moderators, I really mean it this time Co-authored-by: Sabe Jones --- website/client/src/components/static/faq.vue | 40 +++++++++++--------- website/common/locales/en/faq.json | 8 ++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/website/client/src/components/static/faq.vue b/website/client/src/components/static/faq.vue index b9bb3a9d6e..783270f2bc 100644 --- a/website/client/src/components/static/faq.vue +++ b/website/client/src/components/static/faq.vue @@ -13,25 +13,29 @@ :key="index" class="faq-question" > -

- {{ $t(`faqQuestion${index}`) }} -

- -
-
+

+ {{ $t(`faqQuestion${index}`) }} +

+ +
+
+

diff --git a/website/common/locales/en/faq.json b/website/common/locales/en/faq.json index 08ce04e1a0..a91851b6c3 100644 --- a/website/common/locales/en/faq.json +++ b/website/common/locales/en/faq.json @@ -66,10 +66,10 @@ "androidFaqAnswer12": "World Bosses are special monsters that appear in the Tavern. All active users are automatically battling the Boss, and their tasks and Skills will damage the Boss as usual.\n\n You can also be in a normal Quest at the same time. Your tasks and Skills will count towards both the World Boss and the Boss/Collection Quest in your party.\n\n A World Boss will never hurt you or your account in any way. Instead, it has a Rage Bar that fills when users skip Dailies. If its Rage bar fills, it will attack one of the Non-Player Characters around the site and their image will change.\n\n You can read more about [past World Bosses](https://habitica.fandom.com/wiki/World_Bosses) on the wiki.", "webFaqAnswer12": "World Bosses are special monsters that appear in the Tavern. All active users are automatically battling the Boss, and their tasks and Skills will damage the Boss as usual. You can also be in a normal Quest at the same time. Your tasks and Skills will count towards both the World Boss and the Boss/Collection Quest in your party. A World Boss will never hurt you or your account in any way. Instead, it has a Rage Bar that fills when users skip Dailies. If its Rage bar fills, it will attack one of the Non-Player Characters around the site and their image will change. You can read more about [past World Bosses](https://habitica.fandom.com/wiki/World_Bosses) on the wiki.", + "faqQuestion13": "What is a Group Plan?", + "webFaqAnswer13": "## How do Group Plans work?\n\nA [Group Plan](/group-plans) gives your Party or Guild access to a shared task board that’s similar to your personal task board! It’s a shared Habitica experience where tasks can be created and checked off by anyone in the group.\n\nThere are also features available like member roles, status view, and task assigning that give you a more controlled experience. [Visit our wiki](https://habitica.fandom.com/wiki/Group_Plans) to learn more about our Group Plans’ features!\n\n## Who benefits from a Group Plan?\n\nGroup Plans work best when you have a small team of people who want to collaborate together. We recommend 2-5 members.\n\nGroup Plans are great for families, whether it’s a parent and child or you and a partner. Shared goals, chores, or responsibilities are easy to keep track of on one board.\n\nGroup Plans can also be useful for teams of colleagues that have shared goals, or managers that want to introduce their employees to gamification.\n\n## Quick tips for using Groups\n\nHere are some quick tips to get you started with your new Group. We’ll provide more details in the following sections:\n\n* Make a member a manager to give them the ability to create and edit tasks\n* Leave tasks unassigned if anyone can complete it and it only needs done once\n* Assign a task to one person to make sure no one else can complete their task\n* Assign a task to multiple people if they all need to complete it\n* Toggle the ability to display shared tasks on your personal board to not miss anything\n* You get rewarded for the tasks you complete, even multi-assigned\n* Task completion rewards aren’t shared or split between Team members\n* Use task color on the team board to judge the average completion rate of tasks\n* Regularly review the tasks on your Team Board to make sure they are still relevant\n* Missing a Daily won’t damage you or your team, but the task will degrade in color\n\n## How can others in the group create tasks?\n\nOnly the group leader and managers can create tasks. If you’d like a group member to be able to create tasks, then you should promote them to be a manager by going to the Group Information tab, viewing the member list, and clicking the dot icon by their name.\n\n## How does assigning a task work?\n\nGroup Plans give you the unique ability to assign tasks to other group members. Assigning a task is great for delegating. If you assign a task to someone, then other members are prevented from completing it.\n\nYou can also assign a task to multiple people if it needs to be completed by more than one member. For example, if everyone has to brush their teeth, create a task and assign it to each group member. They will all be able to check it off and get their individual rewards for doing so. The main task will show as complete once everyone checks it off.\n\n## How do unassigned tasks work?\n\nUnassigned tasks can be completed by anyone in the group, so leave a task unassigned to allow any member to complete it. For example, taking out the trash. Whoever takes out the trash can check off the unassigned task and it will show as completed for everyone.\n\n## How does the synchronized day reset work?\n\nShared tasks will reset at the same time for everyone to keep the shared task board in sync. This time is visible on the shared task board and is determined by the group leader’s day start time. Because shared tasks reset automatically, you will not get a chance to complete yesterday’s uncompleted shared Dailies when you check in the next morning.\n\nShared Dailies will not do damage if they are missed, however they will degrade in color to help visualize progress. We don’t want the shared experience to be a negative one!\n\n## How do I use my Group on the mobile apps?\n\nWhile the mobile apps don’t fully support all Group Plans functionality yet, you can still complete shared tasks from the iOS and Android app by copying the tasks onto your personal task board. You can switch this preference on from Settings in the mobile apps or from the group task board on the browser version. Now open and assigned shared tasks will display on your personal task board across all platforms.\n\n## What’s the difference between a Group’s shared tasks and Challenges?\n\nGroup Plan shared task boards are more dynamic than Challenges, in that they can constantly be updated and interacted with. Challenges are great if you have one set of tasks to send out to many people.\n\nGroup Plans are also a paid feature, while Challenges are available free to everyone.\n\nYou cannot assign specific tasks in Challenges, and Challenges do not have a shared day reset. In general, Challenges offer less control and direct interaction.", + "iosFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), come ask in the Tavern chat under Menu > Tavern! We're happy to help.", "androidFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), come ask in the Tavern chat under Menu > Tavern! We're happy to help.", - "webFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), come ask in the [Habitica Help guild](https://habitica.com/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)! We're happy to help.", - - "faqQuestion13": "What is a Group Plan?", - "webFaqAnswer13": "## How do Group Plans work?\n\nA [Group Plan](/group-plans) gives your Party or Guild access to a shared task board that’s similar to your personal task board! It’s a shared Habitica experience where tasks can be created and checked off by anyone in the group.\n\nThere are also features available like member roles, status view, and task assigning that give you a more controlled experience. [Visit our wiki](https://habitica.fandom.com/wiki/Group_Plans) to learn more about our Group Plans’ features!\n\n## Who benefits from a Group Plan?\n\nGroup Plans work best when you have a small team of people who want to collaborate together. We recommend 2-5 members.\n\nGroup Plans are great for families, whether it’s a parent and child or you and a partner. Shared goals, chores, or responsibilities are easy to keep track of on one board.\n\nGroup Plans can also be useful for teams of colleagues that have shared goals, or managers that want to introduce their employees to gamification.\n\n## Quick tips for using Groups\n\nHere are some quick tips to get you started with your new Group. We’ll provide more details in the following sections:\n\n* Make a member a manager to give them the ability to create and edit tasks\n* Leave tasks unassigned if anyone can complete it and it only needs done once\n* Assign a task to one person to make sure no one else can complete their task\n* Assign a task to multiple people if they all need to complete it\n* Toggle the ability to display shared tasks on your personal board to not miss anything\n* You get rewarded for the tasks you complete, even multi-assigned\n* Task completion rewards aren’t shared or split between Team members\n* Use task color on the team board to judge the average completion rate of tasks\n* Regularly review the tasks on your Team Board to make sure they are still relevant\n* Missing a Daily won’t damage you or your team, but the task will degrade in color\n\n## How can others in the group create tasks?\n\nOnly the group leader and managers can create tasks. If you’d like a group member to be able to create tasks, then you should promote them to be a manager by going to the Group Information tab, viewing the member list, and clicking the dot icon by their name.\n\n## How does assigning a task work?\n\nGroup Plans give you the unique ability to assign tasks to other group members. Assigning a task is great for delegating. If you assign a task to someone, then other members are prevented from completing it.\n\nYou can also assign a task to multiple people if it needs to be completed by more than one member. For example, if everyone has to brush their teeth, create a task and assign it to each group member. They will all be able to check it off and get their individual rewards for doing so. The main task will show as complete once everyone checks it off.\n\n## How do unassigned tasks work?\n\nUnassigned tasks can be completed by anyone in the group, so leave a task unassigned to allow any member to complete it. For example, taking out the trash. Whoever takes out the trash can check off the unassigned task and it will show as completed for everyone.\n\n## How does the synchronized day reset work?\n\nShared tasks will reset at the same time for everyone to keep the shared task board in sync. This time is visible on the shared task board and is determined by the group leader’s day start time. Because shared tasks reset automatically, you will not get a chance to complete yesterday’s uncompleted shared Dailies when you check in the next morning.\n\nShared Dailies will not do damage if they are missed, however they will degrade in color to help visualize progress. We don’t want the shared experience to be a negative one!\n\n## How do I use my Group on the mobile apps?\n\nWhile the mobile apps don’t fully support all Group Plans functionality yet, you can still complete shared tasks from the iOS and Android app by copying the tasks onto your personal task board. You can switch this preference on from Settings in the mobile apps or from the group task board on the browser version. Now open and assigned shared tasks will display on your personal task board across all platforms.\n\n## What’s the difference between a Group’s shared tasks and Challenges?\n\nGroup Plan shared task boards are more dynamic than Challenges, in that they can constantly be updated and interacted with. Challenges are great if you have one set of tasks to send out to many people.\n\nGroup Plans are also a paid feature, while Challenges are available free to everyone.\n\nYou cannot assign specific tasks in Challenges, and Challenges do not have a shared day reset. In general, Challenges offer less control and direct interaction." + "webFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), come ask in the [Habitica Help guild](https://habitica.com/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)! We're happy to help." } From 3f690c24dac8cf6ba965eff4622f156486ac61fa Mon Sep 17 00:00:00 2001 From: prexio Date: Fri, 18 Nov 2022 14:54:12 -0800 Subject: [PATCH 16/30] Change Wikia to Fandom (#14291) --- website/common/locales/en/front.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/common/locales/en/front.json b/website/common/locales/en/front.json index 65b89d50b2..2f9b23eb38 100644 --- a/website/common/locales/en/front.json +++ b/website/common/locales/en/front.json @@ -55,7 +55,7 @@ "mobileAndroid": "Android App", "mobileIOS": "iOS App", "oldNews": "News", - "newsArchive": "News archive on Wikia (multilingual)", + "newsArchive": "News archive on Fandom (multilingual)", "setNewPass": "Set New Password", "password": "Password", "playButton": "Play", From f1fa6a8456c52eb5ad05811fec29af0f73eca5aa Mon Sep 17 00:00:00 2001 From: SabreCat Date: Mon, 21 Nov 2022 16:39:43 -0600 Subject: [PATCH 17/30] Revert "Allow sub upgrades/downgrades on iOS (#14303)" This reverts commit 9e98e56e9be1f7462bfedc1226f209cd97f93cd2. --- test/api/unit/libs/payments/apple.test.js | 105 +-------- test/api/unit/libs/payments/payments.test.js | 213 +----------------- website/server/libs/payments/apple.js | 36 +-- website/server/libs/payments/subscriptions.js | 10 +- 4 files changed, 17 insertions(+), 347 deletions(-) diff --git a/test/api/unit/libs/payments/apple.test.js b/test/api/unit/libs/payments/apple.test.js index 32f662d22d..1aefe2cb51 100644 --- a/test/api/unit/libs/payments/apple.test.js +++ b/test/api/unit/libs/payments/apple.test.js @@ -218,7 +218,6 @@ describe('Apple Payments', () => { headers = {}; receipt = `{"token": "${token}"}`; nextPaymentProcessing = moment.utc().add({ days: 2 }); - user = new User(); iapSetupStub = sinon.stub(iap, 'setup') .resolves(); @@ -299,7 +298,6 @@ describe('Apple Payments', () => { expirationDate: moment.utc().add({ day: 1 }).toDate(), productId: option.sku, transactionId: token, - originalTransactionId: token, }]); sub = common.content.subscriptionBlocks[option.subKey]; @@ -323,111 +321,12 @@ describe('Apple Payments', () => { nextPaymentProcessing, }); }); - if (option !== subOptions[3]) { - const newOption = subOptions[3]; - it(`upgrades a subscription from ${option.sku} to ${newOption.sku}`, async () => { - const oldSub = common.content.subscriptionBlocks[option.subKey]; - user.profile.name = 'sender'; - user.purchased.plan.paymentMethod = applePayments.constants.PAYMENT_METHOD_APPLE; - user.purchased.plan.customerId = token; - user.purchased.plan.planId = option.subKey; - user.purchased.plan.additionalData = receipt; - iap.getPurchaseData.restore(); - iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData') - .returns([{ - expirationDate: moment.utc().add({ day: 2 }).toDate(), - productId: newOption.sku, - transactionId: `${token}new`, - originalTransactionId: token, - }]); - sub = common.content.subscriptionBlocks[newOption.subKey]; - - await applePayments.subscribe(newOption.sku, - user, - receipt, - headers, - nextPaymentProcessing); - - expect(iapSetupStub).to.be.calledOnce; - expect(iapValidateStub).to.be.calledOnce; - expect(iapValidateStub).to.be.calledWith(iap.APPLE, receipt); - expect(iapIsValidatedStub).to.be.calledOnce; - expect(iapIsValidatedStub).to.be.calledWith({}); - expect(iapGetPurchaseDataStub).to.be.calledOnce; - - expect(paymentsCreateSubscritionStub).to.be.calledOnce; - expect(paymentsCreateSubscritionStub).to.be.calledWith({ - user, - customerId: token, - paymentMethod: applePayments.constants.PAYMENT_METHOD_APPLE, - sub, - headers, - additionalData: receipt, - nextPaymentProcessing, - updatedFrom: oldSub, - }); - }); - } - if (option !== subOptions[0]) { - const newOption = subOptions[0]; - it(`downgrades a subscription from ${option.sku} to ${newOption.sku}`, async () => { - const oldSub = common.content.subscriptionBlocks[option.subKey]; - user.profile.name = 'sender'; - user.purchased.plan.paymentMethod = applePayments.constants.PAYMENT_METHOD_APPLE; - user.purchased.plan.customerId = token; - user.purchased.plan.planId = option.subKey; - user.purchased.plan.additionalData = receipt; - iap.getPurchaseData.restore(); - iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData') - .returns([{ - expirationDate: moment.utc().add({ day: 2 }).toDate(), - productId: newOption.sku, - transactionId: `${token}new`, - originalTransactionId: token, - }]); - sub = common.content.subscriptionBlocks[newOption.subKey]; - - await applePayments.subscribe(newOption.sku, - user, - receipt, - headers, - nextPaymentProcessing); - - expect(iapSetupStub).to.be.calledOnce; - expect(iapValidateStub).to.be.calledOnce; - expect(iapValidateStub).to.be.calledWith(iap.APPLE, receipt); - expect(iapIsValidatedStub).to.be.calledOnce; - expect(iapIsValidatedStub).to.be.calledWith({}); - expect(iapGetPurchaseDataStub).to.be.calledOnce; - - expect(paymentsCreateSubscritionStub).to.be.calledOnce; - expect(paymentsCreateSubscritionStub).to.be.calledWith({ - user, - customerId: token, - paymentMethod: applePayments.constants.PAYMENT_METHOD_APPLE, - sub, - headers, - additionalData: receipt, - nextPaymentProcessing, - updatedFrom: oldSub, - }); - }); - } }); - it('errors when a user is using the same subscription', async () => { + it('errors when a user is already subscribed', async () => { + payments.createSubscription.restore(); user = new User(); await user.save(); - payments.createSubscription.restore(); - - iap.getPurchaseData.restore(); - iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData') - .returns([{ - expirationDate: moment.utc().add({ day: 1 }).toDate(), - productId: sku, - transactionId: token, - originalTransactionId: token, - }]); await applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing); diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 84475e4b0e..65b42b42f3 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -465,89 +465,6 @@ describe('payments/index', () => { }, }); }); - - context('Upgrades subscription', () => { - it('from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - const created = user.purchased.plan.dateCreated; - const updated = user.purchased.plan.dateUpdated; - - data.sub.key = 'basic_6mo'; - data.updatedFrom = { key: 'basic_earned' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.dateCreated).to.eql(created); - expect(user.purchased.plan.dateUpdated).to.not.eql(updated); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - }); - - it('from basic_3mo to basic_12mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - const created = user.purchased.plan.dateCreated; - const updated = user.purchased.plan.dateUpdated; - - data.sub.key = 'basic_12mo'; - data.updatedFrom = { key: 'basic_3mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.dateCreated).to.eql(created); - expect(user.purchased.plan.dateUpdated).to.not.eql(updated); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - }); - }); - - context('Downgrades subscription', () => { - it('from basic_6mo to basic_earned', async () => { - data.sub.key = 'basic_6mo'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - const created = user.purchased.plan.dateCreated; - const updated = user.purchased.plan.dateUpdated; - - data.sub.key = 'basic_earned'; - data.updatedFrom = { key: 'basic_6mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.dateCreated).to.eql(created); - expect(user.purchased.plan.dateUpdated).to.not.eql(updated); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - }); - - it('from basic_12mo to basic_3mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - data.sub.key = 'basic_12mo'; - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - const created = user.purchased.plan.dateCreated; - const updated = user.purchased.plan.dateUpdated; - - data.sub.key = 'basic_3mo'; - data.updatedFrom = { key: 'basic_12mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.dateCreated).to.eql(created); - expect(user.purchased.plan.dateUpdated).to.not.eql(updated); - expect(user.purchased.plan.customerId).to.eql('customer-id'); - }); - }); }); context('Block subscription perks', () => { @@ -571,6 +488,7 @@ describe('payments/index', () => { it('adds 10 to plan.consecutive.gemCapExtra for 6 month block', async () => { data.sub.key = 'basic_6mo'; + await api.createSubscription(data); expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); @@ -578,6 +496,7 @@ describe('payments/index', () => { it('adds 20 to plan.consecutive.gemCapExtra for 12 month block', async () => { data.sub.key = 'basic_12mo'; + await api.createSubscription(data); expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); @@ -613,134 +532,6 @@ describe('payments/index', () => { expect(user.purchased.plan.consecutive.trinkets).to.eql(4); }); - - context('Upgrades subscription', () => { - it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom = { key: 'basic_earned' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - - it('Adds 15 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5); - - data.sub.key = 'basic_12mo'; - data.updatedFrom = { key: 'basic_3mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - }); - - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom = { key: 'basic_earned' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); - }); - - it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(1); - - data.sub.key = 'basic_12mo'; - data.updatedFrom = { key: 'basic_3mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); - }); - }); - - context('Downgrades subscription', () => { - it('does not remove from plan.consecutive.gemCapExtra from basic_6mo to basic_earned', async () => { - data.sub.key = 'basic_6mo'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - - data.sub.key = 'basic_earned'; - data.updatedFrom = { key: 'basic_6mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - - it('does not remove from plan.consecutive.gemCapExtra from basic_12mo to basic_3mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - data.sub.key = 'basic_12mo'; - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - - data.sub.key = 'basic_3mo'; - data.updatedFrom = { key: 'basic_12mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - }); - - it('does not remove from plan.consecutive.trinkets from basic_6mo to basic_earned', async () => { - data.sub.key = 'basic_6mo'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); - - data.sub.key = 'basic_earned'; - data.updatedFrom = { key: 'basic_6mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); - }); - - it('does not remove from plan.consecutive.trinkets from basic_12mo to basic_3mo', async () => { - expect(user.purchased.plan.planId).to.not.exist; - - data.sub.key = 'basic_12mo'; - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); - - data.sub.key = 'basic_3mo'; - data.updatedFrom = { key: 'basic_12mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); - }); - }); }); context('Mystery Items', () => { diff --git a/website/server/libs/payments/apple.js b/website/server/libs/payments/apple.js index e91729a7e0..8c0fd44184 100644 --- a/website/server/libs/payments/apple.js +++ b/website/server/libs/payments/apple.js @@ -106,6 +106,10 @@ api.verifyGemPurchase = async function verifyGemPurchase (options) { }; api.subscribe = async function subscribe (sku, user, receipt, headers, nextPaymentProcessing) { + if (user && user.isSubscribed()) { + throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); + } + if (!sku) throw new BadRequest(shared.i18n.t('missingSubscriptionCode')); let subCode; @@ -136,49 +140,33 @@ api.subscribe = async function subscribe (sku, user, receipt, headers, nextPayme throw new NotAuthorized(api.constants.RESPONSE_NO_ITEM_PURCHASED); } - let originalTransactionId; - let newTransactionId; + let transactionId; for (const purchaseData of purchaseDataList) { const dateTerminated = new Date(Number(purchaseData.expirationDate)); if (purchaseData.productId === sku && dateTerminated > new Date()) { - originalTransactionId = purchaseData.originalTransactionId; - newTransactionId = purchaseData.transactionId; + transactionId = purchaseData.transactionId; break; } } - if (originalTransactionId) { - let existingSub; - if (user && user.isSubscribed()) { - if (user.purchased.plan.customerId !== originalTransactionId) { - throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); - } - existingSub = shared.content.subscriptionBlocks[user.purchased.plan.planId]; - } + if (transactionId) { const existingUser = await User.findOne({ - 'purchased.plan.customerId': originalTransactionId, + 'purchased.plan.customerId': transactionId, }).exec(); - if (existingUser - && (originalTransactionId === newTransactionId || existingUser._id !== user._id)) { - throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); - } + if (existingUser) throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); nextPaymentProcessing = nextPaymentProcessing || moment.utc().add({ days: 2 }); // eslint-disable-line max-len, no-param-reassign - const data = { + await payments.createSubscription({ user, - customerId: originalTransactionId, + customerId: transactionId, paymentMethod: this.constants.PAYMENT_METHOD_APPLE, sub, headers, nextPaymentProcessing, additionalData: receipt, - }; - if (existingSub) { - data.updatedFrom = existingSub; - } - await payments.createSubscription(data); + }); } else { throw new NotAuthorized(api.constants.RESPONSE_INVALID_RECEIPT); } diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 75a49312e2..b5558e82dc 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -74,15 +74,7 @@ async function prepareSubscriptionValues (data) { ? data.gift.subscription.key : data.sub.key]; const autoRenews = data.autoRenews !== undefined ? data.autoRenews : true; - const updatedFrom = data.updatedFrom - ? shared.content.subscriptionBlocks[data.updatedFrom.key] - : undefined; - let months; - if (updatedFrom && Number(updatedFrom.months) !== 1) { - months = Math.max(0, Number(block.months) - Number(updatedFrom.months)); - } else { - months = Number(block.months); - } + const months = Number(block.months); const today = new Date(); let group; let groupId; From 497073a714cb5339dbd3578ac9bbf6537c6a8f71 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Mon, 21 Nov 2022 16:42:36 -0600 Subject: [PATCH 18/30] 4.249.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc0cf3c6e1..4766fa4623 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.249.4", + "version": "4.249.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 01397b7025..3c48b40c45 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.249.4", + "version": "4.249.5", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.19.6", From a8e9c9bc70f42aa1d10444577d336dc8aa4e295a Mon Sep 17 00:00:00 2001 From: SabreCat Date: Mon, 21 Nov 2022 18:54:57 -0600 Subject: [PATCH 19/30] chore(event): set up Harvest Feast 2022 --- .../common/script/content/constants/events.js | 12 ++++++++---- website/server/models/user/hooks.js | 19 ++++--------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/website/common/script/content/constants/events.js b/website/common/script/content/constants/events.js index 54fb486e8d..d3066193a4 100644 --- a/website/common/script/content/constants/events.js +++ b/website/common/script/content/constants/events.js @@ -10,20 +10,24 @@ const gemsPromo = { export const EVENTS = { noEvent: { - start: '2022-11-30T20:00-05:00', + start: '2022-11-27T20:00-05:00', end: '2022-12-20T08:00-05:00', season: 'normal', npcImageSuffix: '', }, + harvestFeast2022: { + start: '2022-11-22T08:00-05:00', + end: '2022-11-27T20:00-05:00', + season: 'thanksgiving', + npcImageSuffix: '_thanksgiving', + }, bundle202211: { start: '2022-11-15T08:00-05:00', end: '2022-11-30T20:00-05:00', - season: 'normal', - npcImageSuffix: '', }, afterGala: { start: '2022-10-31T20:00-04:00', - end: '2022-11-15T08:00-05:00', + end: '2022-11-22T08:00-05:00', season: 'normal', npcImageSuffix: '', }, diff --git a/website/server/models/user/hooks.js b/website/server/models/user/hooks.js index 58340c73cd..6bafec1bd1 100644 --- a/website/server/models/user/hooks.js +++ b/website/server/models/user/hooks.js @@ -150,21 +150,10 @@ function _setUpNewUser (user) { user.items.quests.dustbunnies = 1; user.purchased.background.violet = true; user.preferences.background = 'violet'; - if (moment().isBefore('2022-03-15T20:00-04:00')) { - user.items.gear.owned.head_special_piDay = true; - user.items.gear.equipped.head = 'head_special_piDay'; - user.items.gear.owned.shield_special_piDay = true; - user.items.gear.equipped.shield = 'shield_special_piDay'; - user.items.food.Pie_Skeleton = 1; - user.items.food.Pie_Base = 1; - user.items.food.Pie_CottonCandyBlue = 1; - user.items.food.Pie_CottonCandyPink = 1; - user.items.food.Pie_Shade = 1; - user.items.food.Pie_White = 1; - user.items.food.Pie_Golden = 1; - user.items.food.Pie_Zombie = 1; - user.items.food.Pie_Desert = 1; - user.items.food.Pie_Red = 1; + if (moment().isBetween('2022-11-22T08:00-05:00', '2022-11-27T20:00-05:00')) { + user.migration = '20221122_harvest_feast'; + user.items.pets['Turkey-Base'] = 5; + user.items.currentPet = 'Turkey-Base'; } user.markModified('items achievements'); From bdd926e11047569dc45aaade4e59f2b594dc548b Mon Sep 17 00:00:00 2001 From: SabreCat Date: Mon, 21 Nov 2022 18:55:03 -0600 Subject: [PATCH 20/30] 4.249.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4766fa4623..e06be5522c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.249.5", + "version": "4.249.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3c48b40c45..625f1c91a9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.249.5", + "version": "4.249.6", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.19.6", From 04e2a39a9fd6d464b5f4ebf0a373df17782b6ed0 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Mon, 21 Nov 2022 20:08:15 -0600 Subject: [PATCH 21/30] fix(test): rearrange for legacy event logic --- website/common/script/content/constants/events.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/common/script/content/constants/events.js b/website/common/script/content/constants/events.js index d3066193a4..f561d44bd5 100644 --- a/website/common/script/content/constants/events.js +++ b/website/common/script/content/constants/events.js @@ -21,16 +21,16 @@ export const EVENTS = { season: 'thanksgiving', npcImageSuffix: '_thanksgiving', }, - bundle202211: { - start: '2022-11-15T08:00-05:00', - end: '2022-11-30T20:00-05:00', - }, afterGala: { start: '2022-10-31T20:00-04:00', end: '2022-11-22T08:00-05:00', season: 'normal', npcImageSuffix: '', }, + bundle202211: { + start: '2022-11-15T08:00-05:00', + end: '2022-11-30T20:00-05:00', + }, fall2022: { start: '2022-09-20T08:00-04:00', end: '2022-10-31T20:00-04:00', From 91cbf7a2a97a95d2d4bb94889dcaa60a3f07e09d Mon Sep 17 00:00:00 2001 From: SabreCat Date: Wed, 23 Nov 2022 13:08:23 -0600 Subject: [PATCH 22/30] fix(shops): show correct countdown outside of Gala --- .../client/src/components/shops/buyModal.vue | 5 +- .../components/shops/market/categoryRow.vue | 51 ------------------- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/website/client/src/components/shops/buyModal.vue b/website/client/src/components/shops/buyModal.vue index 013c291d55..66c90b182a 100644 --- a/website/client/src/components/shops/buyModal.vue +++ b/website/client/src/components/shops/buyModal.vue @@ -385,7 +385,6 @@ import EquipmentAttributesGrid from '../inventory/equipment/attributesGrid.vue'; import Item from '@/components/inventory/item'; import Avatar from '@/components/avatar'; -import seasonalShopConfig from '@/../../common/script/libs/shops-seasonal.config'; import { drops as dropEggs } from '@/../../common/script/content/eggs'; import { drops as dropPotions } from '@/../../common/script/content/hatching-potions'; @@ -438,7 +437,6 @@ export default { selectedAmountToBuy: 1, isPinned: false, - endDate: seasonalShopConfig.dateRange.end, }; }, computed: { @@ -489,6 +487,9 @@ export default { nonSubscriberHourglasses () { return (!this.user.purchased.plan.customerId && !this.user.purchased.plan.consecutive.trinkets && this.getPriceClass() === 'hourglasses'); }, + endDate () { + return moment(this.item.event.end); + }, }, watch: { item: function itemChanged () { diff --git a/website/client/src/components/shops/market/categoryRow.vue b/website/client/src/components/shops/market/categoryRow.vue index eada1073a0..77610d2ae2 100644 --- a/website/client/src/components/shops/market/categoryRow.vue +++ b/website/client/src/components/shops/market/categoryRow.vue @@ -8,16 +8,6 @@ :popover-position="'top'" @click="itemSelected(item)" > - - {{ $t('maxBuyGems') }} -

{{ item.text }}

-
- {{ limitedString }} -
-