diff --git a/package-lock.json b/package-lock.json
index a4e493203f..ba6e742da1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "habitica",
- "version": "4.134.0",
+ "version": "4.134.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1849,9 +1849,9 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
},
"aws-sdk": {
- "version": "2.619.0",
- "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.619.0.tgz",
- "integrity": "sha512-qujQf27p3mrGZGCL+C+vXCEB08AMm6gS1572fgHrVLBXfy6SjhV4dzEYtt+ZptQm+8z0zuHsDqghJuBCcdpxqQ==",
+ "version": "2.624.0",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.624.0.tgz",
+ "integrity": "sha512-6MhbdND7A5lEBiNSZ/HLwhKgrysmwTy6C47H7vfuVnY25hDkIND3C0PLqeRyskUqxv0RqsiAB4kqiMtpE08IGA==",
"requires": {
"buffer": "4.9.1",
"events": "1.1.1",
@@ -3962,6 +3962,11 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
+ "denque": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
+ "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
+ },
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -9132,6 +9137,7 @@
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
"integrity": "sha512-juqt5/Z42J4DcE7tG7UdVaTKmUC6zinF4yioPfpeOSNBieWSK6qCY+0tfGQcHLKrauWPDdMZVROHJOa8q2pWsA==",
+ "dev": true,
"requires": {
"bson": "^1.1.1",
"require_optional": "^1.0.1",
@@ -9140,13 +9146,13 @@
}
},
"mongoose": {
- "version": "5.8.11",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.8.11.tgz",
- "integrity": "sha512-Yz0leNEJsAtNtMTxTDEadacLWt58gaVeBVL3c1Z3vaBoc159aJqlf+T8jaL9mAdBxKndF5YWhh6Q719xac7cjA==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.2.tgz",
+ "integrity": "sha512-Sa1qfqBvUfAgsrXpZjbBoIx8PEDUJSKF5Ous8gnBFI7TPiueSgJjg6GRA7A0teU8AB/vd0h8rl1rD5RQNfWhIw==",
"requires": {
"bson": "~1.1.1",
"kareem": "2.3.1",
- "mongodb": "3.4.1",
+ "mongodb": "3.5.3",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.6.0",
"mquery": "3.2.2",
@@ -9155,6 +9161,30 @@
"safe-buffer": "5.1.2",
"sift": "7.0.1",
"sliced": "1.0.1"
+ },
+ "dependencies": {
+ "bl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
+ "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "mongodb": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.3.tgz",
+ "integrity": "sha512-II7P7A3XUdPiXRgcN96qIoRa1oesM6qLNZkzfPluNZjVkgQk3jnQwOT6/uDk4USRDTTLjNFw2vwfmbRGTA7msg==",
+ "requires": {
+ "bl": "^2.2.0",
+ "bson": "^1.1.1",
+ "denque": "^1.4.1",
+ "require_optional": "^1.0.1",
+ "safe-buffer": "^5.1.2",
+ "saslprep": "^1.0.0"
+ }
+ }
}
},
"mongoose-legacy-pluralize": {
@@ -11560,9 +11590,9 @@
}
},
"sinon-chai": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.4.0.tgz",
- "integrity": "sha512-BpVxsjEkGi6XPbDXrgWUe7Cb1ZzIfxKUbu/MmH5RoUnS7AXpKo3aIYIyQUg0FMvlUL05aPt7VZuAdaeQhEnWxg==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz",
+ "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==",
"dev": true
},
"sinon-stub-promise": {
@@ -12204,9 +12234,9 @@
"integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls="
},
"superagent": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.2.1.tgz",
- "integrity": "sha512-46b4Lkwnlz7Ebdv2FBbfuqb3kVkG1jV/SK3EW6NnwL9a3T4h5hHtegNEQfbXvTFbDoUZXId4W3dMgap2f6ic1g==",
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.2.2.tgz",
+ "integrity": "sha512-pMWBUnIllK4ZTw7p/UaobiQPwAO5w/1NRRTDpV0FTVNmECztsxKspj3ZWEordVEaqpZtmOQJJna4yTLyC/q7PQ==",
"requires": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.2",
@@ -12237,9 +12267,9 @@
"integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA=="
},
"readable-stream": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
- "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
diff --git a/package.json b/package.json
index c71a8ad898..ae790537f7 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
- "version": "4.134.0",
+ "version": "4.134.2",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.8.4",
@@ -14,7 +14,7 @@
"amplitude": "^3.5.0",
"apidoc": "^0.17.5",
"apn": "^2.2.0",
- "aws-sdk": "^2.619.0",
+ "aws-sdk": "^2.624.0",
"bcrypt": "^3.0.8",
"body-parser": "^1.18.3",
"compression": "^1.7.4",
@@ -46,7 +46,7 @@
"method-override": "^3.0.0",
"moment": "^2.24.0",
"moment-recur": "^1.0.7",
- "mongoose": "^5.8.11",
+ "mongoose": "^5.9.2",
"morgan": "^1.7.0",
"nconf": "^0.10.0",
"node-gcm": "^1.0.2",
@@ -63,7 +63,7 @@
"rimraf": "^3.0.2",
"short-uuid": "^3.0.0",
"stripe": "^7.15.0",
- "superagent": "^5.2.1",
+ "superagent": "^5.2.2",
"universal-analytics": "^0.4.17",
"useragent": "^2.1.9",
"uuid": "^3.4.0",
@@ -113,7 +113,7 @@
"monk": "^7.1.2",
"require-again": "^2.0.0",
"sinon": "^7.2.4",
- "sinon-chai": "^3.4.0",
+ "sinon-chai": "^3.5.0",
"sinon-stub-promise": "^4.0.0"
},
"optionalDependencies": {}
diff --git a/website/client/package-lock.json b/website/client/package-lock.json
index feae651180..f43795c3f7 100644
--- a/website/client/package-lock.json
+++ b/website/client/package-lock.json
@@ -7814,9 +7814,9 @@
"integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA=="
},
"bootstrap-vue": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.4.2.tgz",
- "integrity": "sha512-gtf0QwbtVyNrnXhL3eyrSrcW0/CVilEkOFddYaVAsJCIFMhUjurmzryw+Dh+fOzJmmKRqRxhkLUIGqlkwAcsbg==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.5.0.tgz",
+ "integrity": "sha512-LixZePxJqIkwsha2WAjAu7ZDH+oJ+JLxPGsl1SIbWebcEYZ+QtGx4JM2nR287t/0uWYGO+/oJ0KlaSO662VtLA==",
"requires": {
"@nuxt/opencollective": "^0.3.0",
"bootstrap": ">=4.4.1 <5.0.0",
@@ -10556,9 +10556,9 @@
}
},
"eslint-plugin-vue": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-6.2.0.tgz",
- "integrity": "sha512-6AnZKycVWbwQtL/RyX77Rytm9r16bfYsd5oy65eoSkNFzWQ5qAisdmqUG08v1InTmAh6mbR24X1HMEvoI24wGQ==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-6.2.1.tgz",
+ "integrity": "sha512-MiIDOotoWseIfLIfGeDzF6sDvHkVvGd2JgkvjyHtN3q4RoxdAXrAMuI3SXTOKatljgacKwpNAYShmcKZa4yZzw==",
"requires": {
"natural-compare": "^1.4.0",
"semver": "^5.6.0",
@@ -11253,9 +11253,9 @@
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fp-ts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.4.2.tgz",
- "integrity": "sha512-/6dNmbu2CRhwR+/OpjLYT3OAlIlyrnY1qjbGDeyYkisTqQfbIdWL1P4sn28yKhcBLcfIvjo9614sfo0EKscOMA=="
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.5.1.tgz",
+ "integrity": "sha512-IjePHUJwegS9h7+cRCywoL/Nfha3UnMd3VHVg4gycv69nAQPOJ3b/XnjtF5ggTBF4gjLZcNaHjZEYOsRcDeGaA=="
},
"fragment-cache": {
"version": "0.2.1",
@@ -12819,9 +12819,9 @@
}
},
"inspectpack": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/inspectpack/-/inspectpack-4.3.1.tgz",
- "integrity": "sha512-EF8MsrIxEmjG6uuo3bKIAzAaRDp1vq+gLG9oZ+D50kaQJnQOwwJp2MPvBk6GslUkIO64u524LwbzRv0AYd0qBQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/inspectpack/-/inspectpack-4.4.0.tgz",
+ "integrity": "sha512-V9vjuP5OqAk3jnCZ0M9TIhZlRNdd9v1fggwAHHOTYvxqFRkAtEbjj1dII6kpj6tN8+yHKBL5u9gf9Lp7GGOLHw==",
"requires": {
"chalk": "^3.0.0",
"fp-ts": "^2.3.1",
@@ -13126,9 +13126,9 @@
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"io-ts": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.0.6.tgz",
- "integrity": "sha512-WNfGzm4csMVwL4hX6QlpQWu65SV6GmOUtDo259GKlLYH1cC5bpOENgYHqQIRJ9uR3FuU1RQKDke5STwHZAn3KA=="
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.1.1.tgz",
+ "integrity": "sha512-6mDCiTc/0uNtC8M1u/kcNiw5JUTlREFCGV7pjcbrQrUDguLkOpuzb4wbJcU78G74QvkhQdvT3F3dAupycXN95g=="
},
"io-ts-reporters": {
"version": "1.0.0",
@@ -19049,36 +19049,13 @@
}
},
"svg-inline-loader": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/svg-inline-loader/-/svg-inline-loader-0.8.0.tgz",
- "integrity": "sha512-rynplY2eXFrdNomL1FvyTFQlP+dx0WqbzHglmNtA9M4IHRC3no2aPAl3ny9lUpJzFzFMZfWRK5YIclNU+FRePA==",
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/svg-inline-loader/-/svg-inline-loader-0.8.2.tgz",
+ "integrity": "sha512-kbrcEh5n5JkypaSC152eGfGcnT4lkR0eSfvefaUJkLqgGjRQJyKDvvEE/CCv5aTSdfXuc+N98w16iAojhShI3g==",
"requires": {
- "loader-utils": "^0.2.11",
+ "loader-utils": "^1.1.0",
"object-assign": "^4.0.1",
"simple-html-tokenizer": "^0.1.1"
- },
- "dependencies": {
- "big.js": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
- "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
- },
- "json5": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
- "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
- },
- "loader-utils": {
- "version": "0.2.17",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
- "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
- "requires": {
- "big.js": "^3.1.3",
- "emojis-list": "^2.0.0",
- "json5": "^0.5.0",
- "object-assign": "^4.0.1"
- }
- }
}
},
"svg-tags": {
diff --git a/website/client/package.json b/website/client/package.json
index 51b414f325..272d968afb 100644
--- a/website/client/package.json
+++ b/website/client/package.json
@@ -29,16 +29,16 @@
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.0.1",
"bootstrap": "^4.4.1",
- "bootstrap-vue": "^2.4.2",
+ "bootstrap-vue": "^2.5.0",
"chai": "^4.1.2",
"core-js": "^3.6.4",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
"eslint-plugin-mocha": "^5.3.0",
- "eslint-plugin-vue": "^6.2.0",
+ "eslint-plugin-vue": "^6.2.1",
"habitica-markdown": "^1.3.2",
"hellojs": "^1.18.4",
- "inspectpack": "^4.3.1",
+ "inspectpack": "^4.4.0",
"intro.js": "^2.9.3",
"jquery": "^3.4.1",
"lodash": "^4.17.15",
@@ -47,7 +47,7 @@
"sass": "^1.25.0",
"sass-loader": "^8.0.2",
"smartbanner.js": "^1.15.0",
- "svg-inline-loader": "^0.8.0",
+ "svg-inline-loader": "^0.8.2",
"svg-url-loader": "^3.0.3",
"svgo": "^1.3.2",
"svgo-loader": "^2.2.1",
diff --git a/website/client/src/assets/css/sprites/spritesmith-largeSprites-0.css b/website/client/src/assets/css/sprites/spritesmith-largeSprites-0.css
index 883b955aa3..dc4bfe8272 100644
--- a/website/client/src/assets/css/sprites/spritesmith-largeSprites-0.css
+++ b/website/client/src/assets/css/sprites/spritesmith-largeSprites-0.css
@@ -1,42 +1,42 @@
.promo_achievement_CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: -328px -148px;
+ background-position: -668px -444px;
width: 204px;
height: 102px;
}
.promo_armoire_backgrounds_202002 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: -328px 0px;
+ background-position: 0px -277px;
width: 423px;
height: 147px;
}
.promo_mystery_022020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: 0px -425px;
+ background-position: -668px -148px;
width: 282px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: -283px -425px;
+ background-position: -873px -444px;
width: 96px;
height: 69px;
}
.promo_valentines_2020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: -421px -277px;
+ background-position: -668px 0px;
width: 309px;
height: 147px;
}
.promo_valentines_potions {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: 0px -277px;
+ background-position: 0px -425px;
width: 420px;
height: 147px;
}
.scene_cake {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
- background-position: -533px -148px;
+ background-position: -424px -277px;
width: 204px;
height: 102px;
}
@@ -46,3 +46,15 @@
width: 327px;
height: 276px;
}
+.scene_gaining_achievement {
+ background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
+ background-position: -328px 0px;
+ width: 339px;
+ height: 210px;
+}
+.scene_shanaqui {
+ background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
+ background-position: -668px -296px;
+ width: 282px;
+ height: 147px;
+}
diff --git a/website/client/src/assets/images/g1g1-notif.png b/website/client/src/assets/images/g1g1-notif.png
index 398b4861f3..75633e6db2 100644
Binary files a/website/client/src/assets/images/g1g1-notif.png and b/website/client/src/assets/images/g1g1-notif.png differ
diff --git a/website/client/src/assets/images/g1g1-send.png b/website/client/src/assets/images/g1g1-send.png
index b92b753402..774be0b37a 100644
Binary files a/website/client/src/assets/images/g1g1-send.png and b/website/client/src/assets/images/g1g1-send.png differ
diff --git a/website/client/src/assets/images/sprites/spritesmith-largeSprites-0.png b/website/client/src/assets/images/sprites/spritesmith-largeSprites-0.png
index d96a792b6d..d0cff3807a 100644
Binary files a/website/client/src/assets/images/sprites/spritesmith-largeSprites-0.png and b/website/client/src/assets/images/sprites/spritesmith-largeSprites-0.png differ
diff --git a/website/client/src/components/header/notifications/g1g1.vue b/website/client/src/components/header/notifications/g1g1.vue
index 8149f0aac1..f49feca7fd 100644
--- a/website/client/src/components/header/notifications/g1g1.vue
+++ b/website/client/src/components/header/notifications/g1g1.vue
@@ -2,19 +2,38 @@
-
{{ $t('g1g1Announcement') }}
-
{{ $t('g1g1Details') }}
+
+ {{ $t('g1g1Announcement') }}
+
+
+ {{ $t('g1g1Details') }}
+
-
{{ $t('sendGift') }}
+
+ {{ $t('sendGift') }}
+
diff --git a/website/client/src/components/payments/selectUserModal.vue b/website/client/src/components/payments/selectUserModal.vue
index 77f76a6e8d..70f8407601 100644
--- a/website/client/src/components/payments/selectUserModal.vue
+++ b/website/client/src/components/payments/selectUserModal.vue
@@ -173,7 +173,6 @@ export default {
methods: {
close () {
this.$root.$emit('habitica::dismiss-modal', 'select-user-modal');
- this.$root.$emit('bv::hide::modal', 'select-user-modal');
},
searchUser: debounce(async function userSearch (searchTerm) {
this.foundUser = {};
diff --git a/website/client/src/components/payments/successModal.vue b/website/client/src/components/payments/successModal.vue
index 8d33203d8d..965eddecb8 100644
--- a/website/client/src/components/payments/successModal.vue
+++ b/website/client/src/components/payments/successModal.vue
@@ -245,7 +245,6 @@ export default {
close () {
this.paymentData = {};
this.$root.$emit('habitica::dismiss-modal', 'payments-success-modal');
- this.$root.$emit('bv::hide::modal', 'payments-success-modal');
},
},
};
diff --git a/website/client/src/components/shops/quests/index.vue b/website/client/src/components/shops/quests/index.vue
index 0612d29869..0dc12f46dc 100644
--- a/website/client/src/components/shops/quests/index.vue
+++ b/website/client/src/components/shops/quests/index.vue
@@ -209,7 +209,6 @@
diff --git a/website/client/src/store/actions/shops.js b/website/client/src/store/actions/shops.js
index fea30216b8..52c2aea350 100644
--- a/website/client/src/store/actions/shops.js
+++ b/website/client/src/store/actions/shops.js
@@ -78,9 +78,8 @@ async function buyArmoire (store, params) {
// @TODO: We might need to abstract notifications to library rather than mixin
const notificationOptions = isExperience
? {
- text: `+ ${item.value}`,
- type: 'xp',
- flavorMessage: message,
+ text: message,
+ type: 'success',
}
: {
text: message,
@@ -93,6 +92,10 @@ async function buyArmoire (store, params) {
timeout: true,
...notificationOptions,
});
+
+ if (isExperience) {
+ await store.dispatch('user:fetch', { forceLoad: true });
+ }
}
}
diff --git a/website/common/script/content/quests.js b/website/common/script/content/quests.js
index 425c1656dd..0e552c87a9 100644
--- a/website/common/script/content/quests.js
+++ b/website/common/script/content/quests.js
@@ -1067,7 +1067,7 @@ const quests = {
notes: t('questBasilistNotes'),
group: 'questGroupEarnable',
completion: t('questBasilistCompletion'),
- value: 4,
+ goldValue: 100,
category: 'unlockable',
unlockCondition: {
condition: 'party invite',
@@ -2238,7 +2238,7 @@ const quests = {
notes: t('questDustBunniesNotes'),
group: 'questGroupEarnable',
completion: t('questDustBunniesCompletion'),
- value: 4,
+ value: 1,
category: 'unlockable',
unlockCondition: {
condition: 'party invite',
@@ -2262,7 +2262,7 @@ const quests = {
value: 4,
category: 'unlockable',
unlockCondition: {
- condition: 'party invite',
+ condition: 'login reward',
incentiveThreshold: 7,
text: t('loginReward', { count: 7 }),
},
@@ -2293,7 +2293,7 @@ const quests = {
value: 4,
category: 'unlockable',
unlockCondition: {
- condition: 'party invite',
+ condition: 'login reward',
incentiveThreshold: 22,
text: t('loginReward', { count: 22 }),
},
@@ -2323,7 +2323,7 @@ const quests = {
value: 4,
category: 'unlockable',
unlockCondition: {
- condition: 'party invite',
+ condition: 'login reward',
incentiveThreshold: 40,
text: t('loginReward', { count: 40 }),
},
diff --git a/website/common/script/ops/buy/buyArmoire.js b/website/common/script/ops/buy/buyArmoire.js
index fab02460d7..9a7f91e200 100644
--- a/website/common/script/ops/buy/buyArmoire.js
+++ b/website/common/script/ops/buy/buyArmoire.js
@@ -10,6 +10,7 @@ import {
import randomVal, * as randomValFns from '../../libs/randomVal';
import { removeItemByPath } from '../pinnedGearUtils';
import { AbstractGoldItemOperation } from './abstractBuyOperation';
+import updateStats from '../../fns/updateStats';
// TODO this is only used on the server
// move out of common?
@@ -156,6 +157,7 @@ export class BuyArmoireOperation extends AbstractGoldItemOperation { // eslint-d
_experienceResult (user) {
const armoireExp = Math.floor(randomValFns.trueRandom() * 40 + 10);
user.stats.exp += armoireExp;
+ updateStats(user, user.stats, this.req);
return {
message: this.i18n('armoireExp'),
diff --git a/website/common/script/ops/buy/buyQuestGold.js b/website/common/script/ops/buy/buyQuestGold.js
index a4f16d4bfd..10a0cfadcb 100644
--- a/website/common/script/ops/buy/buyQuestGold.js
+++ b/website/common/script/ops/buy/buyQuestGold.js
@@ -42,7 +42,7 @@ export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation { // es
if (!item) throw new NotFound(errorMessage('questNotFound', { key }));
- if (!(item.category === 'gold' && item.goldValue)) {
+ if (!(item.goldValue)) {
throw new NotAuthorized(this.i18n('questNotGoldPurchasable', { key }));
}
diff --git a/website/raw_sprites/spritesmith_large/scene_gaining_achievement.png b/website/raw_sprites/spritesmith_large/scene_gaining_achievement.png
new file mode 100644
index 0000000000..0c900350ca
Binary files /dev/null and b/website/raw_sprites/spritesmith_large/scene_gaining_achievement.png differ
diff --git a/website/raw_sprites/spritesmith_large/scene_shanaqui.png b/website/raw_sprites/spritesmith_large/scene_shanaqui.png
new file mode 100644
index 0000000000..fe9d7035dc
Binary files /dev/null and b/website/raw_sprites/spritesmith_large/scene_shanaqui.png differ
diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js
index 745afb0750..9d1befafb8 100644
--- a/website/server/controllers/api-v3/auth.js
+++ b/website/server/controllers/api-v3/auth.js
@@ -29,7 +29,7 @@ const api = {};
/**
* @api {post} /api/v3/user/auth/local/register Register
* @apiDescription Register a new user with email, login name, and password or
- * attach local auth to a social user
+ * attach local authentication to a social auth user
* @apiName UserRegisterLocal
* @apiGroup User
*
@@ -148,12 +148,14 @@ api.loginSocial = {
/**
* @api {put} /api/v3/user/auth/update-username Update username
- * @apiDescription Update the username of a local user
+ * @apiDescription Update and verify the user's username
* @apiName UpdateUsername
* @apiGroup User
*
* @apiParam (Body) {String} username The new username
-
+ * @apiParam (Body) {String} password The user's password if they use local authentication.
+ * Omit if they use social auth.
+ *
* @apiSuccess {String} data.username The new username
* */
api.updateUsername = {
@@ -196,6 +198,8 @@ api.updateUsername = {
// save username
user.auth.local.lowerCaseUsername = newUsername.toLowerCase();
user.auth.local.username = newUsername;
+
+ // reward user for verifying their username
if (!user.flags.verifiedUsername) {
user.flags.verifiedUsername = true;
if (user.items.pets['Bear-Veteran']) {
@@ -277,7 +281,7 @@ api.updatePassword = {
};
/**
- * @api {post} /api/v3/user/reset-password Reset password
+ * @api {post} /api/v3/user/reset-password Reset password (email a reset link)
* @apiDescription Send the user an email to let them reset their password
* @apiName ResetPassword
* @apiGroup User
@@ -371,7 +375,7 @@ api.updateEmail = {
};
/**
- * @api {post} /api/v3/user/auth/reset-password-set-new-one Reset Password Set New one
+ * @api {post} /api/v3/user/auth/reset-password-set-new-one Reset password (set a new one)
* @apiDescription Set a new password for a user that reset theirs. Not meant for public usage.
* @apiName ResetPasswordSetNewOne
* @apiGroup User
@@ -424,8 +428,8 @@ api.resetPasswordSetNewOne = {
/**
* @api {delete} /api/v3/user/auth/social/:network Delete social authentication method
- * @apiDescription Remove a social authentication method (only facebook supported)
- * from a user profile. The user must have local authentication enabled
+ * @apiDescription Remove a social authentication method from a user profile.
+ * The user must have another authentication method enabled.
* @apiName UserDeleteSocial
* @apiGroup User
*
diff --git a/website/server/controllers/api-v3/challenges.js b/website/server/controllers/api-v3/challenges.js
index 00e283add7..a68e08ffa3 100644
--- a/website/server/controllers/api-v3/challenges.js
+++ b/website/server/controllers/api-v3/challenges.js
@@ -513,7 +513,7 @@ api.getGroupChallenges = {
};
/**
- * @api {get} /api/v3/challenges/:challengeId Get a challenge given its id
+ * @api {get} /api/v3/challenges/:challengeId Get a challenge
* @apiName GetChallenge
* @apiGroup Challenge
*
diff --git a/website/server/controllers/api-v3/cron.js b/website/server/controllers/api-v3/cron.js
index 0016650bcf..bea3e41201 100644
--- a/website/server/controllers/api-v3/cron.js
+++ b/website/server/controllers/api-v3/cron.js
@@ -4,8 +4,11 @@ import cron from '../../middlewares/cron';
const api = {};
/**
- * @api {post} /api/v3/cron Runs cron
+ * @api {post} /api/v3/cron Run cron
* @apiName Cron
+ * @apiDescription This causes cron to run. It assumes that the user has already been shown
+ * the Record Yesterday's Activity ("Check off any Dailies you did yesterday") screen and
+ * so it will immediately apply damage for incomplete due Dailies.
* @apiGroup Cron
*
* @apiSuccess {Object} data An empty Object
diff --git a/website/server/controllers/api-v3/hall.js b/website/server/controllers/api-v3/hall.js
index 8e28fbc17a..81b6c97999 100644
--- a/website/server/controllers/api-v3/hall.js
+++ b/website/server/controllers/api-v3/hall.js
@@ -93,7 +93,7 @@ api.getPatrons = {
};
/**
- * @api {get} /api/v3/hall/heroes Get all Heroes
+ * @api {get} /api/v3/hall/heroes Get all Heroes (contributors)
* @apiName GetHeroes
* @apiGroup Hall
*
@@ -154,7 +154,7 @@ const heroAdminFields = 'contributor balance profile.name purchased items auth f
* @apiGroup Hall
* @apiPermission Admin
*
- * @apiDescription Returns the profile of the given user
+ * @apiDescription Returns the profile of the given user. User does not need to be a contributor.
*
* @apiSuccess {Object} data The user object
*
@@ -208,9 +208,9 @@ const gemsPerTier = {
* @apiGroup Hall
* @apiPermission Admin
*
- * @apiDescription Update user's gem balance, contributions & contribution tier
- * and admin status. Grant items, block / unblock user's account
- * and revoke / unrevoke chat privileges.
+ * @apiDescription Update user's gem balance, contributions and contribution tier,
+ * or admin status. Grant items. Block / unblock user's account.
+ * Revoke / unrevoke chat privileges.
*
* @apiExample Example Body:
* {
diff --git a/website/server/controllers/api-v3/members.js b/website/server/controllers/api-v3/members.js
index 126546d4f4..e7d3e0dfe9 100644
--- a/website/server/controllers/api-v3/members.js
+++ b/website/server/controllers/api-v3/members.js
@@ -658,8 +658,8 @@ api.getObjectionsToInteraction = {
* @apiName SendPrivateMessage
* @apiGroup Member
*
- * @apiParam (Body) {String} message Body parameter - The message
- * @apiParam (Body) {UUID} toUserId Body parameter - The user to contact
+ * @apiParam (Body) {String} message The message
+ * @apiParam (Body) {UUID} toUserId The id of the user to contact
*
* @apiSuccess {Object} data.message The message just sent
*
@@ -698,7 +698,7 @@ api.sendPrivateMessage = {
* @apiGroup Member
*
* @apiParam (Body) {String} message The message to the user
- * @apiParam (Body) {UUID} toUserId The toUser _id
+ * @apiParam (Body) {UUID} toUserId The user to send the gift to
* @apiParam (Body) {Integer} gemAmount The number of gems to send
*
* @apiSuccess {Object} data An empty Object
diff --git a/website/server/controllers/api-v3/news.js b/website/server/controllers/api-v3/news.js
index 863a80605b..a3fa4223f2 100644
--- a/website/server/controllers/api-v3/news.js
+++ b/website/server/controllers/api-v3/news.js
@@ -4,7 +4,7 @@ const api = {};
// @TODO export this const, cannot export it from here because only routes are exported from
// controllers
-const LAST_ANNOUNCEMENT_TITLE = 'NEW PET COLLECTION BADGES!';
+const LAST_ANNOUNCEMENT_TITLE = 'BLOG POSTS: PARTY PARTICIPATION AND OUR FAVO(U)RITE GUILDS!';
const worldDmg = { // @TODO
bailey: false,
};
@@ -31,23 +31,43 @@ api.getNews = {
${res.t('newStuff')}
- 2/18/2020 - ${LAST_ANNOUNCEMENT_TITLE}
+ 2/20/2020 - ${LAST_ANNOUNCEMENT_TITLE}
-
+
+ Use Case Spotlight: Party Participation
- We're releasing a new achievement so you can celebrate your successes in the world of
- Habitican pet collecting! Earn the Tickled Pink and Rosy Outlook achievements by
- collecting Cotton Candy Pink pets and mounts and you'll earn a nifty badge for your
- profile.
+ This month's Use Case Spotlight is about Party Participation! It features a number
+ of great suggestions submitted by Habiticans in the Use Case Spotlights Guild.
+ We hope it helps any of you who might be looking for ways to keep your quest party
+ engaged and excited to win battles with good habits.
- If you already have all the Cotton Candy Pink pets and/or mounts in your stable, you'll
- receive the badge automatically! Check your profile and celebrate your new achievement
- with pride in your pink prowess.
+ Plus, we're collecting user submissions for the next spotlight! How do you use Habitica
+ to manage conflicting needs, like productivity versus self-care? We’ll be featuring
+ player-submitted examples in Use Case Spotlights on the Habitica Blog next month, so post
+ your suggestions in the Use Case Spotlight Guild now. We look forward to learning more
+ about how you use Habitica to improve your life and get things done!
- by Piyowo and SabreCat
+ by shanaqui
+
+ Guild Spotlight: Shanaqui's Favourites
+
+ For this year's Guild Spotlight series, we're highlighting some favourites from
+ Habitica's staff, moderators, and maybe some high-level contributors!
+
+
+ This month we're kicking things off with some picks from shanaqui! If you want to curate your Habitica experience
+ and join active, positive Guilds, this is a great way to pick up some new ideas for
+ Guilds to join.
+
+ by shanaqui
`,
});
@@ -55,8 +75,10 @@ api.getNews = {
};
/**
- * @api {post} /api/v3/news/tell-me-later Get latest Bailey announcement in a second moment
+ * @api {post} /api/v3/news/tell-me-later Allow latest Bailey announcement to be read later
* @apiName TellMeLaterNews
+ * @apiDescription Add a notification to allow viewing of the latest "New Stuff by Bailey" message.
+ * Prevent this specific Bailey message from appearing automatically.
* @apiGroup News
*
*
diff --git a/website/server/controllers/api-v3/tags.js b/website/server/controllers/api-v3/tags.js
index 6c2ab2e268..0da234f1df 100644
--- a/website/server/controllers/api-v3/tags.js
+++ b/website/server/controllers/api-v3/tags.js
@@ -78,7 +78,7 @@ api.getTags = {
};
/**
- * @api {get} /api/v3/tags/:tagId Get a tag given its id
+ * @api {get} /api/v3/tags/:tagId Get a tag
* @apiName GetTag
* @apiGroup Tag
*
@@ -199,7 +199,7 @@ api.reorderTags = {
};
/**
- * @api {delete} /api/v3/tags/:tagId Delete a user tag given its id
+ * @api {delete} /api/v3/tags/:tagId Delete a user tag
* @apiName DeleteTag
* @apiGroup Tag
*
diff --git a/website/server/controllers/api-v3/tasks.js b/website/server/controllers/api-v3/tasks.js
index 8f2488cbd6..41544680d8 100644
--- a/website/server/controllers/api-v3/tasks.js
+++ b/website/server/controllers/api-v3/tasks.js
@@ -1479,6 +1479,8 @@ api.unlinkOneTask = {
/**
* @api {post} /api/v3/tasks/clearCompletedTodos Delete user's completed todos
* @apiName ClearCompletedTodos
+ * @apiDescription Deletes all of a user's completed To-Dos except
+ * those belonging to active Challenges and Group Plans.
* @apiGroup Task
*
* @apiExample {curl} Example call:
@@ -1523,7 +1525,7 @@ api.clearCompletedTodos = {
};
/**
- * @api {delete} /api/v3/tasks/:taskId Delete a task given its id
+ * @api {delete} /api/v3/tasks/:taskId Delete a task
* @apiName DeleteTask
* @apiGroup Task
*
diff --git a/website/server/controllers/api-v3/tasks/groups.js b/website/server/controllers/api-v3/tasks/groups.js
index 5b17204bee..dfbd9c0438 100644
--- a/website/server/controllers/api-v3/tasks/groups.js
+++ b/website/server/controllers/api-v3/tasks/groups.js
@@ -178,7 +178,7 @@ api.groupMoveTask = {
* @apiParam (Path) {UUID} taskId The id of the task that will be assigned
* @apiParam (Path) {UUID} assignedUserId The id of the user that will be assigned to the task
*
- * @apiSuccess data An object if a single task was created, otherwise an array of tasks
+ * @apiSuccess data The assigned task
*/
api.assignTask = {
method: 'POST',
@@ -246,14 +246,14 @@ api.assignTask = {
/**
* @api {post} /api/v3/tasks/:taskId/unassign/:assignedUserId Unassign a user from a task
- * @apiDescription Unassigns a user to from a group task
+ * @apiDescription Unassigns a user from a group task
* @apiName UnassignTask
* @apiGroup Task
*
- * @apiParam (Path) {UUID} taskId The id of the task that will be assigned
+ * @apiParam (Path) {UUID} taskId The id of the task that is the original group task
* @apiParam (Path) {UUID} assignedUserId The id of the user that will be unassigned from the task
*
- * @apiSuccess data An object if a single task was created, otherwise an array of tasks
+ * @apiSuccess data The unassigned task
*/
api.unassignTask = {
method: 'POST',
@@ -398,8 +398,8 @@ api.approveTask = {
};
/**
- * @api {post} /api/v3/tasks/:taskId/needs-work/:userId Group task needs more work
- * @apiDescription Mark an assigned group task as needeing more work before it can be approved
+ * @api {post} /api/v3/tasks/:taskId/needs-work/:userId Require more work for a group task
+ * @apiDescription Mark an assigned group task as needing more work before it can be approved
* @apiVersion 3.0.0
* @apiName TaskNeedsWork
* @apiGroup Task
diff --git a/website/server/controllers/api-v3/user.js b/website/server/controllers/api-v3/user.js
index 18c411b018..ac45666121 100644
--- a/website/server/controllers/api-v3/user.js
+++ b/website/server/controllers/api-v3/user.js
@@ -41,28 +41,28 @@ const api = {};
* @apiGroup User
*
* @apiDescription The user profile contains data related to the authenticated
- * user including (but not limited to);
- * Achievements
- * Authentications (including types and timestamps)
- * Challenges
- * Flags (including armoire, tutorial, tour etc...)
- * Guilds
- * History (including timestamps and values)
- * Inbox
- * Invitations (to parties/guilds)
- * Items (character's full inventory)
- * New Messages (flags for groups/guilds that have new messages)
- * Notifications
- * Party (includes current quest information)
- * Preferences (user selected prefs)
- * Profile (name, photo url, blurb)
- * Purchased (includes purchase history, gem purchased items, plans)
- * PushDevices (identifiers for mobile devices authorized)
- * Stats (standard RPG stats, class, buffs, xp, etc..)
- * Tags
- * TasksOrder (list of all ids for dailys, habits, rewards and todos)
+ * user including (but not limited to):
+ * Achievements;
+ * Authentications (including types and timestamps);
+ * Challenges memberships (Challenge IDs);
+ * Flags (including armoire, tutorial, tour etc...);
+ * Guilds memberships (Guild IDs);
+ * History (including timestamps and values, only for Experience and summed To-Do values);
+ * Inbox;
+ * Invitations (to parties/guilds);
+ * Items (character's full inventory);
+ * New Messages (flags for party/guilds that have new messages; also reported in Notifications);
+ * Notifications;
+ * Party (includes current quest information);
+ * Preferences (user selected prefs);
+ * Profile (name, photo url, blurb);
+ * Purchased (includes subscription data and some gem-purchased items);
+ * PushDevices (identifiers for mobile devices authorized);
+ * Stats (standard RPG stats, class, buffs, xp, etc..);
+ * Tags;
+ * TasksOrder (list of all IDs for Dailys, Habits, Rewards and To-Dos).
*
- * @apiParam (Query) {String} [userFields] A list of comma separated user fields to
+ * @apiParam (Query) {String} [userFields] A list of comma-separated user fields to
* be returned instead of the entire document.
* Notifications are always returned.
*
@@ -92,7 +92,7 @@ api.getUser = {
/**
* @api {get} /api/v3/user/inventory/buy
- * Get the gear items available for purchase for the authenticated user
+ * Get equipment/gear items available for purchase for the authenticated user
* @apiName UserGetBuyList
* @apiGroup User
*
@@ -231,7 +231,8 @@ api.updateUser = {
* @apiName UserDelete
* @apiGroup User
*
- * @apiParam (Body) {String} password The user's password if the account uses local authentication
+ * @apiParam (Body) {String} password The user's password if the account uses local authentication,
+ * otherwise the localized word "DELETE"
* @apiParam (Body) {String} feedback User's optional feedback explaining reasons for deletion
*
* @apiSuccess {Object} data An empty Object
@@ -242,9 +243,14 @@ api.updateUser = {
* "data": {}
* }
*
- * @apiError {BadRequest} MissingPassword The password was not included in the request
- * @apiError {BadRequest} LengthExceeded The feedback provided is longer than 10K
- * @apiError {BadRequest} NotAuthorized There is no account that uses those credentials.
+ * @apiError {BadRequest} MissingPassword Missing password.
+ * @apiError {BadRequest} NotAuthorized Wrong password.
+ * @apiError {BadRequest} NotAuthorized Please type DELETE in all capital letters to
+ * delete your account.
+ * @apiError {BadRequest} BadRequest Account deletion feedback is limited to 10,000 characters.
+ * For lengthy feedback, email ${TECH_ASSISTANCE_EMAIL}.
+ * @apiError {BadRequest} NotAuthorized You have an active subscription,
+ * cancel your plan before deleting your account.
*
* @apiErrorExample {json} Example error:
* {
@@ -279,7 +285,7 @@ api.deleteUser = {
}
const { feedback } = req.body;
- if (feedback && feedback.length > 10000) throw new BadRequest(`Account deletion feedback is limited to 10,000 characters. For lengthy feedback, email ${TECH_ASSISTANCE_EMAIL}.`);
+ if (feedback && feedback.length > 10000) throw new BadRequest(`Account deletion feedback is limited to 10,000 characters. For lengthy feedback, email ${TECH_ASSISTANCE_EMAIL}.`); // @TODO localize this string
if (plan && plan.customerId && !plan.dateTerminated) {
throw new NotAuthorized(res.t('cannotDeleteActiveAccount'));
@@ -333,14 +339,14 @@ function _cleanChecklist (task) {
* @apiGroup User
*
* @apiDescription Returns the user's data without:
- * Authentication information
- * NewMessages/Invitations/Inbox
- * Profile
- * Purchased information
- * Contributor information
- * Special items
- * Webhooks
- * Notifications
+ * Authentication information,
+ * NewMessages/Invitations/Inbox,
+ * Profile,
+ * Purchased information,
+ * Contributor information,
+ * Special items,
+ * Webhooks,
+ * Notifications.
*
* @apiSuccess {Object} data.user
* @apiSuccess {Object} data.tasks
@@ -537,7 +543,7 @@ api.buyGear = {
};
/**
- * @api {post} /api/v3/user/buy-armoire Buy an armoire item
+ * @api {post} /api/v3/user/buy-armoire Buy an Enchanted Armoire item
* @apiName UserBuyArmoire
* @apiGroup User
*
@@ -619,8 +625,9 @@ api.buyHealthPotion = {
};
/**
- * @api {post} /api/v3/user/buy-mystery-set/:key Buy a mystery set
+ * @api {post} /api/v3/user/buy-mystery-set/:key Buy a Mystery Item set
* @apiName UserBuyMysterySet
+ * @apiDescription This buys a Mystery Item set using an Hourglass.
* @apiGroup User
*
* @apiParam (Path) {String} key The mystery set to buy
@@ -703,7 +710,7 @@ api.buyQuest = {
};
/**
- * @api {post} /api/v3/user/buy-special-spell/:key Buy special "spell" item
+ * @api {post} /api/v3/user/buy-special-spell/:key Buy special item (card, avatar transformation)
* @apiDescription Includes gift cards (e.g., birthday card), and avatar Transformation
* Items and their antidotes (e.g., Snowball item and Salt reward).
* @apiName UserBuySpecialSpell
@@ -1003,6 +1010,8 @@ api.purchase = {
/**
* @api {post} /api/v3/user/purchase-hourglass/:type/:key Purchase Hourglass-purchasable item
* @apiName UserPurchaseHourglass
+ * @apiDescription Purchases an Hourglass-purchasable item.
+ * Does not include Mystery Item sets (use /api/v3/user/buy-mystery-set/:key).
* @apiGroup User
*
* @apiParam (Path) {String="pets","mounts"} type The type of item to purchase
@@ -1492,7 +1501,7 @@ api.clearMessages = {
};
/**
- * @api {post} /api/v3/user/mark-pms-read Marks Private Messages as read
+ * @api {post} /api/v3/user/mark-pms-read Mark Private Messages as read
* @apiName markPmsRead
* @apiGroup User
*
@@ -1517,7 +1526,7 @@ api.markPmsRead = {
/* NOTE this route has also an API v4 version */
/**
- * @api {post} /api/v3/user/reroll Reroll a user using the Fortify Potion
+ * @api {post} /api/v3/user/reroll Reroll a user (reset tasks) using the Fortify Potion
* @apiName UserReroll
* @apiGroup User
*
@@ -1580,14 +1589,12 @@ api.userReset = {
};
/**
- * @api {post} /api/v3/user/custom-day-start
- * Set preferences.dayStart (Custom Day Start time) for user
+ * @api {post} /api/v3/user/custom-day-start Set Custom Day Start time for user.
* @apiName setCustomDayStart
* @apiGroup User
*
- *
* @apiParam (Body) {number} [dayStart=0] The hour number 0-23 for day to begin.
- * If body is not included, will default to 0.
+ * If not supplied, will default to 0.
*
* @apiParamExample {json} Request-Example:
* {"dayStart":2}
diff --git a/website/server/controllers/api-v3/user/spells.js b/website/server/controllers/api-v3/user/spells.js
index 736fdc114f..86a03a3ecd 100644
--- a/website/server/controllers/api-v3/user/spells.js
+++ b/website/server/controllers/api-v3/user/spells.js
@@ -30,29 +30,30 @@ const api = {};
* the necessary fields will be populated. The user is always returned.
*
* @apiDescription Skill Key to Name Mapping
- * Mage
- * fireball: "Burst of Flames"
- * mpheal: "Ethereal Surge"
- * earth: "Earthquake"
- * frost: "Chilling Frost"
*
- * Warrior
- * smash: "Brutal Smash"
- * defensiveStance: "Defensive Stance"
- * valorousPresence: "Valorous Presence"
- * intimidate: "Intimidating Gaze"
+ * Mage:
+ * fireball="Burst of Flames",
+ * mpheal="Ethereal Surge",
+ * earth="Earthquake",
+ * frost="Chilling Frost"
*
- * Rogue
- * pickPocket: "Pickpocket"
- * backStab: "Backstab"
- * toolsOfTrade: "Tools of the Trade"
- * stealth: "Stealth"
+ * Warrior:
+ * smash="Brutal Smash",
+ * defensiveStance="Defensive Stance",
+ * valorousPresence="Valorous Presence",
+ * intimidate="Intimidating Gaze"
*
- * Healer
- * heal: "Healing Light"
- * protectAura: "Protective Aura"
- * brightness: "Searing Brightness"
- * healAll: "Blessing"
+ * Rogue:
+ * pickPocket="Pickpocket",
+ * backStab="Backstab",
+ * toolsOfTrade="Tools of the Trade",
+ * stealth="Stealth"
+ *
+ * Healer:
+ * heal="Healing Light",
+ * protectAura="Protective Aura",
+ * brightness="Searing Brightness",
+ * healAll="Blessing"
*
* @apiError (400) {NotAuthorized} Not enough mana.
* @apiUse TaskNotFound
diff --git a/website/server/controllers/api-v3/user/stats.js b/website/server/controllers/api-v3/user/stats.js
index 5da2c442f0..3cb24248b0 100644
--- a/website/server/controllers/api-v3/user/stats.js
+++ b/website/server/controllers/api-v3/user/stats.js
@@ -9,6 +9,7 @@ const api = {};
* Allocate a single Stat Point (previously called Attribute Point)
* @apiName UserAllocate
* @apiGroup User
+ * @apiDescription Allocates a single Stat Point.
*
* @apiParam (Query) {String="str","con","int","per"} stat The Stat to increase. Default is 'str'
*
diff --git a/website/server/controllers/api-v4/inbox.js b/website/server/controllers/api-v4/inbox.js
index 6ced58cc26..be5cca6a4d 100644
--- a/website/server/controllers/api-v4/inbox.js
+++ b/website/server/controllers/api-v4/inbox.js
@@ -77,7 +77,9 @@ api.clearMessages = {
* @api {get} /api/v4/inbox/conversations Get the conversations for a user
* @apiName conversations
* @apiGroup Inbox
- * @apiDescription Get the conversations for a user
+ * @apiDescription Get the conversations for a user.
+ * This is for API v4 which must not be used in third-party tools.
+ * For API v3, use "Get inbox messages for a user".
*
* @apiSuccess {Array} data An array of inbox conversations
*
diff --git a/website/server/controllers/api-v4/members.js b/website/server/controllers/api-v4/members.js
index bd31d6a0b4..b84a3775fe 100644
--- a/website/server/controllers/api-v4/members.js
+++ b/website/server/controllers/api-v4/members.js
@@ -5,8 +5,10 @@ const api = {};
/**
* @api {post} /api/v4/members/flag-private-message/:messageId Flag a private message
- * @apiDescription An email and slack message are sent
- * to the moderators about every flagged message.
+ * @apiDescription Moderators are notified about every flagged message,
+ * including the sender, recipient, and full content of the message.
+ * This is for API v4 which must not be used in third-party tools as it can change without notice.
+ * There is no equivalent route in API v3.
* @apiName FlagPrivateMessage
* @apiGroup Member
*
diff --git a/website/server/controllers/top-level/dataexport.js b/website/server/controllers/top-level/dataexport.js
index 7d55fb4074..715b8c2268 100644
--- a/website/server/controllers/top-level/dataexport.js
+++ b/website/server/controllers/top-level/dataexport.js
@@ -161,6 +161,7 @@ api.exportUserDataJson = {
/**
* @api {get} /export/userdata.xml Export user data in XML format
* @apiName ExportUserDataXml
+ * @apiDescription This XML export feature is not currently working (https://github.com/HabitRPG/habitica/issues/10100).
* @apiGroup DataExport
*
* @apiSuccess {XML} File An xml file of the user object.
@@ -224,6 +225,7 @@ api.exportUserAvatarHtml = {
/**
* @api {get} /export/avatar-:uuid.png Render a user avatar as a PNG file
* @apiName ExportUserAvatarPng
+ * @apiDescription This PNG export feature is not currently working (https://github.com/HabitRPG/habitica/issues/9489).
* @apiGroup DataExport
*
* @apiParam (Path) {String} uuid The User ID of the user
@@ -293,6 +295,7 @@ api.exportUserAvatarPng = {
/**
* @api {get} /export/inbox.html Export user private messages as HTML document
* @apiName ExportUserPrivateMessages
+ * @apiDescription This HTML export feature is not currently working (https://github.com/HabitRPG/habitica/issues/9489).
* @apiGroup DataExport
*
* @apiSuccess {HTML} File An html page of the user's private messages.
diff --git a/website/server/controllers/top-level/email.js b/website/server/controllers/top-level/email.js
index 1fd0cdcdf4..5062961cd6 100644
--- a/website/server/controllers/top-level/email.js
+++ b/website/server/controllers/top-level/email.js
@@ -8,14 +8,15 @@ import {
const api = {};
/**
- * @api {get} /email/unsubscribe Unsubscribe an email or user from email notifications
- * @apiDescription Does not require authentication
+ * @api {get} /email/unsubscribe Unsubscribe an email address or user from email notifications
* @apiName UnsubscribeEmail
* @apiGroup Unsubscribe
* @apiDescription This is a GET method included in official emails from Habitica
* that will unsubscribe the user from emails.
+ * Does not require authentication.
*
- * @apiParam (Query) {String} code An unsubscription code
+ * @apiParam (Query) {String} code An unsubscription code that contains an encrypted User ID or
+ * email address
*
* @apiSuccess {String} Webpage An html success message
*
diff --git a/website/server/libs/bannedSlurs.js b/website/server/libs/bannedSlurs.js
index 7c5f4fc9ca..48f3a9aae9 100644
--- a/website/server/libs/bannedSlurs.js
+++ b/website/server/libs/bannedSlurs.js
@@ -95,7 +95,6 @@ const bannedSlurs = [
- 'sluts',
'spics',
'tranny',
'trannies',
diff --git a/website/server/libs/bannedWords.js b/website/server/libs/bannedWords.js
index 620b955c1f..b1dd2f3653 100644
--- a/website/server/libs/bannedWords.js
+++ b/website/server/libs/bannedWords.js
@@ -69,6 +69,10 @@
// These words are blocked from use in the Tavern but do not appear in bannedSlurs.js
// because we do not want people to be automatically muted when the words are used
// appropriately in guilds.
+// As of 2020-02-26, 'sluts' is also here rather than in bannedSlurs.js because
+// "Expanded Party: Polyamorous Adventurers" guild (17bb8393-2d74-42de-8dcb-315a5f596636)
+// wants to discuss https://en.wikipedia.org/wiki/The_Ethical_Slut (a book) and
+// we've decided to allow that.
// DO NOT EDIT! See the comments at the top of this file.
@@ -147,6 +151,7 @@ const bannedWords = [
'fag',
'slut',
+ 'sluts',
'retard',
'retards',
'bastard',
diff --git a/website/server/libs/guildsAllowingBannedWords.js b/website/server/libs/guildsAllowingBannedWords.js
index b2decb3f5a..b7111b36f0 100644
--- a/website/server/libs/guildsAllowingBannedWords.js
+++ b/website/server/libs/guildsAllowingBannedWords.js
@@ -44,6 +44,7 @@ const guildsAllowingBannedWords = {
'612e5766-a171-4e0a-b02b-c55a9fe786e4': true, // Compulsive Overeaters
'726058f7-4452-47a3-aa86-e995d1ac031c': true, // Conscientious Consumption
'c59147bf-46c1-4ec8-a63f-9a8ebfcf9987': true, // Culinary Institute of Habitica
+ '9ffb19bb-1356-4ead-b585-c5031b5393b1': true, // Cynophiles
'202ab416-92b7-4cbe-97d7-772776c8f911': true, // Danish Translators
'6c6f4df6-8bc2-4a4c-a5a1-d4f1ef447989': true, // Dar al-Arqam
'ad251001-c1c5-4227-b165-6549a5b9e267': true, // Das Planertarium
@@ -57,6 +58,7 @@ const guildsAllowingBannedWords = {
'955fdbb8-f1b3-40cb-b528-8d292b312a6a': true, // Egyptology Unearthed
'a4cd281d-4683-4604-86f3-d2cc955e1544': true, // En espanol
'4c366cdd-9ece-4ee1-9bc5-fa0d0c8df63f': true, // Essential Habits of a Christian
+ '17bb8393-2d74-42de-8dcb-315a5f596636': true, // Expanded Party: Polyamorous Adventurers
'414381ad-08bf-4fe4-b767-c0e874660438': true, // FOCUS - Fellowship of Catholic University Students
'1705f33f-9303-4b78-93ac-e21ed2d08df8': true, // Fitbit Guild
'2ed36580-011f-4abb-94fc-e52022f38f6f': true, // Foodies
@@ -117,6 +119,7 @@ const guildsAllowingBannedWords = {
'8dc268f5-5f6d-41a0-82ca-a248dfd240c4': true, // Portugal Fenomenal
'77e13b13-e3ba-4e45-badf-9e448bb9be64': true, // Portuguese Translators
'46bc163e-f34e-4216-b916-9062d30a141f': true, // Procurando Grupo Brasil (Pedir Convite)
+ '14ae3965-0536-4b63-bc55-3dbd6660e3af': true, // Purely Positive Dog Trainers
'00698a77-cda2-4f49-a59f-f32205078903': true, // Quit Soda Support Group
'3584819a-a854-4768-ba49-8880fc0dda14': true, // Reiki Br
'd7838bfa-4577-4a4f-b922-65834e4a824c': true, // Rhyme Commando
@@ -137,8 +140,6 @@ const guildsAllowingBannedWords = {
'8e389264-ada0-4834-828c-ef65679e929c': true, // Witches, Pagans, and Diviners
'0ff469a9-677f-4dcd-a091-2d2d3cebcaa8': true, // Writers of Ideas: Speculative Fiction Authors
'f371368a-b3b0-4a81-a400-3bd59fc0a89d': true, // Youtube francophone
- '9ffb19bb-1356-4ead-b585-c5031b5393b1': true, // Cynophiles
- '14ae3965-0536-4b63-bc55-3dbd6660e3af': true, // Purely Positive Dog Trainers
};
export default guildsAllowingBannedWords;