From c979e568f1ab4a01e74a2e93d7c3356d98215e1e Mon Sep 17 00:00:00 2001 From: Fiz <34069775+Hafizzle@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:44:15 -0500 Subject: [PATCH 01/24] Respect user language preference in content endpoint (#15485) * Respect user language preference in content endpoint Content API now returns data in user's preferred language when authenticated without language parameter. No breaking changes - existing clients unaffected. * lint fix --- .../integration/content/GET-content.test.js | 25 +++++++++++++++++++ website/server/controllers/api-v3/content.js | 10 ++++++++ 2 files changed, 35 insertions(+) diff --git a/test/api/v3/integration/content/GET-content.test.js b/test/api/v3/integration/content/GET-content.test.js index 0dbd2779e4..439667be9f 100644 --- a/test/api/v3/integration/content/GET-content.test.js +++ b/test/api/v3/integration/content/GET-content.test.js @@ -1,6 +1,7 @@ import { requester, translate as t, + generateUser, } from '../../../../helpers/api-integration/v3'; import i18n from '../../../../../website/common/script/i18n'; @@ -56,4 +57,28 @@ describe('GET /content', () => { const res = await requester().get('/content?filter=backgroundsFlat,invalid'); expect(res).to.not.have.property('backgroundsFlat'); }); + + describe('authenticated user', () => { + let user; + it('returns content in user\'s preferred language when no language parameter is provided', async () => { + user = await generateUser({ 'preferences.language': 'de' }); + const res = await user.get('/content'); + expect(res).to.have.nested.property('backgrounds.backgrounds062014.beach'); + expect(res.backgrounds.backgrounds062014.beach.text).to.equal(i18n.t('backgroundBeachText', 'de')); + }); + + it('respects language parameter over user\'s preferred language', async () => { + user = await generateUser({ 'preferences.language': 'de' }); + const res = await user.get('/content?language=fr'); + expect(res).to.have.nested.property('backgrounds.backgrounds062014.beach'); + expect(res.backgrounds.backgrounds062014.beach.text).to.equal(i18n.t('backgroundBeachText', 'fr')); + }); + + it('falls back to English if user\'s preferred language is invalid', async () => { + user = await generateUser({ 'preferences.language': 'invalid_lang' }); + const res = await user.get('/content'); + expect(res).to.have.nested.property('backgrounds.backgrounds062014.beach'); + expect(res.backgrounds.backgrounds062014.beach.text).to.equal(t('backgroundBeachText')); + }); + }); }); diff --git a/website/server/controllers/api-v3/content.js b/website/server/controllers/api-v3/content.js index ed8a79d782..e48b79fb1c 100644 --- a/website/server/controllers/api-v3/content.js +++ b/website/server/controllers/api-v3/content.js @@ -1,6 +1,7 @@ import nconf from 'nconf'; import { langCodes } from '../../libs/i18n'; import { serveContent } from '../../libs/content'; +import { authWithHeaders } from '../../middlewares/auth'; const IS_PROD = nconf.get('IS_PROD'); @@ -66,12 +67,21 @@ api.getContent = { method: 'GET', url: '/content', noLanguage: true, + middlewares: [authWithHeaders({ optional: true })], async handler (req, res) { let language = 'en'; const proposedLang = req.query.language; if (proposedLang && langCodes.includes(proposedLang)) { language = proposedLang; + } else if (res.locals.user + && res.locals.user.preferences + && res.locals.user.preferences.language + ) { + const userLang = res.locals.user.preferences.language; + if (langCodes.includes(userLang)) { + language = userLang; + } } let filter = req.query.filter || ''; From 5ba939ee9c811b58dc85126fa1142e59b394a556 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:44:41 -0500 Subject: [PATCH 02/24] chore(deps): bump form-data from 4.0.0 to 4.0.4 in /website/client (#15478) Bumps [form-data](https://github.com/form-data/form-data) from 4.0.0 to 4.0.4. - [Release notes](https://github.com/form-data/form-data/releases) - [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md) - [Commits](https://github.com/form-data/form-data/compare/v4.0.0...v4.0.4) --- updated-dependencies: - dependency-name: form-data dependency-version: 4.0.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/client/package-lock.json | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/website/client/package-lock.json b/website/client/package-lock.json index c595d61381..bad50688a5 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -4024,13 +4024,15 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -5081,12 +5083,15 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -5364,11 +5369,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" From 641266122ad2f6e975b776e137f3d01dae3b3fef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:45:01 -0500 Subject: [PATCH 03/24] chore(deps): bump on-headers, compression, cookie-session and morgan (#15477) Bumps [on-headers](https://github.com/jshttp/on-headers), [compression](https://github.com/expressjs/compression), [cookie-session](https://github.com/expressjs/cookie-session) and [morgan](https://github.com/expressjs/morgan). These dependencies needed to be updated together. Updates `on-headers` from 1.0.2 to 1.1.0 - [Release notes](https://github.com/jshttp/on-headers/releases) - [Changelog](https://github.com/jshttp/on-headers/blob/master/HISTORY.md) - [Commits](https://github.com/jshttp/on-headers/compare/v1.0.2...v1.1.0) Updates `compression` from 1.7.4 to 1.8.1 - [Release notes](https://github.com/expressjs/compression/releases) - [Changelog](https://github.com/expressjs/compression/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/compression/compare/1.7.4...v1.8.1) Updates `cookie-session` from 2.0.0 to 2.1.1 - [Release notes](https://github.com/expressjs/cookie-session/releases) - [Changelog](https://github.com/expressjs/cookie-session/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/cookie-session/compare/v2.0.0...v2.1.1) Updates `morgan` from 1.10.0 to 1.10.1 - [Release notes](https://github.com/expressjs/morgan/releases) - [Changelog](https://github.com/expressjs/morgan/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/morgan/compare/1.10.0...1.10.1) --- updated-dependencies: - dependency-name: on-headers dependency-version: 1.1.0 dependency-type: direct:production - dependency-name: compression dependency-version: 1.8.1 dependency-type: direct:production - dependency-name: cookie-session dependency-version: 2.1.1 dependency-type: direct:production - dependency-name: morgan dependency-version: 1.10.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 98 ++++++++++++++++++++++++++++++----------------- package.json | 8 ++-- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index 741d453993..17290a2585 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,8 +24,8 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.3", "bootstrap": "^4.6.2", - "compression": "^1.7.4", - "cookie-session": "^2.0.0", + "compression": "^1.8.1", + "cookie-session": "^2.1.1", "coupon-code": "^0.4.5", "csv-stringify": "^5.6.5", "cwait": "^1.1.1", @@ -56,10 +56,10 @@ "moment": "^2.29.4", "moment-recur": "git://github.com/HabitRPG/moment-recur.git#d3e8e6da0806f13b74dd2e4d7d9053e6a63db119", "mongoose": "^8.9.5", - "morgan": "^1.10.0", + "morgan": "^1.10.1", "nconf": "^0.12.1", "node-gcm": "^1.0.5", - "on-headers": "^1.0.2", + "on-headers": "^1.1.0", "passport": "^0.5.3", "passport-facebook": "^3.0.0", "passport-google-oauth2": "^0.2.0", @@ -6906,30 +6906,23 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/compression/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6943,6 +6936,35 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7113,13 +7135,14 @@ } }, "node_modules/cookie-session": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0.tgz", - "integrity": "sha512-hKvgoThbw00zQOleSlUr2qpvuNweoqBtxrmx0UFosx6AGi9lYtLoA+RbsvknrEX8Pr6MDbdWAb2j6SnMn+lPsg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.1.1.tgz", + "integrity": "sha512-ji3kym/XZaFVew1+tIZk5ZLp9Z/fLv9rK1aZmpug0FsgE7Cu3ZDrUdRo7FT9vFjMYfNimrrUHJzywDwT7XEFlg==", + "license": "MIT", "dependencies": { - "cookies": "0.8.0", + "cookies": "0.9.1", "debug": "3.2.7", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1" }, "engines": { @@ -7164,9 +7187,10 @@ "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" }, "node_modules/cookies": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", - "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz", + "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==", + "license": "MIT", "dependencies": { "depd": "~2.0.0", "keygrip": "~1.1.0" @@ -14005,6 +14029,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "license": "MIT", "dependencies": { "tsscmp": "1.0.6" }, @@ -15519,15 +15544,16 @@ "dev": true }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -16856,9 +16882,10 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21043,6 +21070,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", "engines": { "node": ">=0.6.x" } diff --git a/package.json b/package.json index a3e3c401dd..87f91c7d87 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.3", "bootstrap": "^4.6.2", - "compression": "^1.7.4", - "cookie-session": "^2.0.0", + "compression": "^1.8.1", + "cookie-session": "^2.1.1", "coupon-code": "^0.4.5", "csv-stringify": "^5.6.5", "cwait": "^1.1.1", @@ -51,10 +51,10 @@ "moment": "^2.29.4", "moment-recur": "git://github.com/HabitRPG/moment-recur.git#d3e8e6da0806f13b74dd2e4d7d9053e6a63db119", "mongoose": "^8.9.5", - "morgan": "^1.10.0", + "morgan": "^1.10.1", "nconf": "^0.12.1", "node-gcm": "^1.0.5", - "on-headers": "^1.0.2", + "on-headers": "^1.1.0", "passport": "^0.5.3", "passport-facebook": "^3.0.0", "passport-google-oauth2": "^0.2.0", From 0f06ec1ab83f07d43f7a4622d575ddef2e23e241 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:09:13 -0500 Subject: [PATCH 04/24] chore(deps): bump brace-expansion in /website/client (#15461) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 1.1.12. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.12 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/client/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/website/client/package-lock.json b/website/client/package-lock.json index bad50688a5..c0080daec7 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -3393,9 +3393,10 @@ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" From 16e1523b085059738a6ef64e6e73e8ab2701698e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:09:23 -0500 Subject: [PATCH 05/24] chore(deps): bump tar-fs from 2.1.1 to 2.1.3 (#15446) Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 2.1.1 to 2.1.3. - [Commits](https://github.com/mafintosh/tar-fs/commits) --- updated-dependencies: - dependency-name: tar-fs dependency-version: 2.1.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17290a2585..e4b8dc309d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20528,9 +20528,10 @@ } }, "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", + "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", From f17a0c91a3219e3c33f922c7a6ac089a52fc677e Mon Sep 17 00:00:00 2001 From: Kalista Payne Date: Fri, 22 Aug 2025 10:08:33 -0500 Subject: [PATCH 06/24] Privacy Controls (#15492) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP(privacy): start of banner * WIP(privacy): layout rough * WIP(privacy): mobile layout, add modal * fix(privacy): implement toggle disable and setting row fold * fix(privacy): clean up a couple of styles * fix(privacy): adjust banner width at mobile sizes * WIP(privacy): remove Loggly echo of Amplitude data * fix(banners): account for privacy in snackbar position * WIP(privacy): dismiss banner * chore(analytics): update to maintaned GA4 library * fix(tests): lint, misuse of apiError * fix(analytics): add debug mode * fix(analytics): load new library on client * WIP(privacy): gtag.js based implementation * fix(analytics): lint issues * fix(lint): one more unused * fix(lint): client errors * feat(privacy): draft workflows * fix(analytics): linting, send needed user values * fix(tests): use mock analytics service in test env * fix(tests): restore previous logic for node env * feat(intro): jump to page 2 onboarding * WIP(auth): revisions to registration flow * WIP(privacy): landing page and banner revisions * WIP(signup): added new username, tos, privacy state * fix(signup): revert debugging logic * WIP(signup): add defaulting and checkbox * wip(signup): move social auth behind username screen * Squashed commit of the following: commit ca0a238e5f008525ed154c5eaf12e44f2fc22b00 Author: Phillip Thelen Date: Wed May 7 12:17:20 2025 +0200 make emails lowercase commit a2ce748558ce9134e6825208a7e66d78e720202e Author: Phillip Thelen Date: Wed Apr 9 13:27:01 2025 +0200 remove unused import commit cc6ce6c388d9693cf192c4bea733931fc8c31c37 Author: Phillip Thelen Date: Wed Apr 9 13:13:03 2025 +0200 add tests for new api route commit 0d40a6230b548625482aa9f6831c93ed9d62533a Author: Kalista Payne Date: Wed Jun 18 15:50:22 2025 -0500 update social tests commit 79177d6754589b9e54682af8a531b63f60215dab Author: Phillip Thelen Date: Wed Apr 9 10:21:51 2025 +0200 new api route to check if an email is available commit 11df73fe07eeb730c2a95593e18e14a931f52429 Author: Phillip Thelen Date: Wed Apr 9 10:21:39 2025 +0200 Add field to not register social account when called * Squashed commit of the following: commit b8a2f0b8ee12d065e3eb3ebfb2e720353e45607c Author: CuriousMagpie Date: Thu Jun 20 17:18:30 2024 -0400 update privacy policy * fix(vite): import syntax * feat(auth): precheck on defaulted username * feat(auth): add store action for check-email * feat(auth): check email before proceeding * WIP(login): refactor username screen * WIP(auth): complete login/reg flow * fix(auth): filter out expected 404 * fix(login): use allowRegister with Apple and add z-index to component * fix(login): style corrections and email passthru * Fix edgecase Signed-off-by: Kalista Payne * fix(auth): correct error behaviors * fix(auth): rewire Apple auth * make check-email check for restricted domains Signed-off-by: Kalista Payne * fix(signup): all the style * fix(express): return when responding * fix(error): reduce specificity for restricted domain issue * fix apple auth Signed-off-by: Kalista Payne * fix(signup): change from blur to 500ms debounce * fix(login): add missing 200 response in Apple flow * fix(signup): more reconciliation with @phillipthelen's work * fix(signup): now using token not code * fix(reg): don't bail on Apple if we're allowing reg * fix(auth): more reconciliation with @phillipthelen code * feat(copy): privacy policy updates * fix(copy): replace placeholder * fix(vue): use Vite syntax for scss import * fix(static): corrections to copy and css * chore(style): remove excess whitespace * use correct error Signed-off-by: Kalista Payne * fix(layout): inputs, add privacy banner * fix(login): button hover, more validation states * fix(login): further layout and UX corrections * fix(static): add back containing div for show/hide * fix(apple): clean out Apple token * fix(settings): only change preference on save * fix(settings): correct save/cancel behavior * fix(layout): consistent use of header/footer * fix(layout): reposition mountains for reg/login/forgot * fix(signup): partial rollback of /username route * refactor(signup): move /username to page * fix(apple): don't overwrite reg method * fix(username): don't skip empty validation * fix(input): don't show valid if no username * fix(login): clean out Apple token if using another method * fix(apple): possible race with token * fix(tests): some housekeeping * fix(config): copypasta * fix(lint): various cleanup * fix(lint): line squeeze * fix(lint): one more v-for * fix(groups): funnel invite flow to new username page * Squashed commit of the following: commit 3c5ba4bf24e4bb7996786520101f27ad66405bce Author: Kalista Payne Date: Mon Aug 18 14:38:31 2025 -0500 fix(privacy): update link ref commit 9d216f623b5dd65650726240f0197be96ec42075 Author: Kalista Payne Date: Mon Aug 18 14:18:22 2025 -0500 fix(privacy-tos): copy edits cont'd commit d744f471404e6f83142c35fe603938dc07a66f9e Author: Kalista Payne Date: Mon Aug 18 13:43:22 2025 -0500 fix(privacy): copy edits and ToC reflow commit 2c3c3fc9ce982c07c6db3d2a13f23b5005b75383 Author: Phillip Thelen Date: Mon Aug 18 18:46:24 2025 +0200 lint commit cf363034d554428102299bc8ae7aa6a596b25522 Author: Phillip Thelen Date: Mon Aug 18 18:34:54 2025 +0200 fix link commit 3afacd2c0569e01d251f71a850d8d2d223eb7d8a Author: Phillip Thelen Date: Mon Aug 18 18:34:42 2025 +0200 add updated terms commit 258b7224993f04362e6dce9afbb0959c35c95cd1 Author: Phillip Thelen Date: Mon Aug 18 17:58:42 2025 +0200 put back button to show/hide third party info commit 2992e0299b2d82fce4e5b153a3a9a3da1ee1c6b8 Author: Phillip Thelen Date: Mon Aug 18 17:58:32 2025 +0200 minor edits commit bb5e252299dcb6577a21ab092ac401420b1dc9aa Author: Kalista Payne Date: Sun Aug 17 21:01:50 2025 -0500 fix(privacy): update Section 3 commit c79af7baa84bbdffe90e8aaa53da44501f5c2569 Author: Kalista Payne Date: Fri Aug 15 17:28:49 2025 -0500 fix(privacy): various copy edits commit 100f2f4574fc47d1bcdbad4688616d0953a4051d Author: Phillip Thelen Date: Fri Aug 15 11:37:37 2025 +0200 add newline commit 11d1cfd0d94f164d7a1f8f67dea5e83f4d7f39cc Author: Phillip Thelen Date: Fri Aug 15 11:10:01 2025 +0200 update privacy policy commit 59b99badf3699b0d4f7a02ce4251ff1475878052 Author: Kalista Payne Date: Fri Aug 8 14:04:19 2025 -0500 5.38.2 commit 78daeb4191b55486a80282ce82bb6456bba95e2f Author: Kalista Payne Date: Fri Aug 8 13:36:19 2025 -0500 fix(apple): don't run auth middleware during redirect commit 93f8d60903383d1c888f901ae550d0410f89a855 Author: Weblate Date: Fri Aug 8 10:12:25 2025 +0200 Translated using Weblate (German) Currently translated at 99.4% (185 of 186 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (186 of 186 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (186 of 186 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (54 of 54 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (243 of 243 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (15 of 15 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (47 of 47 strings) Translated using Weblate (Dutch) Currently translated at 78.0% (2643 of 3385 strings) Translated using Weblate (Dutch) Currently translated at 40.8% (100 of 245 strings) Translated using Weblate (Polish) Currently translated at 89.9% (233 of 259 strings) Translated using Weblate (Dutch) Currently translated at 67.5% (175 of 259 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (110 of 110 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 20.8% (51 of 245 strings) Translated using Weblate (Turkish) Currently translated at 65.9% (60 of 91 strings) Translated using Weblate (Turkish) Currently translated at 65.9% (60 of 91 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 17.9% (44 of 245 strings) Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Jaime Martí Co-authored-by: Karmelkowy Co-authored-by: Linsey Dunya Pastoor Co-authored-by: Mete Olmez Co-authored-by: Sefa Uğurlu Co-authored-by: Summer_GUI Co-authored-by: Toro Mor Co-authored-by: Weblate Co-authored-by: innnko Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/challenge/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/tr/ Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/death/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/ Translate-URL: https://translate.habitica.com/projects/habitica/front/de/ Translate-URL: https://translate.habitica.com/projects/habitica/front/es/ Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/pl/ Translation: Habitica/Backgrounds Translation: Habitica/Challenge Translation: Habitica/Communityguidelines Translation: Habitica/Contrib Translation: Habitica/Death Translation: Habitica/Defaulttasks Translation: Habitica/Faq Translation: Habitica/Front Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Settings commit eb16fec41eed42ac681ac0667ec7dc510670b5bc Author: Phillip Thelen Date: Wed Aug 6 22:08:07 2025 +0200 Add interface to block ip-addresses or clients due to abuse (#15484) * Read IP blocks from database * begin building general blocking solution * add new frontend files * Add UI for managing blockers * correctly reset local data after creating blocker * Tweak wording * Add UI for managing blockers * restructure admin pages * improve test coverage * Improve blocker UI * add blocker to block emails from registration * lint fix * fix * lint fixes * fix import * add new permission for managing blockers * improve permission check * fix managing permissions from admin * improve navbar display for non fullAccess admin * update block error strings * lint fix * add option to errorHandler to skip logging * validate blocker value during input * improve blocker form display * chore(subproj): reconcile habitica-images * fix(scripts): use same Mongo version for dev/test * fix(whitespace): eof * documentation improvements * remove nconf import * remove old test --------- Co-authored-by: Kalista Payne Co-authored-by: Kalista Payne commit 47d832bf12dfdf0e1eb98f431edf5487e3ce6c3f Author: Fiz <34069775+Hafizzle@users.noreply.github.com> Date: Tue Aug 5 15:12:44 2025 -0500 Add backend support for Hydra mount (#15482) * chore: update time travelers shop to display seasonal backgrounds * chore: update time travelers banner (note CSS borken rn) * chore: fix borken CSS and update logic in shop * chore: added isSubscribed function, not working * chore: isSubscribed working but no bg for subscribers * chore: logic and css updates * chore: update habitica-images * chore: add check for trinket * chore: more time traveler shop logicking * Add backend support for Hydra mount - Add Dragon-Hydra to special mounts in stable.js - Configure as contributor level 7 reward with canFind: true - Add GIF format support for mount sprites - Enable admin panel granting capability * Fix Vue template errors in timeTravelers component * Fix duplicate template block in timeTravelers component * add CSS for Hydra mount GIF sprites Added CSS rules for Mount_Head_Dragon-Hydra and Mount_Body_Dragon-Hydra GIF sprites * Remove the separate Hydra mount dimension declaration --------- Co-authored-by: CuriousMagpie commit c03ab9855f055c1a5b44e1ca915af190764a2bad Author: Kalista Payne Date: Tue Aug 5 14:31:05 2025 -0500 5.38.1 commit 8f96b7b7fdfc8a51db5b4cf8aa96d291e27388d4 Author: Weblate Date: Tue Aug 5 13:02:45 2025 +0200 Translated using Weblate (Chinese (Traditional)) Currently translated at 17.1% (42 of 245 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 16.7% (41 of 245 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 16.3% (40 of 245 strings) Translated using Weblate (Polish) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 98.8% (425 of 430 strings) Translated using Weblate (French) Currently translated at 99.4% (184 of 185 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 15.9% (39 of 245 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (268 of 268 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (3385 of 3385 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (185 of 185 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.8% (3379 of 3385 strings) Translated using Weblate (Polish) Currently translated at 95.5% (128 of 134 strings) Translated using Weblate (Japanese) Currently translated at 94.7% (254 of 268 strings) Translated using Weblate (Polish) Currently translated at 94.0% (126 of 134 strings) Translated using Weblate (Japanese) Currently translated at 98.6% (424 of 430 strings) Translated using Weblate (Japanese) Currently translated at 98.3% (423 of 430 strings) Translated using Weblate (Japanese) Currently translated at 92.5% (798 of 862 strings) Translated using Weblate (Japanese) Currently translated at 92.4% (797 of 862 strings) Translated using Weblate (Japanese) Currently translated at 90.6% (781 of 862 strings) Translated using Weblate (Japanese) Currently translated at 91.9% (3112 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 91.9% (3111 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 94.0% (174 of 185 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (8 of 8 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 15.5% (38 of 245 strings) Translated using Weblate (Japanese) Currently translated at 91.6% (3104 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 93.5% (173 of 185 strings) Translated using Weblate (Japanese) Currently translated at 99.6% (279 of 280 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Japanese) Currently translated at 89.2% (769 of 862 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 94.4% (253 of 268 strings) Translated using Weblate (Japanese) Currently translated at 91.8% (170 of 185 strings) Translated using Weblate (Japanese) Currently translated at 97.9% (421 of 430 strings) Translated using Weblate (Japanese) Currently translated at 91.6% (3104 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 93.6% (251 of 268 strings) Translated using Weblate (Japanese) Currently translated at 90.8% (168 of 185 strings) Translated using Weblate (Japanese) Currently translated at 82.4% (202 of 245 strings) Translated using Weblate (French) Currently translated at 100.0% (268 of 268 strings) Translated using Weblate (French) Currently translated at 100.0% (3385 of 3385 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 15.1% (37 of 245 strings) Translated using Weblate (French) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 91.3% (3092 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 92.5% (248 of 268 strings) Translated using Weblate (Japanese) Currently translated at 92.5% (248 of 268 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (193 of 193 strings) Translated using Weblate (Croatian) Currently translated at 100.0% (15 of 15 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Korean) Currently translated at 22.8% (56 of 245 strings) Translated using Weblate (Korean) Currently translated at 47.7% (128 of 268 strings) Translated using Weblate (Croatian) Currently translated at 45.1% (121 of 268 strings) Translated using Weblate (Korean) Currently translated at 71.9% (620 of 862 strings) Translated using Weblate (Croatian) Currently translated at 70.6% (609 of 862 strings) Translated using Weblate (Croatian) Currently translated at 75.0% (6 of 8 strings) Translated using Weblate (Korean) Currently translated at 67.6% (291 of 430 strings) Translated using Weblate (Korean) Currently translated at 52.8% (1788 of 3385 strings) Translated using Weblate (Croatian) Currently translated at 50.3% (1706 of 3385 strings) Translated using Weblate (Croatian) Currently translated at 51.7% (134 of 259 strings) Translated using Weblate (Czech) Currently translated at 92.8% (130 of 140 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 86.9% (233 of 268 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (Danish) Currently translated at 92.1% (105 of 114 strings) Translated using Weblate (Czech) Currently translated at 89.4% (102 of 114 strings) Translated using Weblate (Czech) Currently translated at 83.5% (112 of 134 strings) Translated using Weblate (Spanish (Latin America)) Currently translated at 71.6% (308 of 430 strings) Translated using Weblate (Spanish (Latin America)) Currently translated at 100.0% (245 of 245 strings) Translated using Weblate (Serbian) Currently translated at 84.4% (49 of 58 strings) Translated using Weblate (Bulgarian) Currently translated at 51.4% (144 of 280 strings) Translated using Weblate (Swedish) Currently translated at 66.5% (286 of 430 strings) Translated using Weblate (Serbian) Currently translated at 65.5% (282 of 430 strings) Translated using Weblate (Slovak) Currently translated at 65.5% (282 of 430 strings) Translated using Weblate (Romanian) Currently translated at 66.7% (287 of 430 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Danish) Currently translated at 66.0% (284 of 430 strings) Translated using Weblate (Czech) Currently translated at 69.7% (300 of 430 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.7% (3377 of 3385 strings) Translated using Weblate (Swedish) Currently translated at 54.1% (1834 of 3385 strings) Translated using Weblate (Serbian) Currently translated at 50.6% (1714 of 3385 strings) Translated using Weblate (Slovak) Currently translated at 50.0% (1695 of 3385 strings) Translated using Weblate (Romanian) Currently translated at 60.5% (2050 of 3385 strings) Translated using Weblate (Hebrew) Currently translated at 38.4% (1301 of 3385 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (3385 of 3385 strings) Translated using Weblate (Danish) Currently translated at 54.0% (1829 of 3385 strings) Translated using Weblate (Czech) Currently translated at 59.6% (2020 of 3385 strings) Translated using Weblate (Swedish) Currently translated at 75.6% (140 of 185 strings) Translated using Weblate (Serbian) Currently translated at 73.5% (136 of 185 strings) Translated using Weblate (Slovak) Currently translated at 84.8% (157 of 185 strings) Translated using Weblate (Romanian) Currently translated at 78.9% (146 of 185 strings) Translated using Weblate (Portuguese) Currently translated at 82.1% (152 of 185 strings) Translated using Weblate (Italian) Currently translated at 91.8% (170 of 185 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (185 of 185 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (185 of 185 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (185 of 185 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (Danish) Currently translated at 77.2% (143 of 185 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 98.7% (242 of 245 strings) Translated using Weblate (Czech) Currently translated at 75.1% (139 of 185 strings) Translated using Weblate (Bulgarian) Currently translated at 74.5% (138 of 185 strings) Translated using Weblate (Czech) Currently translated at 8.1% (20 of 245 strings) Translated using Weblate (Swedish) Currently translated at 72.0% (621 of 862 strings) Translated using Weblate (Serbian) Currently translated at 65.1% (562 of 862 strings) Translated using Weblate (Slovak) Currently translated at 66.9% (577 of 862 strings) Translated using Weblate (Romanian) Currently translated at 77.7% (670 of 862 strings) Translated using Weblate (Portuguese) Currently translated at 70.0% (604 of 862 strings) Translated using Weblate (Polish) Currently translated at 67.1% (579 of 862 strings) Translated using Weblate (Italian) Currently translated at 86.8% (749 of 862 strings) Translated using Weblate (Indonesian) Currently translated at 86.0% (742 of 862 strings) Translated using Weblate (Hebrew) Currently translated at 66.1% (570 of 862 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 98.0% (845 of 862 strings) Translated using Weblate (Danish) Currently translated at 69.9% (603 of 862 strings) Translated using Weblate (Czech) Currently translated at 69.7% (601 of 862 strings) Translated using Weblate (Bulgarian) Currently translated at 66.3% (572 of 862 strings) Translated using Weblate (Serbian) Currently translated at 74.0% (305 of 412 strings) Translated using Weblate (Turkish) Currently translated at 100.0% (193 of 193 strings) Translated using Weblate (Danish) Currently translated at 90.0% (371 of 412 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Swedish) Currently translated at 53.6% (139 of 259 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Danish) Currently translated at 62.1% (161 of 259 strings) Translated using Weblate (Bulgarian) Currently translated at 54.0% (140 of 259 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 82.8% (222 of 268 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 99.4% (184 of 185 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 98.3% (241 of 245 strings) Translated using Weblate (Japanese) Currently translated at 91.3% (3092 of 3385 strings) Translated using Weblate (Japanese) Currently translated at 88.4% (237 of 268 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (243 of 243 strings) Translated using Weblate (Japanese) Currently translated at 82.4% (202 of 245 strings) Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Japanese) Currently translated at 87.3% (234 of 268 strings) Translated using Weblate (Japanese) Currently translated at 86.4% (160 of 185 strings) Translated using Weblate (Japanese) Currently translated at 99.8% (913 of 914 strings) Translated using Weblate (German) Currently translated at 100.0% (268 of 268 strings) Translated using Weblate (German) Currently translated at 100.0% (3377 of 3377 strings) Translated using Weblate (German) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (German) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (German) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (German) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (3385 of 3385 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (914 of 914 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (268 of 268 strings) Translated using Weblate (Russian) Currently translated at 88.5% (248 of 280 strings) Translated using Weblate (Spanish) Currently translated at 99.8% (3379 of 3385 strings) Translated using Weblate (German) Currently translated at 100.0% (862 of 862 strings) Co-authored-by: Ayaka Booker Co-authored-by: Chaotic Lawful Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Jaime Martí Co-authored-by: Jan Freihöfer Co-authored-by: Karmelkowy Co-authored-by: Lio Zam Co-authored-by: Mika Co-authored-by: Sophie LE MASLE Co-authored-by: Summer_GUI Co-authored-by: Vera Co-authored-by: Weblate Co-authored-by: Zhi Hao Li Co-authored-by: Zuz Q Co-authored-by: innnko Co-authored-by: 吳昀錡 Co-authored-by: 潘致翰 Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pl/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/character/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/ Translate-URL: https://translate.habitica.com/projects/habitica/content/da/ Translate-URL: https://translate.habitica.com/projects/habitica/content/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/death/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/es_419/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/ Translate-URL: https://translate.habitica.com/projects/habitica/front/bg/ Translate-URL: https://translate.habitica.com/projects/habitica/front/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/front/da/ Translate-URL: https://translate.habitica.com/projects/habitica/front/de/ Translate-URL: https://translate.habitica.com/projects/habitica/front/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/front/es/ Translate-URL: https://translate.habitica.com/projects/habitica/front/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/front/it/ Translate-URL: https://translate.habitica.com/projects/habitica/front/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/front/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/front/ro/ Translate-URL: https://translate.habitica.com/projects/habitica/front/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/front/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/front/sv/ Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/da/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/he/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/ro/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/sv/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/da/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/es_419/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/ko/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/ro/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/sv/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/bg/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/ru/ Translate-URL: https://translate.habitica.com/projects/habitica/messages/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/pl/ Translate-URL: https://translate.habitica.com/projects/habitica/overview/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/overview/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/da/ Translate-URL: https://translate.habitica.com/projects/habitica/quests/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/quests/es/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/bg/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/cs/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/da/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/he/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/id/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/it/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ko/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pl/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ro/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/sr/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/sv/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/bg/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/da/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/de/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/sv/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/de/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en_GB/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/hr/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ko/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/tasks/cs/ Translation: Habitica/Achievements Translation: Habitica/Backgrounds Translation: Habitica/Character Translation: Habitica/Content Translation: Habitica/Death Translation: Habitica/Faq Translation: Habitica/Front Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Groups Translation: Habitica/Limited Translation: Habitica/Messages Translation: Habitica/Npc Translation: Habitica/Overview Translation: Habitica/Pets Translation: Habitica/Quests Translation: Habitica/Questscontent Translation: Habitica/Settings Translation: Habitica/Subscriber Translation: Habitica/Tasks commit 1dde2674f6fb4664920c003eb827c8431e380479 Author: Kalista Payne Date: Mon Jun 16 16:43:56 2025 -0500 fix(content): don't filter out the thing we want commit 76122a8889a6780cd66ee76194e64dc47ce1223f Author: Kalista Payne Date: Wed Jun 4 14:28:27 2025 -0500 fix(mobile): provide Challenge categories via API commit 9e309a875e3025f3affb434a50c4dd3acaad64ac Author: Kalista Payne Date: Mon Jul 28 14:15:00 2025 -0500 5.38.0 commit 09e3a394b810ad7820e4b100deb588586b304c23 Author: Kalista Payne Date: Mon Jul 28 14:06:45 2025 -0500 5.37.3 commit eba263360f50d529fb28e3b9cad1f8058d83764f Author: Weblate Date: Mon Jul 28 21:03:17 2025 +0200 Translated using Weblate (German) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (German) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (German) Currently translated at 100.0% (3377 of 3377 strings) Translated using Weblate (German) Currently translated at 100.0% (3377 of 3377 strings) Translated using Weblate (German) Currently translated at 100.0% (3377 of 3377 strings) Translated using Weblate (German) Currently translated at 100.0% (243 of 243 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 98.6% (850 of 862 strings) Translated using Weblate (German) Currently translated at 99.8% (3373 of 3377 strings) Translated using Weblate (German) Currently translated at 99.8% (3373 of 3377 strings) Translated using Weblate (German) Currently translated at 99.8% (3373 of 3377 strings) Translated using Weblate (German) Currently translated at 99.5% (3361 of 3377 strings) Translated using Weblate (German) Currently translated at 99.5% (3361 of 3377 strings) Translated using Weblate (German) Currently translated at 99.5% (3361 of 3377 strings) Translated using Weblate (German) Currently translated at 99.4% (3360 of 3377 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (185 of 185 strings) Translated using Weblate (Polish) Currently translated at 67.1% (579 of 862 strings) Translated using Weblate (Polish) Currently translated at 67.1% (579 of 862 strings) Translated using Weblate (Polish) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Polish) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 100.0% (184 of 184 strings) Translated using Weblate (German) Currently translated at 100.0% (245 of 245 strings) Translated using Weblate (German) Currently translated at 100.0% (47 of 47 strings) Translated using Weblate (German) Currently translated at 100.0% (193 of 193 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 14.2% (35 of 245 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 13.8% (34 of 245 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 13.0% (32 of 245 strings) Translated using Weblate (Hebrew) Currently translated at 2.0% (5 of 245 strings) Translated using Weblate (Hebrew) Currently translated at 66.1% (570 of 862 strings) Translated using Weblate (Portuguese) Currently translated at 54.1% (1830 of 3377 strings) Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Jaime Martí Co-authored-by: Jan Freihöfer Co-authored-by: Jonathan Niessen <37.friedrich@gmail.com> Co-authored-by: Karmelkowy Co-authored-by: Katharina Co-authored-by: Laura Fleckenstein Co-authored-by: Omer I.S Co-authored-by: Remigiusz Haziak Co-authored-by: Uwe B Co-authored-by: Weblate Co-authored-by: Wellinton Cardoso Co-authored-by: cloudzzy Co-authored-by: 吳昀錡 Translate-URL: https://translate.habitica.com/projects/habitica/character/de/ Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pl/ Translate-URL: https://translate.habitica.com/projects/habitica/contrib/de/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/he/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/ Translate-URL: https://translate.habitica.com/projects/habitica/front/de/ Translate-URL: https://translate.habitica.com/projects/habitica/front/es/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/de/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/he/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pl/ Translation: Habitica/Character Translation: Habitica/Communityguidelines Translation: Habitica/Contrib Translation: Habitica/Faq Translation: Habitica/Front Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Npc Translation: Habitica/Questscontent commit 9550eec718d284d6ff74aec6264a1ca7042135be Author: Phillip Thelen Date: Mon Jul 28 16:50:38 2025 +0200 Fix 500 when deleting a very old group plan account (#15481) commit f267eb67e9af74129b86edf5092657377065b531 Author: Kalista Payne Date: Tue Jul 29 14:12:35 2025 -0500 fix(static): add back missing div for show/hide commit 28251f42ab5f886ab7bae70c5a29563691c5c22c Author: Kalista Payne Date: Thu Jul 24 22:59:01 2025 -0500 feat(privacy): preview page * feat(privacy): respect Global Privacy Control * fix(lint): remove unused component * fix(test): test user opts in to tracking * fix(test): add user pref to more contexts * fix(test): final spot in api-unit * fix(tests): update integrations * chore(privacy): add paragraph to s1, retire separate preview pages * fix(build): route copypasta * fix(router): lingering dead import --------- Signed-off-by: Kalista Payne Signed-off-by: Kalista Payne Co-authored-by: Phillip Thelen Co-authored-by: CuriousMagpie --- config.json.example | 53 +- package-lock.json | 106 +- package.json | 6 +- test/api/unit/libs/analyticsService.test.js | 69 +- test/api/unit/libs/bug-report.test.js | 1 + .../user/auth/GET-user_auth_apple.test.js | 4 +- .../user/auth/POST-user_auth_social.test.js | 43 + .../api/v4/user/auth/POST-check_email.test.js | 66 ++ website/client/package-lock.json | 6 + website/client/package.json | 1 + website/client/src/app.vue | 27 +- .../assets/images/home/signup-quill@2x.png | Bin 0 -> 33555 bytes website/client/src/assets/scss/button.scss | 26 +- website/client/src/assets/scss/form.scss | 139 ++- website/client/src/assets/scss/privacy.scss | 16 + website/client/src/assets/scss/static.scss | 2 +- .../client/src/assets/scss/typography.scss | 8 + .../src/assets/svg/for-css/checkbox-gray.svg | 3 + .../client/src/assets/svg/habitica-logo.svg | 8 +- website/client/src/components/appFooter.vue | 3 + .../client/src/components/auth/authForm.vue | 5 - .../components/auth/registerLoginReset.vue | 485 +++----- .../src/components/auth/registerUsername.vue | 255 ++++ .../client/src/components/creatorIntro.vue | 56 +- .../src/components/header/banners/privacy.vue | 123 ++ .../src/components/settings/privacyModal.vue | 101 ++ .../components/snackbars/notifications.vue | 9 + .../src/components/static/appleRedirect.vue | 16 +- .../src/components/static/groupPlans.vue | 18 +- website/client/src/components/static/home.vue | 848 ++++++-------- .../client/src/components/static/privacy.vue | 1033 ++++++++++++----- .../src/components/static/privacyReview.vue | 821 ------------- .../src/components/static/staticWrapper.vue | 25 +- .../client/src/components/static/terms.vue | 231 +++- .../src/components/static/termsReview.vue | 244 ---- .../client/src/components/ui/toggleSwitch.vue | 21 +- website/client/src/libs/analytics.js | 90 +- website/client/src/main.js | 4 +- website/client/src/mixins/accountCreation.js | 128 ++ .../client/src/pages/settings-overview.vue | 14 +- .../settings/components/saveCancelButtons.vue | 6 +- .../client/src/pages/settings/siteData.vue | 3 + .../siteDataRows/privacyPreferencesRow.vue | 137 +++ website/client/src/pages/user-main.vue | 11 +- website/client/src/router/index.js | 6 - website/client/src/router/static-routes.js | 25 +- website/client/src/store/actions/auth.js | 29 + website/client/src/store/index.js | 1 + .../client/tests/unit/components/home.spec.js | 117 -- website/common/locales/en/front.json | 21 +- website/common/locales/en/npc.json | 4 +- website/common/locales/en/settings.json | 16 +- .../common/script/errors/apiErrorMessages.js | 2 + website/common/script/fns/randomDrop.js | 2 + website/common/script/libs/onboarding.js | 3 + .../script/ops/buy/abstractBuyOperation.js | 11 +- website/common/script/ops/buy/buyArmoire.js | 9 +- .../common/script/ops/buy/buyMysterySet.js | 2 + .../script/ops/buy/hourglassPurchase.js | 2 + website/common/script/ops/buy/purchase.js | 1 + website/common/script/ops/changeClass.js | 1 + website/common/script/ops/feed.js | 2 + website/common/script/ops/hatch.js | 2 + website/common/script/ops/rebirth.js | 2 + website/common/script/ops/releaseMounts.js | 2 + website/common/script/ops/releasePets.js | 2 + website/common/script/ops/reroll.js | 2 + website/common/script/ops/revive.js | 3 +- website/common/script/ops/sleep.js | 3 + website/common/script/ops/unlock.js | 2 + website/server/controllers/api-v3/auth.js | 10 +- .../server/controllers/api-v3/challenges.js | 19 +- website/server/controllers/api-v3/chat.js | 3 + website/server/controllers/api-v3/groups.js | 29 +- website/server/controllers/api-v3/hall.js | 2 +- website/server/controllers/api-v3/members.js | 2 + website/server/controllers/api-v3/quests.js | 25 +- website/server/controllers/api-v3/tasks.js | 17 +- .../server/controllers/api-v3/tasks/groups.js | 3 + website/server/controllers/api-v3/user.js | 28 +- website/server/controllers/api-v4/auth.js | 46 + .../server/controllers/top-level/analytics.js | 10 +- website/server/libs/analyticsService.js | 126 +- website/server/libs/auth/apple.js | 1 + website/server/libs/auth/index.js | 4 +- website/server/libs/auth/social.js | 32 +- website/server/libs/auth/utils.js | 7 + website/server/libs/bug-report.js | 1 + website/server/libs/cron.js | 18 +- website/server/libs/invites/index.js | 21 +- website/server/libs/payments/gems.js | 2 + website/server/libs/payments/skuItem.js | 2 + website/server/libs/payments/subscriptions.js | 14 +- website/server/libs/tasks/index.js | 2 + website/server/libs/user/index.js | 3 + website/server/models/user/schema.js | 11 +- 96 files changed, 2990 insertions(+), 2991 deletions(-) create mode 100644 test/api/v4/user/auth/POST-check_email.test.js create mode 100644 website/client/src/assets/images/home/signup-quill@2x.png create mode 100644 website/client/src/assets/scss/privacy.scss create mode 100644 website/client/src/assets/svg/for-css/checkbox-gray.svg create mode 100644 website/client/src/components/auth/registerUsername.vue create mode 100644 website/client/src/components/header/banners/privacy.vue create mode 100644 website/client/src/components/settings/privacyModal.vue delete mode 100644 website/client/src/components/static/privacyReview.vue delete mode 100644 website/client/src/components/static/termsReview.vue create mode 100644 website/client/src/mixins/accountCreation.js create mode 100644 website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue delete mode 100644 website/client/tests/unit/components/home.spec.js diff --git a/config.json.example b/config.json.example index d81f1b9ad9..e34d071f06 100644 --- a/config.json.example +++ b/config.json.example @@ -8,18 +8,26 @@ "AMAZON_PAYMENTS_SELLER_ID": "SELLER_ID", "AMPLITUDE_KEY": "AMPLITUDE_KEY", "AMPLITUDE_SECRET": "AMPLITUDE_SECRET", + "APPLE_AUTH_CLIENT_ID": "", + "APPLE_AUTH_KEY_ID": "", + "APPLE_AUTH_PRIVATE_KEY": "", + "APPLE_TEAM_ID": "", "BASE_URL": "http://localhost:3000", + "BLOCKED_IPS": "", + "CONTENT_SWITCHOVER_TIME_OFFSET": 8, "CRON_SAFE_MODE": "false", "CRON_SEMI_SAFE_MODE": "false", + "DEBUG_ENABLED": "false", "DISABLE_REQUEST_LOGGING": "true", - "EMAILS_COMMUNITY_MANAGER_EMAIL": "admin@habitica.com", - "EMAILS_PRESS_ENQUIRY_EMAIL": "admin@habitica.com", - "EMAILS_TECH_ASSISTANCE_EMAIL": "admin@habitica.com", "EMAIL_SERVER_AUTH_PASSWORD": "password", "EMAIL_SERVER_AUTH_USER": "user", "EMAIL_SERVER_URL": "http://example.com", + "EMAILS_COMMUNITY_MANAGER_EMAIL": "admin@habitica.com", + "EMAILS_PRESS_ENQUIRY_EMAIL": "admin@habitica.com", + "EMAILS_TECH_ASSISTANCE_EMAIL": "admin@habitica.com", "ENABLE_CONSOLE_LOGS_IN_PROD": "false", "ENABLE_CONSOLE_LOGS_IN_TEST": "false", + "ENABLE_STACKDRIVER_TRACING": "false", "FACEBOOK_KEY": "123456789012345", "FACEBOOK_SECRET": "aaaabbbbccccddddeeeeffff00001111", "FLAG_REPORT_EMAIL": "email@example.com, email2@example.com", @@ -29,15 +37,16 @@ "IAP_GOOGLE_KEYDIR": "/path/to/google/public/key/dir/", "IGNORE_REDIRECT": "true", "ITUNES_SHARED_SECRET": "aaaabbbbccccddddeeeeffff00001111", + "LIVELINESS_PROBE_KEY": "", + "LOG_AMPLITUDE_EVENTS": "false", + "LOG_REQUESTS_EXCESSIVE_MODE": "false", "LOGGLY_CLIENT_TOKEN": "token", "LOGGLY_SUBDOMAIN": "example-subdomain", "LOGGLY_TOKEN": "example-token", - "LOG_REQUESTS_EXCESSIVE_MODE": "false", "MAINTENANCE_MODE": "false", - "NODE_DB_URI": "mongodb://localhost:27017/habitica-dev?replicaSet=rs", - "TEST_DB_URI": "mongodb://localhost:27017/habitica-test?replicaSet=rs", "MONGODB_POOL_SIZE": "10", "MONGODB_SOCKET_TIMEOUT": "20000", + "NODE_DB_URI": "mongodb://localhost:27017/habitica-dev?replicaSet=rs", "NODE_ENV": "development", "PATH": "bin:node_modules/.bin:/usr/local/bin:/usr/bin:/bin", "PAYPAL_BILLING_PLANS_basic_12mo": "basic_12mo", @@ -55,44 +64,34 @@ "PLAY_API_REFRESH_TOKEN": "aaaabbbbccccddddeeeeffff00001111", "PORT": 3000, "PUSH_CONFIGS_APN_ENABLED": "false", - "PUSH_CONFIGS_APN_KEY": "xxxxxxxxxx", "PUSH_CONFIGS_APN_KEY_ID": "xxxxxxxxxx", + "PUSH_CONFIGS_APN_KEY": "xxxxxxxxxx", "PUSH_CONFIGS_APN_TEAM_ID": "aaabbbcccd", "PUSH_CONFIGS_FCM_SERVER_API_KEY": "aaabbbcccd", + "RATE_LIMITER_ENABLED": "false", + "REDIS_HOST": "aaabbbcccdddeeefff", + "REDIS_PASSWORD": "12345678", + "REDIS_PORT": "1234", "S3_ACCESS_KEY_ID": "accessKeyId", "S3_BUCKET": "bucket", "S3_SECRET_ACCESS_KEY": "secretAccessKey", - "SESSION_SECRET": "YOUR SECRET HERE", "SESSION_SECRET_IV": "12345678912345678912345678912345", "SESSION_SECRET_KEY": "1234567891234567891234567891234567891234567891234567891234567891", + "SESSION_SECRET": "YOUR SECRET HERE", "SITE_HTTP_AUTH_ENABLED": "false", "SITE_HTTP_AUTH_PASSWORDS": "password,wordpass,passkey", "SITE_HTTP_AUTH_USERNAMES": "admin,tester,contributor", + "SKIP_SSL_CHECK_KEY": "key", "SLACK_FLAGGING_FOOTER_LINK": "https://habitrpg.github.io/flag-o-rama/", "SLACK_FLAGGING_URL": "https://hooks.slack.com/services/id/id/id", "SLACK_SUBSCRIPTIONS_URL": "https://hooks.slack.com/services/id/id/id", "SLACK_URL": "https://hooks.slack.com/services/some-url", + "SLOW_REQUEST_THRESHOLD": 1000, "STRIPE_API_KEY": "aaaabbbbccccddddeeeeffff00001111", "STRIPE_PUB_KEY": "22223333444455556666777788889999", "STRIPE_WEBHOOKS_ENDPOINT_SECRET": "111111", - "TRANSIFEX_SLACK_CHANNEL": "transifex", - "WEB_CONCURRENCY": 1, - "SKIP_SSL_CHECK_KEY": "key", - "ENABLE_STACKDRIVER_TRACING": "false", - "APPLE_AUTH_PRIVATE_KEY": "", - "APPLE_TEAM_ID": "", - "APPLE_AUTH_CLIENT_ID": "", - "APPLE_AUTH_KEY_ID": "", - "BLOCKED_IPS": "", - "LOG_AMPLITUDE_EVENTS": "false", - "RATE_LIMITER_ENABLED": "false", - "LIVELINESS_PROBE_KEY": "", - "REDIS_HOST": "aaabbbcccdddeeefff", - "REDIS_PORT": "1234", - "REDIS_PASSWORD": "12345678", - "TRUSTED_DOMAINS": "localhost,https://habitica.com", + "TEST_DB_URI": "mongodb://localhost:27017/habitica-test?replicaSet=rs", "TIME_TRAVEL_ENABLED": "false", - "DEBUG_ENABLED": "false", - "CONTENT_SWITCHOVER_TIME_OFFSET": 8, - "SLOW_REQUEST_THRESHOLD": 1000 + "TRUSTED_DOMAINS": "localhost,https://habitica.com", + "WEB_CONCURRENCY": 1 } diff --git a/package-lock.json b/package-lock.json index e4b8dc309d..70b1c4f5d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@babel/core": "^7.22.10", "@babel/preset-env": "^7.22.10", "@babel/register": "^7.22.15", + "@google-analytics/data": "^4.12.1", "@google-cloud/trace-agent": "^7.1.2", "@parse/node-apn": "^5.2.3", "@slack/webhook": "^6.1.0", @@ -75,7 +76,6 @@ "sinon": "^15.2.0", "stripe": "^12.18.0", "superagent": "^8.1.2", - "universal-analytics": "^0.5.3", "useragent": "^2.1.9", "uuid": "^9.0.0", "validator": "^13.11.0", @@ -1975,6 +1975,17 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/@google-analytics/data": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@google-analytics/data/-/data-4.12.1.tgz", + "integrity": "sha512-LzyrkVrnVUTYTmdmHayOZoroc+YA9GHEUrkSSuiXSmMSNbesuWy/MoTXugC1V7+8PCGqb2eQ1UtVVv/2BCAQYA==", + "dependencies": { + "google-gax": "^4.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@google-cloud/common": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-4.0.3.tgz", @@ -2318,7 +2329,6 @@ "version": "1.10.8", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.8.tgz", "integrity": "sha512-vYVqYzHicDqyKB+NQhAc54I1QWCBLCrYG6unqOIcBTHx+7x8C9lcoLj3KVJXs2VB4lUbpWY+Kk9NipcbXYWmvg==", - "optional": true, "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" @@ -2331,7 +2341,6 @@ "version": "0.7.13", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "optional": true, "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", @@ -2349,7 +2358,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "optional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2364,7 +2372,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "optional": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2378,7 +2385,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, "dependencies": { "color-name": "~1.1.4" }, @@ -2389,14 +2395,12 @@ "node_modules/@grpc/proto-loader/node_modules/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==" }, "node_modules/@grpc/proto-loader/node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "optional": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2405,7 +2409,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "optional": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2422,7 +2425,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "optional": true, "engines": { "node": ">=10" } @@ -2431,7 +2433,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "optional": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -2449,7 +2450,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "optional": true, "engines": { "node": ">=12" } @@ -2620,7 +2620,6 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "optional": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" @@ -2933,32 +2932,27 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "optional": true + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "optional": true + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "optional": true + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "optional": true + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "optional": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2967,32 +2961,27 @@ "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "optional": true + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "optional": true + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "optional": true + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "optional": true + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "optional": true + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@sindresorhus/is": { "version": "4.6.0", @@ -3127,8 +3116,7 @@ "node_modules/@types/caseless": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", - "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", - "optional": true + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==" }, "node_modules/@types/connect": { "version": "3.4.38", @@ -3231,8 +3219,7 @@ "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", - "optional": true + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/mime": { "version": "1.3.5", @@ -3282,7 +3269,6 @@ "version": "2.48.12", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", - "optional": true, "dependencies": { "@types/caseless": "*", "@types/node": "*", @@ -3294,7 +3280,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -3334,8 +3319,7 @@ "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "optional": true + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" }, "node_modules/@types/triple-beam": { "version": "1.3.5", @@ -3545,7 +3529,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "optional": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -9363,7 +9346,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "optional": true, "engines": { "node": ">=6" } @@ -11615,7 +11597,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.3.tgz", "integrity": "sha512-f4F2Y9X4+mqsrJuLZsuTljYuQpcBnQsCt9ScvZpdM8jGjqrcxyJi5JUiqtq0jtpdHVPzyit0N7f5t07e+kH5EA==", - "optional": true, "dependencies": { "@grpc/grpc-js": "~1.10.3", "@grpc/proto-loader": "^0.7.0", @@ -11638,7 +11619,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "optional": true, "dependencies": { "debug": "^4.3.4" }, @@ -11650,7 +11630,6 @@ "version": "6.6.0", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.6.0.tgz", "integrity": "sha512-bpOZVQV5gthH/jVCSuYuokRo2bTKOcuBiVWpjmTn6C5Agl5zclGfTljuGsQZxwwDBkli+YhZhP4TdlqTnhOezQ==", - "optional": true, "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", @@ -11666,7 +11645,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", - "optional": true, "dependencies": { "gaxios": "^6.0.0", "json-bigint": "^1.0.0" @@ -11679,7 +11657,6 @@ "version": "9.10.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.10.0.tgz", "integrity": "sha512-ol+oSa5NbcGdDqA+gZ3G3mev59OHBZksBTxY/tYwjtcp1H/scAFwJfSQU9/1RALoyZ7FslNbke8j4i3ipwlyuQ==", - "optional": true, "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", @@ -11696,7 +11673,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", - "optional": true, "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" @@ -11709,7 +11685,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "optional": true, "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -11723,7 +11698,6 @@ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", "hasInstallScript": true, - "optional": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -11746,7 +11720,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", - "optional": true, "dependencies": { "@types/request": "^2.48.8", "extend": "^3.0.2", @@ -11760,7 +11733,6 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", - "optional": true, "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", @@ -11776,7 +11748,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, "dependencies": { "debug": "4" }, @@ -11788,7 +11759,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -14267,8 +14237,7 @@ "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "optional": true + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", @@ -16691,7 +16660,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "optional": true, "engines": { "node": ">= 6" } @@ -17914,7 +17882,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.1.tgz", "integrity": "sha512-8awBvjO+FwkMd6gNoGFZyqkHZXCFd54CIYTb6De7dPaufGJ2XNW+QUNqbMr8MaAocMdb+KpsD4rxEOaTBDCffA==", - "optional": true, "dependencies": { "protobufjs": "^7.2.5" }, @@ -17927,7 +17894,6 @@ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz", "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==", "hasInstallScript": true, - "optional": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -21397,26 +21363,6 @@ "through2-filter": "^3.0.0" } }, - "node_modules/universal-analytics": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.5.3.tgz", - "integrity": "sha512-HXSMyIcf2XTvwZ6ZZQLfxfViRm/yTGoRgDeTbojtq6rezeyKB0sTBcKH2fhddnteAHRcHiKgr/ACpbgjGOC6RQ==", - "dependencies": { - "debug": "^4.3.1", - "uuid": "^8.0.0" - }, - "engines": { - "node": ">=12.18.2" - } - }, - "node_modules/universal-analytics/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/package.json b/package.json index 87f91c7d87..c847bdd9fa 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@babel/core": "^7.22.10", "@babel/preset-env": "^7.22.10", "@babel/register": "^7.22.15", + "@google-analytics/data": "^4.12.1", "@google-cloud/trace-agent": "^7.1.2", "@parse/node-apn": "^5.2.3", "@slack/webhook": "^6.1.0", @@ -70,7 +71,6 @@ "sinon": "^15.2.0", "stripe": "^12.18.0", "superagent": "^8.1.2", - "universal-analytics": "^0.5.3", "useragent": "^2.1.9", "uuid": "^9.0.0", "validator": "^13.11.0", @@ -106,8 +106,8 @@ "start": "node --watch ./website/server/index.js", "start:simple": "node ./website/server/index.js", "debug": "node --watch --inspect ./website/server/index.js", - "mongo:dev": "run-rs -v 7.0.23 -l ubuntu2404 --keep --dbpath mongodb-data --number 1 --quiet", - "mongo:test": "run-rs -v 7.0.23 -l ubuntu2404 --keep --dbpath mongodb-data-testing --number 1 --quiet", + "mongo:dev": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data --number 1 --quiet", + "mongo:test": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data-testing --number 1 --quiet", "postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install", "apidoc": "gulp apidoc", "heroku-postbuild": ".heroku/report_deploy.sh" diff --git a/test/api/unit/libs/analyticsService.test.js b/test/api/unit/libs/analyticsService.test.js index 68177557cb..b07f08df9b 100644 --- a/test/api/unit/libs/analyticsService.test.js +++ b/test/api/unit/libs/analyticsService.test.js @@ -1,15 +1,11 @@ /* eslint-disable camelcase */ import nconf from 'nconf'; import Amplitude from 'amplitude'; -import { Visitor } from 'universal-analytics'; import * as analyticsService from '../../../../website/server/libs/analyticsService'; describe('analyticsService', () => { beforeEach(() => { sandbox.stub(Amplitude.prototype, 'track').returns(Promise.resolve()); - - sandbox.stub(Visitor.prototype, 'event'); - sandbox.stub(Visitor.prototype, 'transaction'); }); afterEach(() => { @@ -37,8 +33,6 @@ describe('analyticsService', () => { data; beforeEach(() => { - Visitor.prototype.event.yields(); - eventType = 'Cron'; data = { category: 'behavior', @@ -49,6 +43,11 @@ describe('analyticsService', () => { 'x-client': 'habitica-web', 'user-agent': '', }, + user: { + preferences: { + analyticsConsent: true, + }, + }, }; }); @@ -295,6 +294,9 @@ describe('analyticsService', () => { rewards: [{ _id: 'reward' }], balance: 12, loginIncentives: 1, + preferences: { + analyticsConsent: true, + }, }; data.user = user; @@ -326,37 +328,12 @@ describe('analyticsService', () => { }); }); }); - - context('GA', () => { - it('calls out to GA', () => analyticsService.track(eventType, data) - .then(() => { - expect(Visitor.prototype.event).to.be.calledOnce; - })); - - 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; let - itemSpy; + let data; beforeEach(() => { - Visitor.prototype.event.yields(); - - itemSpy = sandbox.stub().returnsThis(); - - Visitor.prototype.transaction.returns({ - item: itemSpy, - send: sandbox.stub().yields(), - }); - data = { uuid: 'user-id', sku: 'paypal-checkout', @@ -370,6 +347,11 @@ describe('analyticsService', () => { 'x-client': 'habitica-web', 'user-agent': '', }, + user: { + preferences: { + analyticsConsent: true, + }, + }, }; }); @@ -533,6 +515,9 @@ describe('analyticsService', () => { dailys: [{ _id: 'daily' }], todos: [{ _id: 'todo' }], rewards: [{ _id: 'reward' }], + preferences: { + analyticsConsent: true, + }, }; data.user = user; @@ -561,26 +546,6 @@ describe('analyticsService', () => { }); }); }); - - context('GA', () => { - 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', () => 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'); - })); - }); }); describe('mockAnalyticsService', () => { diff --git a/test/api/unit/libs/bug-report.test.js b/test/api/unit/libs/bug-report.test.js index 5cb33d39b4..db09de21ca 100644 --- a/test/api/unit/libs/bug-report.test.js +++ b/test/api/unit/libs/bug-report.test.js @@ -34,6 +34,7 @@ describe('bug-report', () => { emailData: { BROWSER_UA: userAgent, REPORT_MSG: userMessage, + USER_ANALYTICS: undefined, USER_CLASS: 'warrior', USER_CONSECUTIVE_MONTHS: 0, USER_COSTUME: 'false', diff --git a/test/api/v3/integration/user/auth/GET-user_auth_apple.test.js b/test/api/v3/integration/user/auth/GET-user_auth_apple.test.js index b1c97f6ca4..b692f60fba 100644 --- a/test/api/v3/integration/user/auth/GET-user_auth_apple.test.js +++ b/test/api/v3/integration/user/auth/GET-user_auth_apple.test.js @@ -25,7 +25,7 @@ describe('GET /user/auth/apple', () => { }); it('registers a new user', async () => { - const response = await api.get(appleEndpoint); + const response = await api.get(`${appleEndpoint}?allowRegister=true`); expect(response.apiToken).to.exist; expect(response.id).to.exist; @@ -35,7 +35,7 @@ describe('GET /user/auth/apple', () => { }); it('logs an existing user in', async () => { - const registerResponse = await api.get(appleEndpoint); + const registerResponse = await api.get(`${appleEndpoint}?allowRegister=true`); const response = await api.get(appleEndpoint); diff --git a/test/api/v3/integration/user/auth/POST-user_auth_social.test.js b/test/api/v3/integration/user/auth/POST-user_auth_social.test.js index 85792e98a1..6a29d56b49 100644 --- a/test/api/v3/integration/user/auth/POST-user_auth_social.test.js +++ b/test/api/v3/integration/user/auth/POST-user_auth_social.test.js @@ -6,6 +6,7 @@ import { translate as t, getProperty, } from '../../../../../helpers/api-integration/v3'; +import apiErrorMessages from '../../../../../../website/common/script/errors/apiErrorMessages'; describe('POST /user/auth/social', () => { let api; @@ -64,6 +65,18 @@ describe('POST /user/auth/social', () => { await expect(getProperty('users', response.id, 'profile.name')).to.eventually.equal('a google user'); }); + it('fails if allowRegister is false and user does not exist', async () => { + await expect(api.post(endpoint, { + authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase + network, + allowRegister: false, + })).to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: `${apiErrorMessages.socialFlowUserNotFound} ${user.auth.local.username}+google@example.com`, + }); + }); + it('logs an existing user in', async () => { const registerResponse = await api.post(endpoint, { authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase @@ -131,6 +144,36 @@ describe('POST /user/auth/social', () => { expect(response.newUser).to.be.false; }); + it('logs an existing user into their social account if allowRegister is false', async () => { + const registerResponse = await api.post(endpoint, { + authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase + network, + }); + expect(registerResponse.newUser).to.be.true; + // This is important for existing accounts before the new social handling + passport._strategies.google.userProfile.restore(); + const expectedResult = { + id: randomGoogleId, + displayName: 'a google user', + emails: [ + { value: user.auth.local.email }, + ], + }; + sandbox.stub(passport._strategies.google, 'userProfile').yields(null, expectedResult); + + const response = await api.post(endpoint, { + authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase + network, + allowRegister: false, + }); + + expect(response.apiToken).to.eql(registerResponse.apiToken); + expect(response.id).to.eql(registerResponse.id); + expect(response.apiToken).not.to.eql(user.apiToken); + expect(response.id).not.to.eql(user._id); + expect(response.newUser).to.be.false; + }); + it('add social auth to an existing user', async () => { const response = await user.post(endpoint, { authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase diff --git a/test/api/v4/user/auth/POST-check_email.test.js b/test/api/v4/user/auth/POST-check_email.test.js new file mode 100644 index 0000000000..afcfd18593 --- /dev/null +++ b/test/api/v4/user/auth/POST-check_email.test.js @@ -0,0 +1,66 @@ +import { + translate as t, + requester, + generateUser, +} from '../../../../helpers/api-integration/v4'; + +const ENDPOINT = '/user/auth/check-email'; + +describe('POST /user/auth/check-email', () => { + const email = 'SOmE-nEw-emAIl_2@example.net'; + let api; + + beforeEach(async () => { + api = requester(); + }); + + it('returns email if it is not used yet', async () => { + const response = await api.post(ENDPOINT, { + email, + }); + expect(response.email).to.eql(email); + expect(response.valid).to.be.true; + }); + + it('rejects if email is not provided', async () => { + await expect(api.post(ENDPOINT, { + })).to.eventually.be.rejected.and.eql({ + code: 400, + error: 'BadRequest', + message: 'Invalid request parameters.', + }); + }); + + it('rejects if email is already taken', async () => { + const user = await generateUser(); + + const response = await api.post(ENDPOINT, { + email: user.auth.local.email, + }); + expect(response).to.eql({ + valid: false, + email: user.auth.local.email, + error: t('cannotFulfillReq'), + }); + }); + + it('rejects if casing is different', async () => { + const user = await generateUser(); + + const response = await api.post(ENDPOINT, { + email: user.auth.local.email.toUpperCase(), + }); + expect(response).to.eql({ + valid: false, + email: user.auth.local.email.toUpperCase(), + error: t('cannotFulfillReq'), + }); + }); + + it('rejects if email uses restricted domain', async () => { + const response = await api.post(ENDPOINT, { + email: 'fake@habitica.com', + }); + expect(response.valid).to.be.false; + }); +}); diff --git a/website/client/package-lock.json b/website/client/package-lock.json index c0080daec7..df62c25ec8 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -42,6 +42,7 @@ "vue": "^2.7.10", "vue-fragment": "^1.6.0", "vue-mugen-scroll": "^0.2.6", + "vue-plugin-load-script": "^1.3.6", "vue-router": "^3.6.5", "vuedraggable": "^2.24.3", "vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0" @@ -8817,6 +8818,11 @@ "node": ">=4" } }, + "node_modules/vue-plugin-load-script": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/vue-plugin-load-script/-/vue-plugin-load-script-1.3.6.tgz", + "integrity": "sha512-O+mpw32dXY3tMBBNKm7/qIByJV1QbHJ+0CXI4GeXx4NHU/Rg+bv7bvzugkEWnYcB/43WvR8ZD2K9KQIeVng1bA==" + }, "node_modules/vue-router": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz", diff --git a/website/client/package.json b/website/client/package.json index 62da71d323..44fb393d61 100644 --- a/website/client/package.json +++ b/website/client/package.json @@ -46,6 +46,7 @@ "vue": "^2.7.10", "vue-fragment": "^1.6.0", "vue-mugen-scroll": "^0.2.6", + "vue-plugin-load-script": "^1.3.6", "vue-router": "^3.6.5", "vuedraggable": "^2.24.3", "vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0" diff --git a/website/client/src/app.vue b/website/client/src/app.vue index d8f561c3c3..58fa3e7e59 100644 --- a/website/client/src/app.vue +++ b/website/client/src/app.vue @@ -108,7 +108,6 @@ diff --git a/website/client/src/components/auth/registerUsername.vue b/website/client/src/components/auth/registerUsername.vue new file mode 100644 index 0000000000..cb5f7efee8 --- /dev/null +++ b/website/client/src/components/auth/registerUsername.vue @@ -0,0 +1,255 @@ + + + + + + + diff --git a/website/client/src/components/creatorIntro.vue b/website/client/src/components/creatorIntro.vue index 933a23febf..e0e566cdd5 100644 --- a/website/client/src/components/creatorIntro.vue +++ b/website/client/src/components/creatorIntro.vue @@ -5,7 +5,7 @@ :size="editing ? 'lg' : 'md'" :hide-header="true" :hide-footer="true" - :modal-class="{'page-2':modalPage > 1 && !editing}" + :modal-class="{'page-2': !editing}" :no-close-on-esc="!editing" :no-close-on-backdrop="!editing" > @@ -13,20 +13,6 @@ v-if="editing" @close="close()" /> -
-
-

- {{ $t('welcomeTo') }} -

- -
-

@@ -433,8 +418,7 @@
-
-

-

- {{ $t('justinIntroMessageUsername') }} -

-
-

{{ $t('justinIntroMessageAppearance') }}

+

@@ -484,25 +459,12 @@

-
import { setup as setupPayments } from '@/libs/payments'; import paymentsMixin from '../../mixins/payments'; -import AuthForm from '../auth/authForm.vue'; import GroupPlanCreationModal from '../group-plans/groupPlanCreationModal.vue'; export default { components: { - AuthForm, GroupPlanCreationModal, }, mixins: [paymentsMixin], @@ -353,13 +339,11 @@ export default { }, methods: { authenticate () { - this.$root.$emit('bv::hide::modal', 'group-plan'); this.$root.$emit('bv::show::modal', 'create-group'); }, goToNewGroupPage () { if (this.isStaticPage && !this.user) { - this.modalOption = 'static'; - return this.$root.$emit('bv::show::modal', 'group-plan'); + return this.$router.push('/register'); } if (this.upgradingGroup._id) { return this.stripeGroup({ group: this.upgradingGroup, upgrade: true }); diff --git a/website/client/src/components/static/home.vue b/website/client/src/components/static/home.vue index 43742d5582..1f2a94bbdc 100644 --- a/website/client/src/components/static/home.vue +++ b/website/client/src/components/static/home.vue @@ -8,124 +8,117 @@
{{ $t('jsDisabledLink') }} -
-
-
-
- -

{{ $t('motivateYourself') }}

-

- {{ $t('timeToGetThingsDone', {userCountInMillions}) }} -

-
-
-

- {{ $t('singUpForFree') }} -

-
-

- {{ $t('usernameLimitations') }} + +

+
+
+
+
+ +

{{ $t('motivateYourself') }}

+

+ {{ $t('timeToGetThingsDone', {userCountInMillions}) }}

- - -
- - {{ issue }} -
- - -
- {{ $t('minPasswordLength') }} -
- -
- {{ $t('passwordConfirmationMatch') }} -
-

- - -
- {{ $t('or') }}
-
- -
+ - {{ $t('signUpWithSocial', {social: 'Apple'}) }} - + v-if="passwordInvalid" + class="input-error" + > + {{ $t('minPasswordLength') }} +
+ +
+ {{ $t('passwordConfirmationMatch') }} +
+ + +
+ {{ $t('or') }} +
+
+ + +
@@ -135,218 +128,218 @@ >
-
-
-
-
-
-
-
-
-

{{ $t('gamifyYourLife') }}

-

- {{ $t('aboutHabitica') }} -

+ id="gamify-life" + class="bg-purple-100 white" + > +
+
-
-
-
- - {{ $t('trackYourGoals') }} -

{{ $t('trackYourGoalsDesc') }}

+
+
+
+

{{ $t('gamifyYourLife') }}

+

+ {{ $t('aboutHabitica') }} +

+
+
+
+
+ + {{ $t('trackYourGoals') }} +

{{ $t('trackYourGoalsDesc') }}

+
+
+ + {{ $t('earnRewards') }} +

{{ $t('earnRewardsDesc') }}

+
+
+ + {{ $t('battleMonsters') }} +

{{ $t('battleMonstersDesc') }}

+
+
-
- - {{ $t('earnRewards') }} -

{{ $t('earnRewardsDesc') }}

-
-
- - {{ $t('battleMonsters') }} -

{{ $t('battleMonstersDesc') }}

-
-
-
-
-
-
-
-
-
-
-

{{ $t('playersUseToImprove') }}

+
-
-
- - {{ $t('healthAndFitness') }} -

{{ $t('healthAndFitnessDesc') }}

-
-
- - {{ $t('schoolAndWork') }} -

{{ $t('schoolAndWorkDesc') }}

-
-
- - {{ $t('muchmuchMore') }} -

{{ $t('muchmuchMoreDesc') }}

-
-
-
-
-
-
+ id="use-cases" + class="bg-purple-100 white" + > +
+
+
+

{{ $t('playersUseToImprove') }}

+
+
+
+
+ + {{ $t('healthAndFitness') }} +

{{ $t('healthAndFitnessDesc') }}

+
+
+ + {{ $t('schoolAndWork') }} +

{{ $t('schoolAndWorkDesc') }}

+
+
+ + {{ $t('muchmuchMore') }} +

{{ $t('muchmuchMoreDesc') }}

+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+ id="level-up-anywhere" + class="bg-purple-50 white" + > +
+
+
+
+
+
+

{{ $t('levelUpAnywhere') }}

+

{{ $t('levelUpAnywhereDesc') }}

+ + +
+
-
-

{{ $t('levelUpAnywhere') }}

-

{{ $t('levelUpAnywhereDesc') }}

- - +
+
-
-
-
-
-
-
@@ -354,16 +347,26 @@ diff --git a/website/client/src/components/static/privacy.vue b/website/client/src/components/static/privacy.vue index c2615ce69b..3599e9a5e8 100644 --- a/website/client/src/components/static/privacy.vue +++ b/website/client/src/components/static/privacy.vue @@ -1,368 +1,821 @@ + + + + diff --git a/website/client/src/components/static/privacyReview.vue b/website/client/src/components/static/privacyReview.vue deleted file mode 100644 index 3599e9a5e8..0000000000 --- a/website/client/src/components/static/privacyReview.vue +++ /dev/null @@ -1,821 +0,0 @@ - - - - - diff --git a/website/client/src/components/static/staticWrapper.vue b/website/client/src/components/static/staticWrapper.vue index 2b6b7f5a64..bc2b1707c0 100644 --- a/website/client/src/components/static/staticWrapper.vue +++ b/website/client/src/components/static/staticWrapper.vue @@ -2,7 +2,7 @@
+
+
+
+ - -
+ />
-
+
@@ -263,13 +269,16 @@ export default { StaticHeader, }, computed: { - showContentWrap () { - return this.$route.name !== 'news'; - }, footerId () { if (this.$route.name === 'plans') return null; return 'purple-footer'; }, + loginFlow () { + return ['login', 'register', 'username'].indexOf(this.$route.name) !== -1; + }, + showContentWrap () { + return this.$route.name !== 'news'; + }, }, }; diff --git a/website/client/src/components/static/terms.vue b/website/client/src/components/static/terms.vue index e3b99aa39d..6a67e5cb5f 100644 --- a/website/client/src/components/static/terms.vue +++ b/website/client/src/components/static/terms.vue @@ -3,49 +3,128 @@

Terms of Service

- Last Updated: December 14, 2021 + Last Updated September 1, 2025.

Thanks for choosing Habitica!

Our Service is provided by HabitRPG, Inc. ("HabitRPG"). By accepting these Terms of Service and our Privacy Policy located at: https://habitica.com/static/privacy (collectively, the "Agreement"), registering for the Service (as defined below), accessing or using any part of the Service, or otherwise manifesting your assent to the Agreement, you acknowledge that you have read, understood, and agree to be legally bound by the Agreement. If you do not agree to (or cannot comply with) the Agreement, you are not permitted to access or use the Service. + >https://habitica.com/static/privacy (collectively, the "Agreement"), using our website, Habitica.com, or our other features or services (collectively, “the Services”, or otherwise manifesting your assent to the Agreement, you acknowledge that you have read, understood, and agree to be legally bound by the Agreement. If you do not agree to (or cannot comply with) the Agreement, you are not permitted to access or use the Service. By accepting or agreeing to this Agreement on behalf of a company or other legal entity, you represent and warrant that you have the authority to bind that company or other legal entity to the Agreement and, in such event, "you" and "your" will refer and apply to that company or other legal entity. You further represent and warrant that your assent to this Agreement constitutes an electronic signature as defined by the Electronic Signatures in Global and National Commerce Act (“E-Sign”) and the Uniform Electronic Transactions Act (“UETA”) and that you have formed, executed, entered into, and accepted the terms of and otherwise authenticated the Agreement and acknowledged and agreed that the Agreement is an electronic record for purposes of E- Sign, UETA, and the Uniform Computer Information Transactions Act and, as such, is completely valid, has legal effect, is enforceable, and is binding on, and non- refutable by, you and/or any entity on whose behalf you are acting.

-

By accepting or agreeing to this Agreement on behalf of a company or other legal entity, you represent and warrant that you have the authority to bind that company or other legal entity to the Agreement and, in such event, "you" and "your" will refer and apply to that company or other legal entity.

- THE SECTIONS BELOW TITLED "BINDING ARBITRATION," AND "CLASS ACTION WAIVER" CONTAIN A BINDING ARBITRATION AGREEMENT AND CLASS ACTION WAIVER. THEY AFFECT YOUR LEGAL RIGHTS. PLEASE READ THEM. + THE SECTIONS BELOW TITLED "BINDING ARBITRATION' AND "CLASS ACTION WAIVER" CONTAIN A BINDING ARBITRATION AGREEMENT AND CLASS ACTION WAIVER. THEY AFFECT YOUR LEGAL RIGHTS. PLEASE READ THEM CAREFULLY.

Changes to the Terms of Service

-

These Terms of Service are effective as of the last updated date stated at the top of this page. We may change these Terms of Service from time to time with or without notice to you. By accessing the Service after we make any such changes to this Terms of Service, you are deemed to have accepted such changes. Please be aware that, to the extent permitted by applicable law, our use of the information collected is governed by the Terms of Service in effect at the time we collect the information. Please refer back to this Terms of Service on a regular basis.

-

Our Service allows you to upload, store, send, download, or receive content, including but not limited to information, text, graphics, artwork, or other material ("Content"). You retain ownership of any intellectual property rights that you have in your Content. You hereby grant HabitRPG a worldwide, perpetual, irrevocable, sublicenseable, transferable, assignable, non-exclusive, and royalty-free right and license to use, reproduce, distribute, adapt, modify, translate, create derivative works of, publicly perform, publicly display, digitally perform, make, have made, sell, offer for sale, and import your Content, including all intellectual property rights therein. You represent, warrant, and agree that your Content does not and will not violate any third-party intellectual property, privacy, or other rights, and that you have all right, title and interest in and to your Content required to grant us the license above. We reserve the right at all times, but have no obligation, to delete or refuse to use or distribute any Content on or through the Service, including your Content.

-

Ideas and Suggestions/Requests

-

HabitRPG appreciates receiving your ideas, comments, suggestions and requests regarding the Service ("Unsolicited Ideas"). By submitting your Unsolicited Ideas (in any form or medium), you are transferring all your right, title and interest therein exclusively to HabitRPG. As the owner of Unsolicited Ideas, we have unrestricted rights to use, disclose and process the Unsolicited Ideas for any purpose whatsoever without any compensation to you. You also give up any claim that any use, disclosure and processing by us or our licensees of your Unsolicited Ideas violates any of your rights, including moral rights, privacy rights, rights to publicity, proprietary or other rights, and rights to credit for the material or ideas set for therein.

-

Software in Our Service

-

When the Service requires or includes downloadable software ("Software"), it may may update automatically on your device once a new version or features become available to you. Some platforms may let you adjust your automatic update settings.

-

HabitRPG hereby grants you a personal, worldwide, royalty-free, non-assignable and non-exclusive license to use the Software provided by HabitRPG as part of the Service. You may not copy, modify, distribute, sell, or lease any part of our Service or included Software you are explicitly allowed to do so by the GPL-3.0 license, or you have our written permission for those parts not covered by the open source license.

-

Third party applications may use one of the permitted logos and signifiers in order to represent their applicability to the Service, but may not claim formal association with and/or impersonate HabitRPG or our staff without prior written consent. Third Party applications, the companies that own or provide them, and their employees and agents, are not authorized to make any promises or representations on our behalf, or change the terms of this Agreement.

-

We allow for personal, non-commercial uses like fanart under Commercial Commons License CC-NC-SA 3.0 terms.

-

Outside the above explicitly allowed use cases, you may not use our trademarks, service marks, trade names, logos, domain names, taglines, or trade dress without a signed written contract with us granting you a license to do so.

+

+ These Terms of Service are effective as of the last updated date stated at the top of this page. We may change these Terms of Service from time to time with or without notice to you. By accessing the Service after we make any such changes to this Terms of Service, you are deemed to have accepted such changes. Please be aware that, to the extent permitted by applicable law, our use of the information collected is governed by the Terms of Service in effect at the time we collect the information. Please refer back to this Terms of Service on a regular basis. +

+

Intellectual Property

+

+ Our Services allow you to upload, store, send, download, or receive content, including but not limited to information, text, graphics, artwork, or other material ("Content"). You retain ownership of any intellectual property rights that you had in your Content prior to using it in connection with the Service. You hereby grant HabitRPG a worldwide, perpetual, irrevocable, sublicenseable, transferable, assignable, non-exclusive, and royalty-free right and license to use, reproduce, distribute, adapt, modify, translate, create derivative works of, publicly perform, publicly display, digitally perform, make, have made, sell, offer for sale, and import your Content, including all intellectual property rights therein. You represent, warrant, and agree that your Content does not and will not violate any third-party intellectual property, privacy, or other rights, and that you have all right, title and interest in and to your Content required to grant us the license above. We reserve the right at all times, but have no obligation, to delete or refuse to use or distribute any Content on or through the Service, including your Content. +

+

+ HabitRPG appreciates receiving your ideas, comments, suggestions and requests regarding the Service ("Unsolicited Ideas"). By submitting your Unsolicited Ideas (in any form or medium), you are transferring all your right, title and interest therein exclusively to HabitRPG. As the owner of Unsolicited Ideas, we have unrestricted rights to use, disclose and process the Unsolicited Ideas for any purpose whatsoever without any compensation to you. You also give up any claim that any use, disclosure, and/or processing by us or our licensees of your Unsolicited Ideas violates any of your rights, including moral rights, privacy rights, rights to publicity, proprietary or other rights, and rights to credit for the material or ideas set forth therein. +

+

+ DMCA Notice. We respect the intellectual property rights of third parties. We respond to notices of alleged copyright infringement according to the Digital Millennium Copyright Act (“DMCA”) at 17 U.S.C. § 512 et seq. Regardless of whether or not the we believe that we are liable for any copyright infringement for which we are provided notice, our response may include removing or disabling access to material claimed to be the subject of infringing activity and/or terminating an individual’s access to the Service, in our sole discretion and operating within the parameters of the DMCA. +

+

+ If you believe that your work has been copied in a manner that constitutes copyright infringement, please contact us at admin@habitica.com with the following information: +

+
    +
  • Your name, address, telephone number, and email address;
  • +
  • A description of the copyrighted work that you claim has been infringed;
  • +
  • A description of the allegedly infringing material and where it is located on the Service;
  • +
  • A statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agents, or the law;
  • +
  • A statement by you under penalty of perjury that your notice is accurate, that you are the copyright owner, or that the copyright holder has authorized you to act on its behalf; and
  • +
  • Your written or electronic signature attesting to the above.
  • +
+

+ If your content has been removed from the Service in response to our receipt of a DMCA Notification as outlined above, and you believe the removal was inappropriate, you may submit a DMCA Counter-Notification by contacting us using the information above with the following information: +

+
    +
  • Your name, address, telephone number, and email address;
  • +
  • A statement that you consent to the jurisdiction of Federal District Court for the judicial district in which your address is located, or if your address is outside of the United States, for any judicial district for which jurisdiction for us would be appropriate, and that you will accept service of process from the person who submitted the DMCA notification or an agent of such person;
  • +
  • A description of the material that has been removed or to which access has been disabled and the location at which the material appeared before it was removed or access to it was disabled;
  • +
  • A statement by you under penalty of perjury that you have a good faith belief that the material was removed or disabled as a result of mistake or misidentification of the material to be removed or disabled; and
  • +
  • Your written or electronic signature attesting to the above.
  • +
+ +

Software in our Service

+

+ When the Service requires or includes downloadable software ("Software"), it may update automatically on your device once a new version or features become available to you. Some platforms may let you adjust your automatic update settings. +

+

+ HabitRPG hereby grants you a non-commercial, worldwide, royalty-free, non-assignable and non-exclusive license to use the Software provided by HabitRPG as part of the Service. You may not copy, modify, distribute, sell, or lease any part of our Service or included Software unless you are explicitly allowed to do so by the GPL-3.0 license, or you have our written permission to do so with respect to those parts not covered by the open-source license. +

+

+ Third party applications may use one of the permitted logos and signifiers in order to represent their compatibility with the Service, but may not claim formal association with and/or impersonate HabitRPG or our staff without prior written consent. Third Party applications, the companies that own or provide them, and their employees and agents, are not authorized to make any promises or representations on our behalf, or change the terms of this Agreement. +

+

+ We allow for personal, non-commercial uses like fanart under Commercial Commons License CC-NC-SA 3.0 terms. +

+

+ Outside the above explicitly allowed use cases, you may not use our trademarks, service marks, trade names, logos, domain names, taglines, or trade dress without a signed written contract with us granting you a license to do so. +

+

Modifying and Termination of Service

-

HabitRPG reserves the right, in its sole discretion, to add, modify, or remove functionalities or features from the Service, and improve, change and/or update the Service. We may also suspend or terminate the Service at any time, with or without notice to you.

-

You can choose to stop using our Service at any time. We may suspend or cease providing the Service to you at any time, including if we determine in our sole discretion, that:

+

+ HabitRPG reserves the right, in its sole discretion, to add, modify, or remove functionalities or features from the Service, and improve, change and/or update the Service. We may also suspend or terminate the Service at any time, with or without notice to you. +

+

+ You can choose to stop using our Service at any time. We may suspend or cease providing the Service to you at any time, including if we determine in our sole discretion, that: +

  • You have violated any part of this Agreement, the Privacy Policy, or the Community Guidelines;
  • We have stopped offering the Service in your region; or
  • Doing so would be in the best interests of our community, the Service, or the rights of a third party.
-

If your account is terminated, you will no longer have access to it, including to any of the associated data or Content. You will not be entitled to any refunds and we will have no liability to you. We also reserve the right to terminate any other accounts you may have created, as well as access to any other HabitRPG Service (also without refunds or liability to you).

-

You understand and agree that using the Service comes with the risk that your account may be terminated or suspended at our discretion and at any time. Please keep this risk in mind and comport yourself appropriately.

+

+ If your account is terminated, you will no longer have access to it, including to any of the associated data or Content. You will not be entitled to any refunds and we will have no liability to you. We also reserve the right to terminate any other accounts you may have created, as well as access to any other HabitRPG Service (also without refunds or liability to you). + You understand and agree that using the Service comes with the risk that your account may be terminated or suspended at our discretion and at any time. Please keep this risk in mind and comport yourself appropriately. +

+

API

-

You may access your Service data via the Application Program Interface ("API"). By using API you are automatically bound by the Agreement.

+

+ You may access your Service data via the Application Program Interface ("API"). By using API you are automatically bound by the Agreement. +

+ +

Links to Third-Party Sites

+

+ The Service may contain links to other web sites (“Linked Sites”). The Linked Sites are not under our control and we are not responsible for the contents of any Linked Site, including, without limitation, any link contained in a Linked Site, or any changes or updates to a Linked Site. +

+

+ By providing these links, we do not endorse, sponsor, or recommend such sites or the materials disseminated by or services provided by them, and are not responsible for the materials, services, or other situations at or related to or from any other site. We are not responsible for webcasting or any other form of transmission received from any Linked Site. We are providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement by us of the Linked Site or any association with its operators. We reserve the right to disable links from any third-party sites to the Service. +

+

+ Please exercise discretion while using the Service. You should be aware that when you are using the Service, you could be directed to other sites that are beyond our control. There are links to other sites from the Service pages that take you outside of the Service. These other sites may send their own cookies to users, collect data, solicit personal information, or contain information that you may find inappropriate or offensive. +

+ +

Links to Third-Party Integrations

+

+ We may provide links to third-party integrations. Third-party integrations are websites or platforms that synchronize with our Service to provide you with additional functionality, tools, or services, such as delivering content based on your location. +

+

+ You acknowledge and agree that we are not responsible for the availability of such sites or resources and do not endorse and are not responsible or liable for any content, advertising, goods, services, or other materials on, available through, or provided by such sites or resources. +

+

+ We are not responsible for the privacy or other practices of such sites and cannot guarantee the security of any personal information that you provide to such sites or that such sites collect. We encourage you to review the privacy policies and terms and conditions on those linked sites. +

+

Using Our Service

-

You must follow any policies made available to you within the Service, including but not limited to the Terms of Service, Privacy Policy, and Community Guidelines. You may only use our Service as permitted by law. HabitRPG may investigate and/or suspend or terminate our Service to you at any time if we find your use of our Service violates the Terms and/or any policies.

-

Using our Service does not grant you ownership of any intellectual property rights in our Service or the content you may have access to. You may not use any copyrighted content in our Service unless you obtain permission from the content owner and/or are otherwise permitted by law. The Terms do not grant you the right to use any branding or logos used in our Service. Our Service may display some logos, trademarks, or branding materials that are not the property of HabitRPG. Such content is the sole responsibility of the entity that makes it available.

-

You may not abuse and/or misuse our Service, including but not limited to the following actions:

+

+ You must follow any policies made available to you within the Service, including but not limited to the Terms of Service, Privacy Policy, and Community Guidelines. You may only use our Service as permitted by law. HabitRPG may investigate and/or suspend or terminate our Service to you at any time if we find your use of our Service violates the Agreement, applicable law, and/or any of our policies. +

+

+ Using our Service does not grant you ownership of any intellectual property rights in our Service or the content you may have access to. You may not use any copyrighted content in our Service unless you obtain permission from the content owner and/or are otherwise permitted by law. The Agreement does not grant you the right to use any branding or logos used in our Service. Our Service may display some logos, trademarks, or branding materials that are not the property of HabitRPG. Such content is the sole property of the entity that makes it available. +

+

+ You may not abuse and/or misuse our Service, including but not limited to the following actions: +

  • Using the Service for any unlawful purposes or activities;
  • -
  • Uploading any content to the Service in violation of any applicable law, including but not limited to intellectual property laws and publicity laws;
  • +
  • Uploading any content to the Service in violation of any applicable law, including but not limited to intellectual property laws, privacy laws, and publicity laws;
  • Sending unsolicited promotions or advertisements;
  • Accessing or tampering with the Service's server systems;
  • Interfering with or disrupting the access of any user, host, or network;
  • @@ -53,53 +132,113 @@
  • Spamming chat, whether for personal or commercial purposes, by disrupting the flow of conversation with repeated postings;
  • Impersonating any person, business, or entity, including an employee of HabitRPG, or member of the Habitica moderation team, or communicating in any way that makes it appear that the communication originates from Habitica staff or HabitRPG;
  • Transmitting or communicating any content which, in the sole and exclusive discretion of HabitRPG, is deemed offensive, including language that is unlawful, harmful, threatening, abusive, harassing, defamatory, vulgar, obscene, sexually explicit, or racially, ethically, or otherwise objectionable,
  • -
  • Participating in any action which, in the sole and exclusive judgment of HabitRPG, defrauds any other user of the Game, including by scamming or social engineering; or
  • +
  • Participating in any action which, in the sole and exclusive judgment of HabitRPG, defrauds any other user of the Service, including by scamming or social engineering; or
  • Inducing or encouraging others to violate the Community Guidelines or the Agreement.
-

HabitRPG, in its sole discretion, will determine what constitutes abuse and/or misuse of our Service.

+

+ HabitRPG, in its sole discretion, will determine what constitutes abuse and/or misuse of our Service. +

+

Premium Service and Payments

-

You may choose our free Service or paid Service ("Premium") depending on your needs. We do not guarantee when, if ever, Premium features will be available in the free Service. You may upgrade from free Service to Premium at any time by any of the following methods:

+

+ You may choose our free Service or paid Service ("Premium") depending on your needs. We do not guarantee when, if ever, Premium features will be available in the free Service. You may upgrade from free Service to Premium at any time by any of the following methods: +

  • Web: Selecting the user icon in the top right corner and selecting "Subscription" from the dropdown menu,
  • Web: Clicking the green gem icon in the navigation bar at the top of the screen and following instructions to Subscribe or Buy Gems,
  • -
  • Android: Tap the menu icon in the top left corner of the main screen and select "Gems & Subscription". Follow the instructions to make a purchase.
  • -
  • iOS: Tap the menu icon in the lower right and select "Gems & Subscriptions". Follow the instructions to make a purchase.
  • +
  • Android: Tap the menu icon in the top left corner of the main screen and select “Purchase Gems” or “Subscription”. Follow the instructions to make a purchase.
  • +
  • iOS: Tap the menu icon in the lower right and select “Purchase Gems” or “Subscription”. Follow the instructions to make a purchase.
-

You will be charged the amount shown on Pricing before you can access Premium Service. All prices shown on Pricing are inclusive of any applicable sales taxes, levies, value-added taxes, or duties imposed by taxing authorities, and you are responsible for payment of all such taxes, levies, or duties. We may revise the Pricing at any time and may, from time to time, modify, amend, or supplement our fees and fee-billing methods. Such changes shall be effective upon posting on the Pricing page or elsewhere in the Service. If there is a dispute regarding payment of fees to us, we reserve the right to terminate or suspend your account at our sole discretion.

-

BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY:

-

WITHIN THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE AS SHOWN ON YOUR PAYMENT BILL, YOU CAN REQUEST A FULL REFUND BY CONTACTING US AT ADMIN@HABITICA.COM. AFTER THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE, ANY PAYMENT REFUND IS SOLELY SUBJECT TO OUR DISCRETION. THE REFUND SHALL BE YOUR SOLE AND EXCLUSIVE REMEDY.

+

+ You will be charged the amount shown on Pricing before you can access Premium Service. All prices shown on Pricing are inclusive of any applicable sales taxes, levies, value-added taxes, or duties imposed by taxing authorities, and you are responsible for payment of all such taxes, levies, or duties. We may revise the Pricing at any time and may, from time to time, modify, amend, or supplement our fees and fee-billing methods. Such changes shall be effective upon posting on the Pricing page or elsewhere in the Service. If there is a dispute regarding payment of fees to us, we reserve the right to terminate or suspend your account at our sole discretion. +

+

+ BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY: +

+

+ WITHIN THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE AS SHOWN ON YOUR PAYMENT BILL, YOU CAN REQUEST A FULL REFUND BY CONTACTING US AT ADMIN@HABITICA.COM. AFTER THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE, ANY PAYMENT REFUND IS SOLELY SUBJECT TO OUR DISCRETION. THE REFUND SHALL BE YOUR SOLE AND EXCLUSIVE REMEDY. +

FOR ANY CUSTOMER WHO PURCHASED PREMIUM IN APPLE INC.'s APP STORE ("APP STORE"), PLEASE CONTACT APPLE INC.'s SUPPORT TEAM: https://reportaproblem.apple.com. APPLE'S APP STORE DOES NOT ALLOW DEVELOPERS TO ISSUE REFUND FOR APP STORE PURCHASES MADE BY CUSTOMERS. + >https://reportaproblem.apple.com. APPLE'S APP STORE DOES NOT ALLOW DEVELOPERS TO ISSUE REFUNDS FOR APP STORE PURCHASES MADE BY CUSTOMERS.

-

Warranty Disclaimer

-

THE SERVICE AND ANY CONTENT MADE AVAILABLE BY HABITRPG VIA THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT ANY WARRANTIES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, THAT THE SERVICE OR CONTENT WILL OPERATE ERROR-FREE OR THAT THE SERVICE OR CONTENT OR ITS SERVERS ARE FREE OF COMPUTER VIRUSES OR SIMILAR CONTAMINATION OR DESTRUCTIVE FEATURES.

-

WE DISCLAIM ALL WARRANTIES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, MERCHANTABILITY, NON-INFRINGEMENT OF THIRD PARTIES' RIGHTS, AND FITNESS FOR PARTICULAR PURPOSE AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE.

-

WE RESERVE THE RIGHT TO MAKE CHANGES, CORRECTIONS, AND/OR IMPROVEMENTS TO THE SERVICE OR THE CONTENT AT ANY TIME WITHOUT NOTICE.

-

IN CONNECTION WITH ANY WARRANTY, CONTRACT, OR COMMON LAW TORT CLAIMS: (I) WE AND OUR LICENSORS SHALL NOT BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST PROFITS, OR DAMAGES RESULTING FROM LOST DATA OR BUSINESS INTERRUPTION RESULTING FROM THE USE OR INABILITY TO ACCESS AND USE THE SERVICE OR CONTENT POSTED BY HABITPRG, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; AND (II) ANY DIRECT DAMAGES THAT YOU MAY SUFFER AS A RESULT OF YOUR USE OF THE PLATFORM SHALL BE LIMITED TO THE GREATER OF (I) MONIES YOU HAVE PAID US IN CONNECTION WITH YOUR USE OF THE PLATFORM DURING THE TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE EVENTS GIVING RISE TO THE CLAIM, OR (II) ONE HUNDRED US DOLLARS ($100).

-

SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES. THEREFORE, SOME OF THE ABOVE LIMITATIONS ON WARRANTIES IN THIS SECTION MAY NOT APPLY TO YOU. NOTHING IN THIS AGREEMENT SHALL AFFECT ANY NON-WAIVABLE STATUTORY RIGHTS THAT APPLY TO YOU.

+ +

Warranty Disclaimer and Limitation on Liability

+

+ THE SERVICE AND ANY CONTENT MADE AVAILABLE BY HABITRPG VIA THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT ANY WARRANTIES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, THAT THE SERVICE OR CONTENT WILL OPERATE ERROR-FREE OR THAT THE SERVICE OR CONTENT OR ITS SERVERS ARE FREE OF COMPUTER VIRUSES OR SIMILAR CONTAMINATION OR DESTRUCTIVE FEATURES. +

+

+ WE DISCLAIM ALL WARRANTIES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, MERCHANTABILITY, NON-INFRINGEMENT OF THIRD PARTIES' RIGHTS, AND FITNESS FOR PARTICULAR PURPOSE AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. +

+

+ WE RESERVE THE RIGHT TO MAKE CHANGES, CORRECTIONS, AND/OR IMPROVEMENTS TO THE SERVICE OR THE CONTENT AT ANY TIME WITHOUT NOTICE. IN CONNECTION WITH ANY WARRANTY, CONTRACT, OR COMMON LAW TORT CLAIMS: (I) WE AND OUR LICENSORS SHALL NOT BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST PROFITS, OR DAMAGES RESULTING FROM LOST DATA OR BUSINESS INTERRUPTION RESULTING FROM THE USE OR INABILITY TO ACCESS AND USE THE SERVICE OR CONTENT POSTED BY HABITRPG, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; AND (II) ANY DIRECT DAMAGES THAT YOU MAY SUFFER AS A RESULT OF YOUR USE OF THE PLATFORM SHALL BE LIMITED TO THE GREATER OF (I) MONIES YOU HAVE PAID US IN CONNECTION WITH YOUR USE OF THE PLATFORM DURING THE TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE EVENTS GIVING RISE TO THE CLAIM, OR (II) ONE HUNDRED US DOLLARS ($100). +

+

+ SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES. THEREFORE, SOME OF THE ABOVE LIMITATIONS ON WARRANTIES IN THIS SECTION MAY NOT APPLY TO YOU. NOTHING IN THIS AGREEMENT SHALL AFFECT ANY NON-WAIVABLE STATUTORY RIGHTS THAT APPLY TO YOU. +

+

Indemnification

-

You agree to defend, indemnify, and hold us and our officers, directors, employees, agents, successors, licensees, licensors, and assigns harmless from and against any damages, liabilities, losses, expenses, claims, actions, and/or demands, including, without limitation, reasonable legal and accounting fees, arising or resulting from: (i) your breach of any of your representations, warranties or other obligations under this Agreement; (ii) your use or misuse of the Service or content posted or made available by HabitRPG; and/or (iii) your violation of any third-party rights, including without limitation any copyright, trademark, property, publicity, or privacy right. We shall provide notice to you of any such claim, suit, or proceeding and shall assist you, at your expense, in defending any such claim, suit, or proceeding. We reserve the right to assume the exclusive defense and control (at your expense) of any matter that is subject to indemnification under this section. In such case, you agree to cooperate with any reasonable requests assisting our defense of such matter.

+

+ You agree to defend, indemnify, and hold us and our officers, directors, employees, agents, successors, licensees, licensors, and assigns harmless from and against any damages, liabilities, losses, expenses, claims, actions, and/or demands, including, without limitation, reasonable legal and accounting fees, arising or resulting from: (i) your breach of any of your representations, warranties or other obligations under this Agreement; (ii) your use or misuse of the Service or content posted or made available by HabitRPG; and/or (iii) your violation of any third-party rights in connection with your use of the Service, including without limitation any copyright, trademark, property, publicity, or privacy right. We shall provide notice to you of any such claim, suit, or proceeding and shall assist you, at your expense, in defending any such claim, suit, or proceeding. We reserve the right to participate in the defense (at our expense) of any matter that is subject to indemnification under this section. In such case, you agree to cooperate with any reasonable requests assisting our defense of such matter. +

+ +

Electronic Communications Privacy Act Notice (18 U.S.C. 2701-2711)

+

+ We make no guaranty of confidentiality or privacy with respect to any communication or information transmitted via the Service. We will not be liable for the privacy of the information, e-mail addresses, registration, and identification information, disk space, communications, confidential or trade-secret information, or any other content transmitted over networks accessed by the Service, or otherwise connected with your use of the Service. +

+

Compliance with Applicable Laws

-

The Service is based in the United States. We make no claims concerning whether the Service or posted content may be downloaded, viewed, or be appropriate for use outside of the United States. If you access the Service or such content from outside of the United States, you do so at your own risk. Whether inside or outside of the United States, you are solely responsible for ensuring compliance with the laws of your specific jurisdiction.

+

+ The Service is based in the United States. We make no claims concerning whether the Service or posted content may be downloaded, viewed, or be appropriate for use outside of the United States. If you access the Service or such content from outside of the United States, you do so at your own risk. Whether inside or outside of the United States, you are solely responsible for ensuring compliance with the laws of your specific jurisdiction. +

+

Binding Arbitration

- In the event of a dispute arising under or relating to this Agreement or the Service (each, a "Dispute"), such dispute will be finally and exclusively resolved by binding arbitration governed by the Federal Arbitration Act ("FAA"). Any election to arbitrate, at any time, shall be final and binding on the other party. NEITHER PARTY SHALL HAVE THE RIGHT TO LITIGATE SUCH CLAIM IN COURT OR TO HAVE A JURY TRIAL, EXCEPT EITHER PARTY MAY BRING ITS CLAIM IN ITS LOCAL SMALL CLAIMS COURT, IF PERMITTED BY THAT SMALL CLAIMS COURT RULES AND IF WITHIN SUCH COURT'S JURISDICTION. ARBITRATION IS DIFFERENT FROM COURT, AND DISCOVERY AND APPEAL RIGHTS MAY ALSO BE LIMITED IN ARBITRATION. All disputes will be resolved before a neutral arbitrator selected jointly by the parties, whose decision will be final, except for a limited right of appeal under the FAA. The arbitration shall be commenced and conducted by JAMS pursuant to its then current Comprehensive Arbitration Rules and Procedures and in accordance with the Expedited Procedures in those rules, or, where appropriate, pursuant to JAMS' Streamlined Arbitration Rules and Procedures. All applicable JAMS' rules and procedures are available at the JAMS website +

+ All disputes will be resolved before a neutral arbitrator selected jointly by the parties, whose decision will be final, except for a limited right of appeal under the FAA. The arbitration shall be commenced and conducted by JAMS pursuant to its then current Comprehensive Arbitration Rules and Procedures and in accordance with the Expedited Procedures in those rules, or, where appropriate, pursuant to JAMS' Streamlined Arbitration Rules and Procedures. All applicable JAMS rules and procedures are available at the JAMS website www.jamsadr.com. Each party will be responsible for paying any JAMS filing, administrative, and arbitrator fees in accordance with JAMS rules. Judgment on the arbitrator's award may be entered in any court having jurisdiction. This clause shall not preclude parties from seeking provisional remedies in aid of arbitration from a court of appropriate jurisdiction. The arbitration may be conducted in person, through the submission of documents, by phone, or online. If conducted in person, the arbitration shall take place in the United States county where you reside. The parties may litigate in court to compel arbitration, to stay a proceeding pending arbitration, or to confirm, modify, vacate, or enter judgment on the award entered by the arbitrator. The parties shall cooperate in good faith in the voluntary and informal exchange of all non-privileged documents and other information (including electronically stored information) relevant to the Dispute immediately after commencement of the arbitration. As set forth below, nothing in this Agreement will prevent us from seeking injunctive relief in any court of competent jurisdiction as necessary to protect our proprietary interests.

-

ANY CLAIMS, ACTIONS OR PROCEEDINGS BY YOU MUST BE COMMENCED WITHIN ONE YEAR AFTER THE EVENT THAT GAVE RISE TO YOUR CLAIM OCCURS. ALL OTHER CLAIMS YOU MAY HAVE ARE PERMANENTLY BARRED.

+

+ ANY CLAIMS, ACTIONS OR PROCEEDINGS BY YOU MUST BE COMMENCED WITHIN ONE YEAR AFTER THE EVENT THAT GAVE RISE TO YOUR CLAIM OCCURS. ALL OTHER CLAIMS YOU MAY HAVE ARE PERMANENTLY BARRED. +

+

Class Action Waiver

-

You agree that any arbitration or proceeding shall be limited to the Dispute between us and you individually. To the full extent permitted by law, (i) no arbitration or proceeding shall be joined with any other; (ii) there is no right or authority for any Dispute to be arbitrated or resolved on a class action-basis or to utilize class action procedures; and (iii) there is no right or authority for any Dispute to be brought in a purported representative capacity on behalf of the general public or any other persons. YOU AGREE THAT YOU MAY BRING CLAIMS AGAINST US ONLY IN YOUR INDIVIDUAL CAPACITY AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING.

+

+ You agree that any arbitration or proceeding shall be limited to the Dispute between us and you individually. To the full extent permitted by law, (i) no arbitration or proceeding shall be joined with any other; (ii) there is no right or authority for any Dispute to be arbitrated or resolved on a class action-basis or to utilize class action procedures; and (iii) there is no right or authority for any Dispute to be brought in a purported representative capacity on behalf of the general public or any other persons. YOU AGREE THAT YOU MAY BRING CLAIMS AGAINST US ONLY IN YOUR INDIVIDUAL CAPACITY AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. +

+ +

Jury Trial Waiver

+

+ IF FOR ANY REASON A DISPUTE OR CLAIM MAY PROCEED IN COURT RATHER THAN IN ARBITRATION, EACH PARTY TO THIS AGREEMENT IRREVOCABLY WAIVES, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, ANY RIGHT IT MAY HAVE TO A TRIAL BY JURY IN ANY LEGAL PROCEEDING DIRECTLY OR INDIRECTLY ARISING OUT OF OR RELATING TO THESE TERMS OR THE SERVICE (WHETHER BASED ON CONTRACT, TORT, OR ANY OTHER THEORY), UNLESS SUCH WAIVERS ARE UNENFORCEABLE. +

+

Equitable Relief

-

You acknowledge and agree that in the event of a breach or threatened violation of our intellectual property rights and confidential and proprietary information by you, we will suffer irreparable harm and will therefore be entitled to injunctive relief to enforce this Agreement. We may, without waiving any other remedies under this Agreement, seek from any court having jurisdiction any interim, equitable, provisional, or injunctive relief that is necessary to protect our rights and property pending the outcome of the arbitration referenced above.

+

+ You acknowledge and agree that in the event of a breach or threatened violation by you of our intellectual property rights and/or rights related to our confidential and proprietary information, we will suffer irreparable harm and will therefore be entitled to injunctive relief to enforce this Agreement. We may, without waiving any other remedies under this Agreement, seek from any court having jurisdiction any interim, equitable, provisional, or injunctive relief that is necessary to protect our rights and property pending the outcome of the arbitration referenced above. +

+

Contact Us

-

If you have any questions about the Agreement, or want to report a violation (including DMCA take-down notices relating to infringement of copyright) please contact us at admin@habitica.com.

+

+ If you have any questions about the Agreement, or want to report a violation, please contact us at admin@habitica.com. +

+

Miscellaneous

-

This Agreement and any action related thereto will be governed by the laws of the State of California without regard to its conflict of laws provisions. Our failure to act on or enforce any provision of this Agreement shall not be construed as a waiver of that provision or any other provision therein. No waiver shall be effective against us unless made in writing, and no such waiver shall be construed as a waiver in any other or subsequent instance. Except as expressly agreed by us and you in writing, this Agreement constitutes the entire agreement between you and us with respect to the subject matter, and supersedes all previous or contemporaneous agreements, whether written or oral, between the parties with respect to the subject matter. The section headings are provided merely for convenience and shall not be given any legal import. This Agreement will inure to the benefit of our successors, assigns, licensees, and sublicensees.

+
    +
  • This Agreement and any action related thereto will be governed by the laws of the State of California without regard to its conflict of laws provisions.
  • +
  • Our failure to act on or enforce any provision of this Agreement shall not be construed as a waiver of that provision or any other provision therein. No waiver shall be effective against us unless made in writing, and no such waiver shall be construed as a waiver in any other or subsequent instance.
  • +
  • Except as expressly agreed by us and you in writing, this Agreement constitutes the entire agreement between you and us with respect to the subject matter, and supersedes all previous or contemporaneous agreements, whether written or oral, between the parties with respect to the subject matter.
  • +
  • The section headings are provided merely for convenience and shall not be given any legal import. This Agreement will inure to the benefit of our successors, assigns, licensees, and sublicensees.
  • +
  • You agree that no joint venture, partnership, employment, or agency relationship exists between you and us as a result of the Agreement or your use of the Service.
  • +
  • Our performance under the Agreement is subject to existing laws and legal process, and nothing contained in the Agreement is in derogation of our right to comply with governmental, court, and law enforcement requests, or requirements relating to your use of the Service or information provided to or gathered by us with respect to such use.
  • +
  • If any part of the Agreement is determined to be invalid or unenforceable pursuant to applicable law, including, without limitation, the warranty disclaimers and liability limitations set forth above, then the invalid or unenforceable provision will be deemed superseded by a valid, enforceable provision that most closely matches the intent of the original provision and the remainder of the Agreement shall continue in effect.
  • +
  • A printed version of the Agreement and of any notice given in electronic form shall be admissible in judicial or administrative proceedings based upon or relating to the Agreement to the same extent and subject to the same conditions as other business documents and records originally generated and maintained in printed form.
  • +
diff --git a/website/client/src/components/static/termsReview.vue b/website/client/src/components/static/termsReview.vue deleted file mode 100644 index 6a67e5cb5f..0000000000 --- a/website/client/src/components/static/termsReview.vue +++ /dev/null @@ -1,244 +0,0 @@ - diff --git a/website/client/src/components/ui/toggleSwitch.vue b/website/client/src/components/ui/toggleSwitch.vue index 5f0e592707..ddf0f50294 100644 --- a/website/client/src/components/ui/toggleSwitch.vue +++ b/website/client/src/components/ui/toggleSwitch.vue @@ -26,12 +26,17 @@ :checked="isChecked" :value="value" @change="handleChange" + :disabled="disabled" >