mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 06:37:23 +01:00
Squashed commit of the following:
commit3aba0abeddAuthor: SabreCat <sabe@habitica.com> Date: Mon Oct 2 20:51:20 2023 -0500 fix(router): use state to pass modal launch info commit541eadd319Merge:c0bb56c8c289fff49d02Author: SabreCat <sabe@habitica.com> Date: Mon Oct 2 20:12:40 2023 -0500 Merge branch 'release' into report-profile-modal commitc0bb56c8c2Author: SabreCat <sabe@habitica.com> Date: Wed Sep 27 16:15:28 2023 -0500 test(profiles): add integrations commit9b644e9ad8Author: SabreCat <sabe@habitica.com> Date: Tue Sep 26 17:17:22 2023 -0500 fix(profile): adjust margin commitbfefe5dfa9Author: SabreCat <sabe@habitica.com> Date: Tue Sep 26 17:12:24 2023 -0500 fix(profiles): moar layout fixes commit8f211ee3e2Author: SabreCat <sabe@habitica.com> Date: Mon Sep 25 17:32:04 2023 -0500 fix(profile): fix admin actions Correct "user is banned" banner Fix bouncing modal Add "Days" smart plural Fix leaky CSS on Market page Refactor some redundant functions commitb1d23ec88bMerge:ee9709a9e1a63cc84779Author: SabreCat <sabe@habitica.com> Date: Mon Sep 25 15:37:54 2023 -0500 Merge branch 'release' into report-profile-modal commitee9709a9e1Author: CuriousMagpie <eilatan@gmail.com> Date: Mon Sep 18 16:30:30 2023 -0400 WIP(profile): add banned banner, toggle switches now toggle, add "days" to Next Login Reward commitf80928a895Author: CuriousMagpie <eilatan@gmail.com> Date: Mon Sep 18 13:43:34 2023 -0400 update(node): update node modules commit1d552f7e80Author: SabreCat <sabe@habitica.com> Date: Fri Sep 15 16:52:22 2023 -0500 fix(import): remove empty import commitf55d74a95dAuthor: SabreCat <sabe@habitica.com> Date: Fri Sep 15 16:39:50 2023 -0500 refactor(profiles): remove email feature also still more visual cleanup of profile modal commit311c743284Author: SabreCat <sabe@habitica.com> Date: Fri Sep 15 15:44:56 2023 -0500 refactor(profile): remove page view commitf8632bf50dMerge:ec85159c659e25360102Author: SabreCat <sabe@habitica.com> Date: Fri Sep 15 15:23:21 2023 -0500 Merge branch 'release' into report-profile-modal commitec85159c65Author: SabreCat <sabe@habitica.com> Date: Mon Sep 11 22:53:14 2023 -0500 feat(profiles): load modal instead of page? commit9986082914Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 8 14:49:57 2023 -0400 WIP(profile): fixed a comment, woohoo commit6262a9ba0cMerge:ae2b614df2ea2b007b1aAuthor: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 8 13:40:23 2023 -0400 Merge remote-tracking branch 'origin/report-profile-modal' into report-profile-modal commitea2b007b1aAuthor: SabreCat <sabe@habitica.com> Date: Thu Sep 7 16:54:19 2023 -0500 fix(profile): focus behavior commitae2b614df2Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Sep 7 17:47:08 2023 -0400 WIP(profile): styling updates commit2e0723f1b9Author: SabreCat <sabe@habitica.com> Date: Thu Sep 7 15:37:59 2023 -0500 feat(moderation): unflag profile Also a few stylistic tweaks commitedcf8113deAuthor: SabreCat <sabe@habitica.com> Date: Wed Sep 6 16:39:02 2023 -0500 WIP(profile): dropdown draft commit0691483d63Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Sep 6 16:33:30 2023 -0400 WIP(profile): Styling and string updates commit7e9d57d10aAuthor: SabreCat <sabe@habitica.com> Date: Wed Sep 6 11:40:31 2023 -0500 feat(profile): functional dropdown buttons commita2989b2833Merge:af6575e40ce072d7c09cAuthor: SabreCat <sabe@habitica.com> Date: Wed Sep 6 10:04:57 2023 -0500 Merge branch 'release' into report-profile-modal commitaf6575e40cAuthor: CuriousMagpie <eilatan@gmail.com> Date: Wed Sep 6 11:01:05 2023 -0400 WIP(profile): comment cleanup commit7b1de37202Author: CuriousMagpie <eilatan@gmail.com> Date: Tue Sep 5 17:22:14 2023 -0400 WIP(profile): remove shadowban tooltip commitd1177c32b9Merge:321a01b08131f821021bAuthor: CuriousMagpie <eilatan@gmail.com> Date: Tue Sep 5 17:02:40 2023 -0400 Merge branch 'sabrecat/report-profile' into report-profile-modal commit321a01b081Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 1 16:14:36 2023 -0400 WIP(profile): close button finally workinating commite143d36d28Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 1 15:52:38 2023 -0400 WIP(profile): close icon moved to profile.vue commit31f821021bMerge:a8f5e25d388957c5c009Author: SabreCat <sabe@habitica.com> Date: Fri Sep 1 14:52:31 2023 -0500 Merge branch 'report-profile-modal' into sabrecat/report-profile commit8957c5c009Merge:d340f06a220aec3866a4Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 1 15:38:12 2023 -0400 Merge remote-tracking branch 'origin/report-profile-modal' into report-profile-modal commitd340f06a22Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Sep 1 15:37:57 2023 -0400 WIP(profile): fixed user not found error commit0aec3866a4Merge:b01f323b14ac7c8e0eb6Author: Natalie <78037386+CuriousMagpie@users.noreply.github.com> Date: Fri Sep 1 15:28:58 2023 -0400 Merge branch 'HabitRPG:develop' into report-profile-modal commita8f5e25d38Author: SabreCat <sabe@habitica.com> Date: Thu Aug 31 17:02:07 2023 -0500 feat(community): basic "report profile" commitb01f323b14Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Aug 31 17:42:12 2023 -0400 WIP(profile): removed refactoring crud, located where close icon should be (profileModal.vue) commitce7d51a20cMerge:010f2299f0ac7c8e0eb6Author: SabreCat <sabe@habitica.com> Date: Thu Aug 31 14:20:37 2023 -0500 Merge branch 'release' into sabrecat/report-profile commit18b41acd94Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Aug 31 12:23:41 2023 -0400 WIP(profile): moar buttonz commit9387b3a6bcAuthor: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 30 17:21:36 2023 -0400 WIP(profile): buttons commitb3ea48c4f5Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Aug 25 15:52:41 2023 -0400 WIP(profile): work on achievement component commita1ceb2ea75Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Aug 25 14:39:12 2023 -0400 WIP(profile): create achievements component commit4a24d9b80bMerge:8fe263a3771e05297e96Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 23 13:14:39 2023 -0400 Merge branch 'develop' into report-profile-modal commit1e05297e96Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 23 13:12:52 2023 -0400 package updates commit8fe263a377Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 23 12:12:36 2023 -0400 update(dependencies): ran npm install to update dependencies commit190fe048a1Merge:3ea48ab5cbfa83d1a9cfAuthor: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 23 11:52:08 2023 -0400 Merge branch 'develop' into report-profile-modal commit3ea48ab5cbAuthor: CuriousMagpie <eilatan@gmail.com> Date: Fri Aug 11 17:12:31 2023 -0400 WIP(user profile): dropdown menu and toggles and colors oh my commitc301a2b460Merge:1da6af11b5647b27c55fAuthor: CuriousMagpie <eilatan@gmail.com> Date: Fri Aug 11 12:40:07 2023 -0400 Merge branch 'develop' into report-profile-modal commit1da6af11b5Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Aug 10 16:50:07 2023 -0400 WIP(user profile): moved some CSS classes out of unscoped and into the scoped section, started on toggle buttons commitdd55cbc928Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 9 15:38:46 2023 -0400 WIP(user profile): workin on the hamburger (kebab?) menu commit3834093207Author: CuriousMagpie <eilatan@gmail.com> Date: Tue Aug 8 14:14:40 2023 -0400 WIP(user profiles): working on the drop down menu commitf2be588195Author: CuriousMagpie <eilatan@gmail.com> Date: Mon Aug 7 16:10:30 2023 -0400 WIP(user profile): options menu commit010f2299f0Author: SabreCat <sabe@habitica.com> Date: Mon Aug 7 11:49:04 2023 -0500 fix(lint): eof and const commit4551dbf4b3Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Aug 4 15:34:05 2023 -0400 WIP(user profile): styling the top portion of the modal commit19a9fe3644Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Aug 3 15:06:51 2023 -0400 WIP(user profile): adding buttons commitdfdb305b1cAuthor: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 2 14:41:20 2023 -0400 WIP(user profile): layout commitded4eee693Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Aug 2 12:04:02 2023 -0400 WIP(user profile): start flex grid & tidy up CSS commitaaca48be32Author: CuriousMagpie <eilatan@gmail.com> Date: Fri Jul 28 16:44:06 2023 -0400 WIP(user profile): mostly css updates commite531985b87Author: CuriousMagpie <eilatan@gmail.com> Date: Thu Jul 27 16:49:44 2023 -0400 WIP(user profile): one infinitesimal change that's hardly worth the electricity it's made from commiteb4021fcc7Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Jul 26 16:33:05 2023 -0400 feat(content): upgrade profile page commit1b25394f3eMerge:c50cee0d888558dcc3a8Author: CuriousMagpie <eilatan@gmail.com> Date: Wed Jul 26 11:50:12 2023 -0400 Merge branch 'develop' into report-profile-modal commitc50cee0d88Author: SabreCat <sabe@habitica.com> Date: Wed Jul 12 16:32:25 2023 -0500 fix(flagging): debug params issue Also add and document the "source" body param commit55848c58beAuthor: SabreCat <sabe@habitica.com> Date: Mon Jul 10 16:24:20 2023 -0500 WIP(members): basic report a user API commitdda6180792Author: SabreCat <sabe@habitica.com> Date: Thu Jul 6 10:05:07 2023 -0500 fix(lint): remove console.info
This commit is contained in:
463
package-lock.json
generated
463
package-lock.json
generated
@@ -27,33 +27,74 @@
|
|||||||
"integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA=="
|
"integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA=="
|
||||||
},
|
},
|
||||||
"@babel/core": {
|
"@babel/core": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz",
|
||||||
"integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
|
"integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.22.5",
|
"@babel/code-frame": "^7.22.10",
|
||||||
"@babel/generator": "^7.22.5",
|
"@babel/generator": "^7.22.10",
|
||||||
"@babel/helper-compilation-targets": "^7.22.5",
|
"@babel/helper-compilation-targets": "^7.22.10",
|
||||||
"@babel/helper-module-transforms": "^7.22.5",
|
"@babel/helper-module-transforms": "^7.22.9",
|
||||||
"@babel/helpers": "^7.22.5",
|
"@babel/helpers": "^7.22.10",
|
||||||
"@babel/parser": "^7.22.5",
|
"@babel/parser": "^7.22.10",
|
||||||
"@babel/template": "^7.22.5",
|
"@babel/template": "^7.22.5",
|
||||||
"@babel/traverse": "^7.22.5",
|
"@babel/traverse": "^7.22.10",
|
||||||
"@babel/types": "^7.22.5",
|
"@babel/types": "^7.22.10",
|
||||||
"convert-source-map": "^1.7.0",
|
"convert-source-map": "^1.7.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"gensync": "^1.0.0-beta.2",
|
"gensync": "^1.0.0-beta.2",
|
||||||
"json5": "^2.2.2",
|
"json5": "^2.2.2",
|
||||||
"semver": "^6.3.0"
|
"semver": "^6.3.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
|
||||||
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
|
"integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/highlight": "^7.22.5"
|
"@babel/highlight": "^7.22.10",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/compat-data": {
|
||||||
|
"version": "7.22.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz",
|
||||||
|
"integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ=="
|
||||||
|
},
|
||||||
|
"@babel/generator": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/types": "^7.22.10",
|
||||||
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
|
"jsesc": "^2.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/helper-compilation-targets": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/compat-data": "^7.22.9",
|
||||||
|
"@babel/helper-validator-option": "^7.22.5",
|
||||||
|
"browserslist": "^4.21.9",
|
||||||
|
"lru-cache": "^5.1.1",
|
||||||
|
"semver": "^6.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/helper-module-transforms": {
|
||||||
|
"version": "7.22.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
|
||||||
|
"integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/helper-environment-visitor": "^7.22.5",
|
||||||
|
"@babel/helper-module-imports": "^7.22.5",
|
||||||
|
"@babel/helper-simple-access": "^7.22.5",
|
||||||
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
|
"@babel/helper-validator-identifier": "^7.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
@@ -62,25 +103,72 @@
|
|||||||
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
|
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
|
||||||
},
|
},
|
||||||
"@babel/highlight": {
|
"@babel/highlight": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
|
||||||
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
|
"integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-validator-identifier": "^7.22.5",
|
"@babel/helper-validator-identifier": "^7.22.5",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/types": {
|
"@babel/parser": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz",
|
||||||
"integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
|
"integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ=="
|
||||||
|
},
|
||||||
|
"@babel/traverse": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-string-parser": "^7.22.5",
|
"@babel/code-frame": "^7.22.10",
|
||||||
"@babel/helper-validator-identifier": "^7.22.5",
|
"@babel/generator": "^7.22.10",
|
||||||
"to-fast-properties": "^2.0.0"
|
"@babel/helper-environment-visitor": "^7.22.5",
|
||||||
|
"@babel/helper-function-name": "^7.22.5",
|
||||||
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
|
"@babel/parser": "^7.22.10",
|
||||||
|
"@babel/types": "^7.22.10",
|
||||||
|
"debug": "^4.1.0",
|
||||||
|
"globals": "^11.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@jridgewell/resolve-uri": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA=="
|
||||||
|
},
|
||||||
|
"@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.4.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
|
},
|
||||||
|
"@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||||
|
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||||
|
"requires": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"version": "4.21.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
|
||||||
|
"integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
|
||||||
|
"requires": {
|
||||||
|
"caniuse-lite": "^1.0.30001517",
|
||||||
|
"electron-to-chromium": "^1.4.477",
|
||||||
|
"node-releases": "^2.0.13",
|
||||||
|
"update-browserslist-db": "^1.0.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"caniuse-lite": {
|
||||||
|
"version": "1.0.30001522",
|
||||||
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz",
|
||||||
|
"integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg=="
|
||||||
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
@@ -91,10 +179,32 @@
|
|||||||
"supports-color": "^5.3.0"
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
|
},
|
||||||
|
"update-browserslist-db": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
|
||||||
|
"requires": {
|
||||||
|
"escalade": "^3.1.1",
|
||||||
|
"picocolors": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -542,28 +652,99 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helpers": {
|
"@babel/helpers": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz",
|
||||||
"integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
|
"integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/template": "^7.22.5",
|
"@babel/template": "^7.22.5",
|
||||||
"@babel/traverse": "^7.22.5",
|
"@babel/traverse": "^7.22.10",
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.22.10"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/code-frame": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/highlight": "^7.22.10",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/generator": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/types": "^7.22.10",
|
||||||
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
|
"jsesc": "^2.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
|
||||||
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
|
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
|
||||||
},
|
},
|
||||||
"@babel/types": {
|
"@babel/highlight": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
|
||||||
"integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
|
"integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-string-parser": "^7.22.5",
|
|
||||||
"@babel/helper-validator-identifier": "^7.22.5",
|
"@babel/helper-validator-identifier": "^7.22.5",
|
||||||
"to-fast-properties": "^2.0.0"
|
"chalk": "^2.4.2",
|
||||||
|
"js-tokens": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/parser": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ=="
|
||||||
|
},
|
||||||
|
"@babel/traverse": {
|
||||||
|
"version": "7.22.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz",
|
||||||
|
"integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/code-frame": "^7.22.10",
|
||||||
|
"@babel/generator": "^7.22.10",
|
||||||
|
"@babel/helper-environment-visitor": "^7.22.5",
|
||||||
|
"@babel/helper-function-name": "^7.22.5",
|
||||||
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
|
"@babel/parser": "^7.22.10",
|
||||||
|
"@babel/types": "^7.22.10",
|
||||||
|
"debug": "^4.1.0",
|
||||||
|
"globals": "^11.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@jridgewell/resolve-uri": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA=="
|
||||||
|
},
|
||||||
|
"@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.4.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
|
},
|
||||||
|
"@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||||
|
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||||
|
"requires": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^3.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2105,13 +2286,13 @@
|
|||||||
"integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw=="
|
"integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw=="
|
||||||
},
|
},
|
||||||
"@parse/node-apn": {
|
"@parse/node-apn": {
|
||||||
"version": "5.1.3",
|
"version": "5.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.2.3.tgz",
|
||||||
"integrity": "sha512-Bwhmbm895lEIF2772PJ8dSvBjrtOG9/q/TDMxmX40IgZxQFoXS73+JUIKTq3CA7SUB/Szu5roJINQ0L2U/1MJw==",
|
"integrity": "sha512-uBUTTbzk0YyMOcE5qTcNdit5v1BdaECCRSQYbMGU/qY1eHwBaqeWOYd8rwi2Caga3K7IZyQGhpvL4/56H+uvrQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "4.3.3",
|
"debug": "4.3.3",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "9.0.0",
|
||||||
"node-forge": "1.3.0",
|
"node-forge": "1.3.1",
|
||||||
"verror": "1.10.1"
|
"verror": "1.10.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2124,20 +2305,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jsonwebtoken": {
|
"jsonwebtoken": {
|
||||||
"version": "8.5.1",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
|
||||||
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
"integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"jws": "^3.2.2",
|
"jws": "^3.2.2",
|
||||||
"lodash.includes": "^4.3.0",
|
"lodash": "^4.17.21",
|
||||||
"lodash.isboolean": "^3.0.3",
|
|
||||||
"lodash.isinteger": "^4.0.4",
|
|
||||||
"lodash.isnumber": "^3.0.3",
|
|
||||||
"lodash.isplainobject": "^4.0.6",
|
|
||||||
"lodash.isstring": "^4.0.1",
|
|
||||||
"lodash.once": "^4.0.0",
|
|
||||||
"ms": "^2.1.1",
|
"ms": "^2.1.1",
|
||||||
"semver": "^5.6.0"
|
"semver": "^7.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jwa": {
|
"jwa": {
|
||||||
@@ -2159,10 +2334,13 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-forge": {
|
"semver": {
|
||||||
"version": "1.3.0",
|
"version": "7.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||||
"integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA=="
|
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"verror": {
|
"verror": {
|
||||||
"version": "1.10.1",
|
"version": "1.10.1",
|
||||||
@@ -2177,9 +2355,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sindresorhus/is": {
|
"@sindresorhus/is": {
|
||||||
"version": "4.2.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||||
"integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw=="
|
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="
|
||||||
},
|
},
|
||||||
"@sinonjs/commons": {
|
"@sinonjs/commons": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -2283,14 +2461,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/cacheable-request": {
|
"@types/cacheable-request": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||||
"integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==",
|
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/http-cache-semantics": "*",
|
"@types/http-cache-semantics": "*",
|
||||||
"@types/keyv": "*",
|
"@types/keyv": "^3.1.4",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/responselike": "*"
|
"@types/responselike": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
@@ -2383,9 +2561,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/keyv": {
|
"@types/keyv": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||||
"integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==",
|
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
@@ -3355,9 +3533,9 @@
|
|||||||
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.3.6",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||||
"integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==",
|
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
@@ -4210,9 +4388,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
|
||||||
"integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw=="
|
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ=="
|
||||||
},
|
},
|
||||||
"boxen": {
|
"boxen": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
@@ -8265,9 +8443,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"got": {
|
"got": {
|
||||||
"version": "11.8.3",
|
"version": "11.8.6",
|
||||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||||
"integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==",
|
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sindresorhus/is": "^4.0.0",
|
"@sindresorhus/is": "^4.0.0",
|
||||||
"@szmarczak/http-timer": "^4.0.5",
|
"@szmarczak/http-timer": "^4.0.5",
|
||||||
@@ -8291,9 +8469,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cacheable-request": {
|
"cacheable-request": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
|
||||||
"integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
|
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"clone-response": "^1.0.2",
|
"clone-response": "^1.0.2",
|
||||||
"get-stream": "^5.1.0",
|
"get-stream": "^5.1.0",
|
||||||
@@ -8331,9 +8509,9 @@
|
|||||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||||
},
|
},
|
||||||
"keyv": {
|
"keyv": {
|
||||||
"version": "4.0.4",
|
"version": "4.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
|
||||||
"integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==",
|
"integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
}
|
}
|
||||||
@@ -8359,9 +8537,9 @@
|
|||||||
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="
|
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="
|
||||||
},
|
},
|
||||||
"responselike": {
|
"responselike": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||||
"integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
|
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lowercase-keys": "^2.0.0"
|
"lowercase-keys": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -10256,41 +10434,6 @@
|
|||||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash.includes": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
|
|
||||||
},
|
|
||||||
"lodash.isboolean": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
|
|
||||||
},
|
|
||||||
"lodash.isinteger": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
|
|
||||||
},
|
|
||||||
"lodash.isnumber": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
|
|
||||||
},
|
|
||||||
"lodash.isplainobject": {
|
|
||||||
"version": "4.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
|
||||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
|
|
||||||
},
|
|
||||||
"lodash.isstring": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
|
|
||||||
},
|
|
||||||
"lodash.once": {
|
|
||||||
"version": "4.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
|
||||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
|
||||||
},
|
|
||||||
"log-driver": {
|
"log-driver": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
|
||||||
@@ -11113,16 +11256,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mongoose": {
|
"mongoose": {
|
||||||
"version": "5.13.7",
|
"version": "5.13.20",
|
||||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.7.tgz",
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.20.tgz",
|
||||||
"integrity": "sha512-ADIvftZ+KfoTALMZ0n8HvBlezFhcUd73hQaHQDwQ+3X+JZlqE47fUy9yhFZ2SjT+qzmuaCcIXCfhewIc38t2fQ==",
|
"integrity": "sha512-TjGFa/XnJYt+wLmn8y9ssjyO2OhBMeEBtOHb9iJM16EWu2Du6L1Q6zSiEK2ziyYQM8agb4tumNIQFzqbxId7MA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@types/bson": "1.x || 4.0.x",
|
||||||
"@types/mongodb": "^3.5.27",
|
"@types/mongodb": "^3.5.27",
|
||||||
"bson": "^1.1.4",
|
"bson": "^1.1.4",
|
||||||
"kareem": "2.3.2",
|
"kareem": "2.3.2",
|
||||||
"mongodb": "3.6.11",
|
"mongodb": "3.7.4",
|
||||||
"mongoose-legacy-pluralize": "1.0.2",
|
"mongoose-legacy-pluralize": "1.0.2",
|
||||||
"mpath": "0.8.3",
|
"mpath": "0.8.4",
|
||||||
"mquery": "3.2.5",
|
"mquery": "3.2.5",
|
||||||
"ms": "2.1.2",
|
"ms": "2.1.2",
|
||||||
"optional-require": "1.0.x",
|
"optional-require": "1.0.x",
|
||||||
@@ -11142,22 +11286,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
"version": "3.6.11",
|
"version": "3.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz",
|
||||||
"integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==",
|
"integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bl": "^2.2.1",
|
"bl": "^2.2.1",
|
||||||
"bson": "^1.1.4",
|
"bson": "^1.1.4",
|
||||||
"denque": "^1.4.1",
|
"denque": "^1.4.1",
|
||||||
"optional-require": "^1.0.3",
|
"optional-require": "^1.1.8",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"saslprep": "^1.0.0"
|
"saslprep": "^1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"optional-require": {
|
||||||
|
"version": "1.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz",
|
||||||
|
"integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==",
|
||||||
|
"requires": {
|
||||||
|
"require-at": "^1.0.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.7",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "~1.0.0",
|
"core-util-is": "~1.0.0",
|
||||||
"inherits": "~2.0.3",
|
"inherits": "~2.0.3",
|
||||||
@@ -11300,9 +11454,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mpath": {
|
"mpath": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
|
||||||
"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA=="
|
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g=="
|
||||||
},
|
},
|
||||||
"mquery": {
|
"mquery": {
|
||||||
"version": "3.2.5",
|
"version": "3.2.5",
|
||||||
@@ -11327,7 +11481,7 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -12203,9 +12357,9 @@
|
|||||||
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
|
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
|
||||||
},
|
},
|
||||||
"passport": {
|
"passport": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/passport/-/passport-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/passport/-/passport-0.5.3.tgz",
|
||||||
"integrity": "sha512-ln+ue5YaNDS+fes6O5PCzXKSseY5u8MYhX9H5Co4s+HfYI5oqvnHKoOORLYDUPh+8tHvrxugF2GFcUA1Q1Gqfg==",
|
"integrity": "sha512-gGc+70h4gGdBWNsR3FuV3byLDY6KBTJAIExGFXTpQaYfbbcHCBlRRKx7RBQSpqEqc5Hh2qVzRs7ssvSfOpkUEA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"passport-strategy": "1.x.x",
|
"passport-strategy": "1.x.x",
|
||||||
"pause": "0.0.1"
|
"pause": "0.0.1"
|
||||||
@@ -12319,7 +12473,7 @@
|
|||||||
"pause": {
|
"pause": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||||
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
|
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||||
},
|
},
|
||||||
"pause-stream": {
|
"pause-stream": {
|
||||||
"version": "0.0.11",
|
"version": "0.0.11",
|
||||||
@@ -13153,6 +13307,11 @@
|
|||||||
"integrity": "sha1-7W2Lm9Y4wTMosV3YOL1mYRHdeBw=",
|
"integrity": "sha1-7W2Lm9Y4wTMosV3YOL1mYRHdeBw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"require-at": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g=="
|
||||||
|
},
|
||||||
"require-directory": {
|
"require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@@ -13809,7 +13968,7 @@
|
|||||||
"sliced": {
|
"sliced": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
||||||
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
|
"integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
|
||||||
},
|
},
|
||||||
"snapdragon": {
|
"snapdragon": {
|
||||||
"version": "0.8.2",
|
"version": "0.8.2",
|
||||||
@@ -14402,9 +14561,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stripe": {
|
"stripe": {
|
||||||
"version": "12.9.0",
|
"version": "12.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-12.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-12.18.0.tgz",
|
||||||
"integrity": "sha512-stYtrWetRYUsEbsUVyJaPG9Sppt0ds2szBqXsuDG6KZPPuUmCccbpceLrhoOBwNl1RziEfNB7oG9wg1n2eW+EQ==",
|
"integrity": "sha512-cYjgBM2SY/dTm8Lr6eMyyONaHTZHA/QjHxFUIW5WH8FevSRIGAVtXEmBkUXF1fsqe7QvvRgQSGSJZmjDacegGg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": ">=8.1.0",
|
"@types/node": ">=8.1.0",
|
||||||
"qs": "^6.11.0"
|
"qs": "^6.11.0"
|
||||||
@@ -15636,9 +15795,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"validator": {
|
"validator": {
|
||||||
"version": "13.9.0",
|
"version": "13.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
|
||||||
"integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA=="
|
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ=="
|
||||||
},
|
},
|
||||||
"value-or-function": {
|
"value-or-function": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -4,11 +4,11 @@
|
|||||||
"version": "5.6.0",
|
"version": "5.6.0",
|
||||||
"main": "./website/server/index.js",
|
"main": "./website/server/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.22.5",
|
"@babel/core": "^7.22.10",
|
||||||
"@babel/preset-env": "^7.22.10",
|
"@babel/preset-env": "^7.22.10",
|
||||||
"@babel/register": "^7.22.5",
|
"@babel/register": "^7.22.5",
|
||||||
"@google-cloud/trace-agent": "^7.1.2",
|
"@google-cloud/trace-agent": "^7.1.2",
|
||||||
"@parse/node-apn": "^5.1.3",
|
"@parse/node-apn": "^5.2.3",
|
||||||
"@slack/webhook": "^6.1.0",
|
"@slack/webhook": "^6.1.0",
|
||||||
"accepts": "^1.3.8",
|
"accepts": "^1.3.8",
|
||||||
"amazon-payments": "^0.2.9",
|
"amazon-payments": "^0.2.9",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"apple-auth": "^1.0.9",
|
"apple-auth": "^1.0.9",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"bootstrap": "^4.6.0",
|
"bootstrap": "^4.6.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"cookie-session": "^2.0.0",
|
"cookie-session": "^2.0.0",
|
||||||
"coupon-code": "^0.4.5",
|
"coupon-code": "^0.4.5",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
"express-validator": "^5.2.0",
|
"express-validator": "^5.2.0",
|
||||||
"glob": "^8.1.0",
|
"glob": "^8.1.0",
|
||||||
"got": "^11.8.3",
|
"got": "^11.8.6",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.0",
|
||||||
"gulp-babel": "^8.0.0",
|
"gulp-babel": "^8.0.0",
|
||||||
"gulp-imagemin": "^7.1.0",
|
"gulp-imagemin": "^7.1.0",
|
||||||
@@ -49,12 +49,12 @@
|
|||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"moment-recur": "^1.0.7",
|
"moment-recur": "^1.0.7",
|
||||||
"mongoose": "^5.13.7",
|
"mongoose": "^5.13.20",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"nconf": "^0.12.0",
|
"nconf": "^0.12.0",
|
||||||
"node-gcm": "^1.0.5",
|
"node-gcm": "^1.0.5",
|
||||||
"on-headers": "^1.0.2",
|
"on-headers": "^1.0.2",
|
||||||
"passport": "^0.5.0",
|
"passport": "^0.5.3",
|
||||||
"passport-facebook": "^3.0.0",
|
"passport-facebook": "^3.0.0",
|
||||||
"passport-google-oauth2": "^0.2.0",
|
"passport-google-oauth2": "^0.2.0",
|
||||||
"passport-google-oauth20": "2.0.0",
|
"passport-google-oauth20": "2.0.0",
|
||||||
@@ -67,12 +67,12 @@
|
|||||||
"remove-markdown": "^0.5.0",
|
"remove-markdown": "^0.5.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"short-uuid": "^4.2.2",
|
"short-uuid": "^4.2.2",
|
||||||
"stripe": "^12.9.0",
|
"stripe": "^12.18.0",
|
||||||
"superagent": "^8.1.2",
|
"superagent": "^8.1.2",
|
||||||
"universal-analytics": "^0.5.3",
|
"universal-analytics": "^0.5.3",
|
||||||
"useragent": "^2.1.9",
|
"useragent": "^2.1.9",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.11.0",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"winston": "^3.10.0",
|
"winston": "^3.10.0",
|
||||||
"winston-loggly-bulk": "^3.2.1",
|
"winston-loggly-bulk": "^3.2.1",
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
"apidoc": "gulp apidoc"
|
"apidoc": "gulp apidoc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"axios": "^1.3.6",
|
"axios": "^1.4.0",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai-as-promised": "^7.1.1",
|
||||||
"chai-moment": "^0.1.0",
|
"chai-moment": "^0.1.0",
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { v4 as generateUUID } from 'uuid';
|
||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
|
describe('POST /members/:memberId/clear-flags', () => {
|
||||||
|
let reporter;
|
||||||
|
let admin;
|
||||||
|
let moderator;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
reporter = await generateUser();
|
||||||
|
admin = await generateUser({ permissions: { userSupport: true } });
|
||||||
|
moderator = await generateUser({ permissions: { moderator: true } });
|
||||||
|
await reporter.post(`/members/${admin._id}/flag`);
|
||||||
|
});
|
||||||
|
|
||||||
|
context('error cases', () => {
|
||||||
|
it('returns error when memberId is not a UUID', async () => {
|
||||||
|
await expect(moderator.post('/members/gribbly/clear-flags'))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns error when member with UUID is not found', async () => {
|
||||||
|
const randomId = generateUUID();
|
||||||
|
|
||||||
|
await expect(moderator.post(`/members/${randomId}/clear-flags`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 404,
|
||||||
|
error: 'NotFound',
|
||||||
|
message: t('userWithIDNotFound', { userId: randomId }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns error when requesting user is not a moderator', async () => {
|
||||||
|
await expect(reporter.post(`/members/${admin._id}/clear-flags`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'Only a moderator may clear reports from a profile.',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('valid request', () => {
|
||||||
|
it('removes a single flag from user', async () => {
|
||||||
|
await expect(moderator.post(`/members/${admin._id}/clear-flags`)).to.eventually.be.ok;
|
||||||
|
const updatedTarget = await admin.get(`/hall/heroes/${admin._id}`);
|
||||||
|
expect(updatedTarget.profile.flags).to.eql({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes multiple flags from user', async () => {
|
||||||
|
await moderator.post(`/members/${admin._id}/flag`);
|
||||||
|
await expect(moderator.post(`/members/${admin._id}/clear-flags`)).to.eventually.be.ok;
|
||||||
|
const updatedTarget = await admin.get(`/hall/heroes/${admin._id}`);
|
||||||
|
expect(updatedTarget.profile.flags).to.eql({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
151
test/api/v3/integration/members/POST-members_memberId_flag.js
Normal file
151
test/api/v3/integration/members/POST-members_memberId_flag.js
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import { v4 as generateUUID } from 'uuid';
|
||||||
|
import moment from 'moment';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../helpers/api-integration/v3';
|
||||||
|
import { IncomingWebhook } from '@slack/webhook';
|
||||||
|
|
||||||
|
describe('POST /members/:memberId/flag', () => {
|
||||||
|
let reporter;
|
||||||
|
let target;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
reporter = await generateUser();
|
||||||
|
target = await generateUser({
|
||||||
|
'profile.blurb': 'Naughty Text',
|
||||||
|
'profile.imageUrl': 'https://evil.com/',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('error cases', () => {
|
||||||
|
it('returns error when memberId is not a UUID', async () => {
|
||||||
|
await expect(reporter.post('/members/gribbly/flag'))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns error when member with UUID is not found', async () => {
|
||||||
|
const randomId = generateUUID();
|
||||||
|
|
||||||
|
await expect(reporter.post(`/members/${randomId}/flag`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 404,
|
||||||
|
error: 'NotFound',
|
||||||
|
message: t('userWithIDNotFound', { userId: randomId }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns error when non-admin flags same profile twice', async () => {
|
||||||
|
await reporter.post(`/members/${target._id}/flag`);
|
||||||
|
await expect (reporter.post(`/members/${target._id}/flag`))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: 'A profile can not be flagged more than once by the same user.',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('valid request', () => {
|
||||||
|
let admin;
|
||||||
|
const comment = 'this profile is bad';
|
||||||
|
const source = 'Third Party Script';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
admin = await generateUser({ 'permissions.userSupport': true });
|
||||||
|
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds flags object to target user', async () => {
|
||||||
|
await reporter.post(`/members/${target._id}/flag`);
|
||||||
|
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
|
||||||
|
expect(updatedTarget.profile.flags[reporter._id]).to.have.all.keys([
|
||||||
|
'comment',
|
||||||
|
'source',
|
||||||
|
'timestamp',
|
||||||
|
]);
|
||||||
|
expect(moment(updatedTarget.profile.flags[reporter._id].timestamp).toDate()).to.be.a('date');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows addition of a comment and source', async () => {
|
||||||
|
await reporter.post(`/members/${target._id}/flag`, {
|
||||||
|
comment,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
|
||||||
|
expect(updatedTarget.profile.flags[reporter._id].comment).to.eql(comment);
|
||||||
|
expect(updatedTarget.profile.flags[reporter._id].source).to.eql(source);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows moderator to flag twice', async () => {
|
||||||
|
const moderator = await generateUser({ 'permissions.moderator': true });
|
||||||
|
await moderator.post(`/members/${target._id}/flag`);
|
||||||
|
await expect(moderator.post(`/members/${target._id}/flag`)).to.eventually.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows multiple non-moderators to flag individually', async () => {
|
||||||
|
await admin.post(`/members/${target._id}/flag`);
|
||||||
|
await reporter.post(`/members/${target._id}/flag`);
|
||||||
|
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
|
||||||
|
expect(updatedTarget.profile.flags[admin._id]).to.exist;
|
||||||
|
expect(updatedTarget.profile.flags[reporter._id]).to.exist;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sends a flag report to moderation Slack', async () => {
|
||||||
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
await reporter.post(`/members/${target._id}/flag`, {
|
||||||
|
comment,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||||
|
text: `@${reporter.auth.local.username} (${reporter._id}; language: ${reporter.preferences.language}) flagged @${target.auth.local.username}'s profile from ${source} and commented: ${comment}`,
|
||||||
|
attachments: [{
|
||||||
|
fallback: 'Flag Profile',
|
||||||
|
color: 'danger',
|
||||||
|
title: 'User Profile Report',
|
||||||
|
title_link: `${BASE_URL}/profile/${target._id}`,
|
||||||
|
text: `Display Name: ${target.profile.name}\n\nImage URL: ${target.profile.imageUrl}\n\nAbout: ${target.profile.blurb}`,
|
||||||
|
mrkdwn_in: [
|
||||||
|
'text',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes empty fields when sending Slack message', async () => {
|
||||||
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
await reporter.post(`/members/${admin._id}/flag`, {
|
||||||
|
comment,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||||
|
text: `@${reporter.auth.local.username} (${reporter._id}; language: ${reporter.preferences.language}) flagged @${admin.auth.local.username}'s profile from ${source} and commented: ${comment}`,
|
||||||
|
attachments: [{
|
||||||
|
fallback: 'Flag Profile',
|
||||||
|
color: 'danger',
|
||||||
|
title: 'User Profile Report',
|
||||||
|
title_link: `${BASE_URL}/profile/${admin._id}`,
|
||||||
|
text: `Display Name: ${admin.profile.name}`,
|
||||||
|
mrkdwn_in: [
|
||||||
|
'text',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
125
website/client/package-lock.json
generated
125
website/client/package-lock.json
generated
@@ -13318,11 +13318,34 @@
|
|||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
},
|
},
|
||||||
|
"emojis-list": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||||
},
|
},
|
||||||
|
"loader-utils": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"big.js": "^5.2.2",
|
||||||
|
"emojis-list": "^3.0.0",
|
||||||
|
"json5": "^2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
@@ -13354,6 +13377,38 @@
|
|||||||
"ansi-regex": "^5.0.1"
|
"ansi-regex": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vue-loader-v16": {
|
||||||
|
"version": "npm:vue-loader@16.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||||
|
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"hash-sum": "^2.0.0",
|
||||||
|
"loader-utils": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
@@ -30581,76 +30636,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vue-loader-v16": {
|
|
||||||
"version": "npm:vue-loader@16.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
|
||||||
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
|
||||||
"requires": {
|
|
||||||
"chalk": "^4.1.0",
|
|
||||||
"hash-sum": "^2.0.0",
|
|
||||||
"loader-utils": "^2.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
||||||
"requires": {
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
|
||||||
"version": "4.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
|
||||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^4.1.0",
|
|
||||||
"supports-color": "^7.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"requires": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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=="
|
|
||||||
},
|
|
||||||
"emojis-list": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
|
|
||||||
},
|
|
||||||
"has-flag": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
|
||||||
},
|
|
||||||
"loader-utils": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
|
||||||
"requires": {
|
|
||||||
"big.js": "^5.2.2",
|
|
||||||
"emojis-list": "^3.0.0",
|
|
||||||
"json5": "^2.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"supports-color": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vue-mugen-scroll": {
|
"vue-mugen-scroll": {
|
||||||
"version": "0.2.6",
|
"version": "0.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/vue-mugen-scroll/-/vue-mugen-scroll-0.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/vue-mugen-scroll/-/vue-mugen-scroll-0.2.6.tgz",
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 1.71;
|
line-height: 1.71;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
padding: 0.219rem 0.75rem;
|
padding: 4px 12px;
|
||||||
border-radius: 2px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||||
color: $white;
|
color: $white;
|
||||||
|
|
||||||
|
|||||||
10
website/client/src/assets/svg/crown.svg
Normal file
10
website/client/src/assets/svg/crown.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#nw2v1izcda)">
|
||||||
|
<path d="m8 4.01 2.2 5.4 3.8-3.4-2 6H4l-2-6 3.8 3.4L8 4.01zm0-2c-.81 0-1.55.49-1.85 1.25L5.02 6.03 3.33 4.52A1.98 1.98 0 0 0 2 4.01 2.002 2.002 0 0 0 .1 6.64l2 6A2 2 0 0 0 4 14.01h8a2 2 0 0 0 1.9-1.37l1.97-5.9a1.997 1.997 0 0 0-1.85-2.73h-.04c-.5.01-.95.2-1.3.51L11 6.02 9.87 3.25A2.012 2.012 0 0 0 8.02 2L8 2.01z" fill="#4E4A57"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="nw2v1izcda">
|
||||||
|
<path fill="#fff" d="M0 0h16v16H0z"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 617 B |
10
website/client/src/assets/svg/mute.svg
Normal file
10
website/client/src/assets/svg/mute.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#464rik5fna)">
|
||||||
|
<path d="M12 2c1.1 0 2 .9 2 2v6c0 1.1-.9 2-2 2l-4 2v-2H4c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h8zm0-2H4C1.79 0 0 1.79 0 4v6c0 2.21 1.79 4 4 4h2c0 .69.36 1.34.95 1.7a1.993 1.993 0 0 0 1.94.09l3.65-1.83A4 4 0 0 0 15.99 10V4c0-2.21-1.79-4-4-4H12zM9.41 7l1.29-1.29A.996.996 0 1 0 9.29 4.3L8 5.59 6.71 4.3A.996.996 0 1 0 5.3 5.71L6.59 7 5.3 8.29a.996.996 0 0 0 .71 1.7c.26 0 .51-.1.71-.29l1.29-1.29L9.3 9.7c.2.2.45.29.71.29.26 0 .51-.1.71-.29a.996.996 0 0 0 0-1.41L9.43 7h-.02z" fill="#4E4A57"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="464rik5fna">
|
||||||
|
<path fill="#fff" d="M0 0h16v16H0z"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 770 B |
10
website/client/src/assets/svg/shadow-mute.svg
Normal file
10
website/client/src/assets/svg/shadow-mute.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#mzh0y8jf2a)">
|
||||||
|
<path d="M12 2c1.1 0 2 .9 2 2v6c0 1.1-.9 2-2 2l-4 2v-2H4c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h8zm0-2H4C1.79 0 0 1.79 0 4v6c0 2.21 1.79 4 4 4h2c0 .69.36 1.34.95 1.7a1.993 1.993 0 0 0 1.94.09l3.65-1.83A4 4 0 0 0 15.99 10V4c0-2.21-1.79-4-4-4H12zm-.17 7c0-.55-.45-1-1-1H5.17c-.55 0-1 .45-1 1s.45 1 1 1h5.66c.55 0 1-.45 1-1z" fill="#4E4A57"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="mzh0y8jf2a">
|
||||||
|
<path fill="#fff" d="M0 0h16v16H0z"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 618 B |
@@ -84,7 +84,7 @@
|
|||||||
v-if="invites.length > 0"
|
v-if="invites.length > 0"
|
||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<div class="col-6 offset-3 nav">
|
<div class="col-6 offset-3 nav mt-2 mb-3">
|
||||||
<div
|
<div
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
:class="{active: selectedPage === 'members'}"
|
:class="{active: selectedPage === 'members'}"
|
||||||
@@ -111,17 +111,18 @@
|
|||||||
:key="member._id"
|
:key="member._id"
|
||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<div class="col-11 no-padding-left">
|
<div class="col-11 pl-0">
|
||||||
<member-details
|
<member-details
|
||||||
:member="member"
|
:member="member"
|
||||||
:class-badge-position="'next-to-name'"
|
:class-badge-position="'next-to-name'"
|
||||||
|
class="ml-4"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-1 actions">
|
<div class="col-1 actions">
|
||||||
<b-dropdown right="right">
|
<b-dropdown right="right">
|
||||||
<div
|
<div
|
||||||
slot="button-content"
|
slot="button-content"
|
||||||
class="svg-icon inline dots"
|
class="svg-icon inline dots pt-1"
|
||||||
v-html="icons.dots"
|
v-html="icons.dots"
|
||||||
></div>
|
></div>
|
||||||
<b-dropdown-item @click="sendMessage(member)">
|
<b-dropdown-item @click="sendMessage(member)">
|
||||||
@@ -216,7 +217,7 @@
|
|||||||
:key="member._id"
|
:key="member._id"
|
||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<div class="col-11 no-padding-left">
|
<div class="col-11 pl-0">
|
||||||
<member-details :member="member" />
|
<member-details :member="member" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-1 actions">
|
<div class="col-1 actions">
|
||||||
@@ -259,10 +260,6 @@
|
|||||||
color: #878190;
|
color: #878190;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-padding-left {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
@@ -303,21 +300,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
padding-top: 5em;
|
.b-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
right: 24px;
|
||||||
|
top: 8px;
|
||||||
|
}
|
||||||
.dots {
|
.dots {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group {
|
|
||||||
margin-left: -2em;
|
|
||||||
margin-top: -2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-icon {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#members-modal_modal_body {
|
#members-modal_modal_body {
|
||||||
@@ -353,8 +344,6 @@
|
|||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: .5em;
|
|
||||||
margin-top: .5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.nav-item {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
:class-badge-position="'next-to-name'"
|
:class-badge-position="'next-to-name'"
|
||||||
:is-header="true"
|
:is-header="true"
|
||||||
:disable-name-styling="true"
|
:disable-name-styling="true"
|
||||||
|
class="mr-3"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="hasParty"
|
v-if="hasParty"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<creator-intro />
|
<creator-intro />
|
||||||
<profileModal />
|
<profileModal />
|
||||||
<report-flag-modal />
|
<report-flag-modal />
|
||||||
|
<report-member-modal />
|
||||||
<send-gift-modal />
|
<send-gift-modal />
|
||||||
<select-user-modal />
|
<select-user-modal />
|
||||||
<b-navbar
|
<b-navbar
|
||||||
@@ -732,6 +733,7 @@ import creatorIntro from '../creatorIntro';
|
|||||||
import notificationMenu from './notificationsDropdown';
|
import notificationMenu from './notificationsDropdown';
|
||||||
import profileModal from '../userMenu/profileModal';
|
import profileModal from '../userMenu/profileModal';
|
||||||
import reportFlagModal from '../chat/reportFlagModal';
|
import reportFlagModal from '../chat/reportFlagModal';
|
||||||
|
import reportMemberModal from '../members/reportMemberModal';
|
||||||
import sendGiftModal from '@/components/payments/sendGiftModal';
|
import sendGiftModal from '@/components/payments/sendGiftModal';
|
||||||
import selectUserModal from '@/components/payments/selectUserModal';
|
import selectUserModal from '@/components/payments/selectUserModal';
|
||||||
import sync from '@/mixins/sync';
|
import sync from '@/mixins/sync';
|
||||||
@@ -744,6 +746,7 @@ export default {
|
|||||||
notificationMenu,
|
notificationMenu,
|
||||||
profileModal,
|
profileModal,
|
||||||
reportFlagModal,
|
reportFlagModal,
|
||||||
|
reportMemberModal,
|
||||||
sendGiftModal,
|
sendGiftModal,
|
||||||
selectUserModal,
|
selectUserModal,
|
||||||
userDropdown,
|
userDropdown,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="member-details"
|
class="member-details d-flex"
|
||||||
:class="{ condensed, expanded, 'd-flex': isHeader, row: !isHeader, }"
|
:class="{ condensed, expanded }"
|
||||||
@click="showMemberModal(member)"
|
@click="showMemberModal(member)"
|
||||||
>
|
>
|
||||||
<div class="avatar-container" :class="{ 'col-4': !isHeader }">
|
<div class="avatar-container">
|
||||||
<avatar
|
<avatar
|
||||||
:member="member"
|
:member="member"
|
||||||
:hide-class-badge="classBadgePosition !== 'under-avatar'"
|
:hide-class-badge="classBadgePosition !== 'under-avatar'"
|
||||||
@@ -15,14 +15,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="member-stats"
|
class="member-stats"
|
||||||
:class="{'col-8': !expanded && !isHeader}"
|
:class="{ 'mt-2': !isHeader }"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-items-center profile-first-row">
|
<div class="d-flex align-items-center profile-first-row">
|
||||||
<class-badge
|
<class-badge
|
||||||
v-if="classBadgePosition === 'next-to-name'"
|
v-if="classBadgePosition === 'next-to-name'"
|
||||||
:member-class="member.stats.class"
|
:member-class="member.stats.class"
|
||||||
/>
|
/>
|
||||||
<div class="d-flex flex-column profile-name-character">
|
<div
|
||||||
|
class="d-flex flex-column"
|
||||||
|
:class="{ 'ml-2': classBadgePosition === 'next-to-name' }"
|
||||||
|
>
|
||||||
<h3 class="character-name">
|
<h3 class="character-name">
|
||||||
<span v-if="member.contributor && member.contributor.level > 0 && !disableNameStyling">
|
<span v-if="member.contributor && member.contributor.level > 0 && !disableNameStyling">
|
||||||
<user-link
|
<user-link
|
||||||
@@ -30,19 +33,23 @@
|
|||||||
:name="member.profile.name"
|
:name="member.profile.name"
|
||||||
:backer="member.backer"
|
:backer="member.backer"
|
||||||
:contributor="member.contributor"
|
:contributor="member.contributor"
|
||||||
|
:showBuffed="isBuffed"
|
||||||
|
:context="'profile'"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>{{ member.profile.name }}</span>
|
<div v-else>
|
||||||
|
<span>{{ member.profile.name }}</span>
|
||||||
<div
|
<div
|
||||||
v-if="isBuffed"
|
v-if="isBuffed"
|
||||||
v-b-tooltip.hover.bottom="$t('buffed')"
|
v-b-tooltip.hover.bottom="$t('buffed')"
|
||||||
class="is-buffed"
|
class="is-buffed ml-2 mt-n1"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="svg-icon"
|
class="svg-icon"
|
||||||
v-html="icons.buff"
|
v-html="icons.buff"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="small-text character-level">
|
<div class="small-text character-level">
|
||||||
<span
|
<span
|
||||||
@@ -98,9 +105,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.standard-page .member-details {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.member-stats {
|
.member-stats {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 24px;
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: width 0.15s ease-out;
|
transition: width 0.15s ease-out;
|
||||||
}
|
}
|
||||||
@@ -114,10 +124,6 @@
|
|||||||
color: $header-color;
|
color: $header-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-name-character {
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-name {
|
.character-name {
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
color: $white;
|
color: $white;
|
||||||
@@ -133,7 +139,6 @@
|
|||||||
height: 20px;
|
height: 20px;
|
||||||
background: $header-dark-background;
|
background: $header-dark-background;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 16px;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
|
|
||||||
|
|||||||
199
website/client/src/components/members/reportMemberModal.vue
Normal file
199
website/client/src/components/members/reportMemberModal.vue
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<b-modal
|
||||||
|
id="report-profile"
|
||||||
|
:title="$t('reportPlayer')"
|
||||||
|
:hide-footer="!hasPermission(user, 'moderator')"
|
||||||
|
size="md"
|
||||||
|
>
|
||||||
|
<div slot="modal-header">
|
||||||
|
<h2 class="mt-2 mb-0"> {{ $t('reportPlayer') }} </h2>
|
||||||
|
<close-x
|
||||||
|
@close="close()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<blockquote>
|
||||||
|
<strong> {{ displayName }} </strong>
|
||||||
|
<p class="mb-0"> {{ username }} </p>
|
||||||
|
</blockquote>
|
||||||
|
<div>
|
||||||
|
<strong>{{ $t('whyReportingPlayer') }}</strong>
|
||||||
|
<textarea
|
||||||
|
v-model="reportComment"
|
||||||
|
class="mt-2 form-control"
|
||||||
|
:placeholder="$t('whyReportingPlayerPlaceholder')"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="mb-2"
|
||||||
|
v-html="$t('playerReportModalBody', abuseFlagModalBody)">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer text-center d-flex flex-column">
|
||||||
|
<button
|
||||||
|
class="btn btn-danger mx-auto mb-3"
|
||||||
|
:disabled="!reportComment"
|
||||||
|
:class="{ disabled: !reportComment }"
|
||||||
|
@click="reportAbuse()"
|
||||||
|
>
|
||||||
|
{{ $t('report') }}
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
class="cancel-link"
|
||||||
|
@click.prevent="close()"
|
||||||
|
>{{ $t('cancel') }}</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="modal-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="d-flex"
|
||||||
|
@click="resetFlags()"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-once
|
||||||
|
class="svg-icon icon-16 color my-auto mr-2"
|
||||||
|
v-html="icons.report"
|
||||||
|
></div>
|
||||||
|
<a>Reset Flags</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</b-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
#report-profile {
|
||||||
|
.modal-header {
|
||||||
|
padding: 24px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.modal-body {
|
||||||
|
padding: 0px 24px 24px 24px;
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
color: $maroon-50;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
border-top: none;
|
||||||
|
height: 48px;
|
||||||
|
background-color: rgba($red-500, 0.25);
|
||||||
|
margin-top: -8px;
|
||||||
|
padding: 0px;
|
||||||
|
a {
|
||||||
|
margin-top: 2px;
|
||||||
|
color: $maroon-50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
strong, p {
|
||||||
|
line-height: 1.71;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $maroon-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: $gray-700;
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: solid 1px $gray-400;
|
||||||
|
min-height: 106px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 1rem 1rem 0rem 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import closeX from '@/components/ui/closeX';
|
||||||
|
import notifications from '@/mixins/notifications';
|
||||||
|
import markdownDirective from '@/directives/markdown';
|
||||||
|
import { userStateMixin } from '../../mixins/userState';
|
||||||
|
import report from '@/assets/svg/report.svg';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
closeX,
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
markdown: markdownDirective,
|
||||||
|
},
|
||||||
|
mixins: [notifications, userStateMixin],
|
||||||
|
data () {
|
||||||
|
const abuseFlagModalBody = {
|
||||||
|
firstLinkStart: '<a href="/static/community-guidelines" target="_blank">',
|
||||||
|
secondLinkStart: '<a href="/static/terms" target="_blank">',
|
||||||
|
linkEnd: '</a>',
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
abuseFlagModalBody,
|
||||||
|
displayName: '',
|
||||||
|
username: '',
|
||||||
|
reportComment: '',
|
||||||
|
icons: Object.freeze({
|
||||||
|
report,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$root.$on('habitica::report-profile', this.handleReport);
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.$root.$off('habitica::report-profile', this.handleReport);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close () {
|
||||||
|
this.$root.$emit('bv::hide::modal', 'report-profile');
|
||||||
|
},
|
||||||
|
async reportAbuse () {
|
||||||
|
const result = await this.$store.dispatch('members:reportMember', {
|
||||||
|
memberId: this.memberId,
|
||||||
|
source: this.$route.fullPath,
|
||||||
|
comment: this.reportComment,
|
||||||
|
});
|
||||||
|
if (result.status === 200) {
|
||||||
|
this.text(this.$t('abuseReported'));
|
||||||
|
|
||||||
|
this.$root.$emit('habitica:report-profile-result', result.data.data);
|
||||||
|
} else {
|
||||||
|
this.error(result.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
handleReport (data) {
|
||||||
|
if (!data.memberId) return;
|
||||||
|
this.displayName = data.displayName;
|
||||||
|
this.username = `@${data.username}`;
|
||||||
|
this.memberId = data.memberId;
|
||||||
|
this.reportComment = '';
|
||||||
|
this.$root.$emit('bv::show::modal', 'report-profile');
|
||||||
|
},
|
||||||
|
async resetFlags () {
|
||||||
|
const result = await this.$store.dispatch('members:clearMemberFlags', {
|
||||||
|
memberId: this.memberId,
|
||||||
|
});
|
||||||
|
if (result.status === 200) {
|
||||||
|
this.text('Flags cleared.');
|
||||||
|
} else {
|
||||||
|
this.err(result.statusText);
|
||||||
|
}
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -265,7 +265,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.how-many-to-sell {
|
.how-many-to-sell {
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
@@ -313,8 +312,7 @@
|
|||||||
line-height: 1.33;
|
line-height: 1.33;
|
||||||
color: $gray-200;
|
color: $gray-200;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -486,6 +486,15 @@ export default {
|
|||||||
this.$store.dispatch('common:setTitle', {
|
this.$store.dispatch('common:setTitle', {
|
||||||
section: this.$t('tasks'),
|
section: this.$t('tasks'),
|
||||||
});
|
});
|
||||||
|
if (this.$store.state.postLoadModal) {
|
||||||
|
const modalToLoad = this.$store.state.postLoadModal;
|
||||||
|
if (modalToLoad.includes('profile')) {
|
||||||
|
this.$router.push(modalToLoad);
|
||||||
|
} else {
|
||||||
|
this.$root.$emit('bv::show::modal', modalToLoad);
|
||||||
|
}
|
||||||
|
this.$store.state.postLoadModal = '';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({ setUser: 'user:set' }),
|
...mapActions({ setUser: 'user:set' }),
|
||||||
|
|||||||
@@ -9,8 +9,19 @@
|
|||||||
{{ displayName }}
|
{{ displayName }}
|
||||||
<div
|
<div
|
||||||
class="svg-icon icon-12"
|
class="svg-icon icon-12"
|
||||||
|
:class="{ 'margin-bump': context === 'profile' }"
|
||||||
v-html="tierIcon()"
|
v-html="tierIcon()"
|
||||||
></div>
|
></div>
|
||||||
|
<div
|
||||||
|
v-if="showBuffed"
|
||||||
|
v-b-tooltip.hover.bottom="$t('buffed')"
|
||||||
|
class="is-buffed ml-2 d-flex align-items-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="svg-icon m-auto"
|
||||||
|
v-html="icons.buff"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -39,7 +50,12 @@
|
|||||||
|
|
||||||
&[class*="tier"] .svg-icon {
|
&[class*="tier"] .svg-icon {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
|
||||||
|
&.margin-bump {
|
||||||
|
margin-top: 7px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.npc .svg-icon {
|
&.npc .svg-icon {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
@@ -52,6 +68,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-buffed {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: $header-dark-background;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 2px;
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 12px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -70,6 +101,7 @@ import tier7 from '@/assets/svg/tier-7.svg';
|
|||||||
import tier8 from '@/assets/svg/tier-mod.svg';
|
import tier8 from '@/assets/svg/tier-mod.svg';
|
||||||
import tier9 from '@/assets/svg/tier-staff.svg';
|
import tier9 from '@/assets/svg/tier-staff.svg';
|
||||||
import tierNPC from '@/assets/svg/tier-npc.svg';
|
import tierNPC from '@/assets/svg/tier-npc.svg';
|
||||||
|
import buffIcon from '@/assets/svg/buff.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [styleHelper],
|
mixins: [styleHelper],
|
||||||
@@ -81,6 +113,8 @@ export default {
|
|||||||
'contributor',
|
'contributor',
|
||||||
'hideTooltip',
|
'hideTooltip',
|
||||||
'smallerStyle',
|
'smallerStyle',
|
||||||
|
'showBuffed',
|
||||||
|
'context',
|
||||||
],
|
],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -95,6 +129,7 @@ export default {
|
|||||||
tier8,
|
tier8,
|
||||||
tier9,
|
tier9,
|
||||||
tierNPC,
|
tierNPC,
|
||||||
|
buff: buffIcon,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
264
website/client/src/components/userMenu/profileAchievs.vue
Normal file
264
website/client/src/components/userMenu/profileAchievs.vue
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
id="achievements"
|
||||||
|
class="standard-page"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(category, key) in achievements"
|
||||||
|
:key="key"
|
||||||
|
class="row category-row"
|
||||||
|
>
|
||||||
|
<h3 class="text-center">
|
||||||
|
{{ $t(`${key}Achievs`) }}
|
||||||
|
</h3>
|
||||||
|
<div class="">
|
||||||
|
<div class="row achievements-row justify-content-center">
|
||||||
|
<div
|
||||||
|
v-for="(achievement, achievKey) in achievementsCategory(key, category)"
|
||||||
|
:key="achievKey"
|
||||||
|
class="achievement-wrapper col text-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:id="achievKey + '-achievement'"
|
||||||
|
class="box achievement-container"
|
||||||
|
:class="{'achievement-unearned': !achievement.earned}"
|
||||||
|
>
|
||||||
|
<b-popover
|
||||||
|
:target="'#' + achievKey + '-achievement'"
|
||||||
|
triggers="hover"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<h4 class="popover-content-title">
|
||||||
|
{{ achievement.title }}
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="popover-content-text"
|
||||||
|
v-html="achievement.text"
|
||||||
|
></div>
|
||||||
|
</b-popover>
|
||||||
|
<div
|
||||||
|
v-if="achievement.earned"
|
||||||
|
class="achievement"
|
||||||
|
:class="achievement.icon + '2x'"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="achievement.optionalCount"
|
||||||
|
class="counter badge badge-pill stack-count"
|
||||||
|
>
|
||||||
|
{{ achievement.optionalCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!achievement.earned"
|
||||||
|
class="achievement achievement-unearned achievement-unearned2x"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="achievementsCategories[key].number > 5"
|
||||||
|
class="btn btn-flat btn-show-more"
|
||||||
|
@click="toggleAchievementsCategory(key)"
|
||||||
|
>
|
||||||
|
{{ achievementsCategories[key].open ?
|
||||||
|
$t('hideAchievements', {category: $t(`${key}Achievs`)}) :
|
||||||
|
$t('showAllAchievements', {category: $t(`${key}Achievs`)})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="">
|
||||||
|
<div class="row">
|
||||||
|
<div
|
||||||
|
v-if="user.achievements.challenges"
|
||||||
|
class="col-12 col-md-6"
|
||||||
|
>
|
||||||
|
<div class="achievement-icon achievement-karaoke-2x"></div>
|
||||||
|
<h3 class="text-center">
|
||||||
|
{{ $t('challengesWon') }}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
v-for="chal in user.achievements.challenges"
|
||||||
|
:key="chal"
|
||||||
|
class="achievement-list-item"
|
||||||
|
>
|
||||||
|
<span v-markdown="chal"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="user.achievements.quests"
|
||||||
|
class="col-12 col-md-6"
|
||||||
|
>
|
||||||
|
<div class="achievement-icon achievement-alien2x"></div>
|
||||||
|
<h3 class="text-center">
|
||||||
|
{{ $t('questsCompleted') }}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
v-for="(value, key) in user.achievements.quests"
|
||||||
|
:key="key"
|
||||||
|
class="achievement-list-item d-flex justify-content-between"
|
||||||
|
>
|
||||||
|
<span>{{ content.quests[key].text() }}</span>
|
||||||
|
<span
|
||||||
|
v-if="value > 1"
|
||||||
|
class="badge badge-pill stack-count"
|
||||||
|
>
|
||||||
|
{{ value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
#achievements {
|
||||||
|
.category-row {
|
||||||
|
margin-bottom: 34px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievements-row {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 590px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-wrapper {
|
||||||
|
margin-left: 12px;
|
||||||
|
margin-right: 12px;
|
||||||
|
max-width: 94px;
|
||||||
|
min-width: 94px;
|
||||||
|
padding: 0px;
|
||||||
|
width: 94px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
background: $white;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin-bottom: 48px;
|
||||||
|
margin-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box.achievement-unearned {
|
||||||
|
background-color: $gray-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter.badge {
|
||||||
|
background-color: $orange-100;
|
||||||
|
color: $white;
|
||||||
|
max-height: 24px;
|
||||||
|
position: absolute;
|
||||||
|
right: -8px;
|
||||||
|
top: -12.8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-icon {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-list-item {
|
||||||
|
border-top: 1px solid $gray-500;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
padding-top: 11px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 1px solid $gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
background: $gray-600;
|
||||||
|
color: $gray-300;
|
||||||
|
height: fit-content;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import moment from 'moment';
|
||||||
|
// import axios from 'axios';
|
||||||
|
// import each from 'lodash/each';
|
||||||
|
// import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
// import closeX from '../ui/closeX';
|
||||||
|
|
||||||
|
import achievementsLib from '@/../../common/script/libs/achievements';
|
||||||
|
import Content from '@/../../common/script/content';
|
||||||
|
import error404 from '../404';
|
||||||
|
// import { userCustomStateMixin } from '../../mixins/userState';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components:
|
||||||
|
error404,
|
||||||
|
// closeX,
|
||||||
|
props: ['userId', 'startingPage'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
selectedPage: 'achievements',
|
||||||
|
achievements: {},
|
||||||
|
achievementsCategories: {}, // number, open
|
||||||
|
content: Content,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadUser () {
|
||||||
|
let user = null;
|
||||||
|
|
||||||
|
const profileUserId = this.userId;
|
||||||
|
|
||||||
|
if (profileUserId && profileUserId !== this.userLoggedIn._id) {
|
||||||
|
const response = await this.$store.dispatch('members:fetchMember', {
|
||||||
|
memberId: profileUserId,
|
||||||
|
unpack: false,
|
||||||
|
});
|
||||||
|
if (response.response && response.response.status === 404) {
|
||||||
|
user = null;
|
||||||
|
this.$store.dispatch('snackbars:add', {
|
||||||
|
title: 'Habitica',
|
||||||
|
text: this.$t('messageDeletedUser'),
|
||||||
|
type: 'error',
|
||||||
|
timeout: false,
|
||||||
|
});
|
||||||
|
} else if (response.status && response.status === 200) {
|
||||||
|
user = response.data.data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user = this.userLoggedIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
if (!user.achievements.quests) user.achievements.quests = {};
|
||||||
|
if (!user.achievements.challenges) user.achievements.challenges = {};
|
||||||
|
// @TODO: this common code should handle the above
|
||||||
|
this.achievements = achievementsLib.getAchievementsForProfile(user);
|
||||||
|
|
||||||
|
const achievementsCategories = {};
|
||||||
|
Object.keys(this.achievements).forEach(category => {
|
||||||
|
achievementsCategories[category] = {
|
||||||
|
open: false,
|
||||||
|
number: Object.keys(this.achievements[category].achievements).length,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.achievementsCategories = achievementsCategories;
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userLoaded = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<b-modal
|
<b-modal
|
||||||
id="profile"
|
id="profile"
|
||||||
size="lg"
|
|
||||||
:hide-footer="true"
|
:hide-footer="true"
|
||||||
:hide-header="true"
|
|
||||||
@hide="beforeHide"
|
@hide="beforeHide"
|
||||||
@shown="onShown()"
|
@shown="onShown()"
|
||||||
>
|
>
|
||||||
|
<div slot="modal-header">
|
||||||
|
<close-x
|
||||||
|
@close="close()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<profile
|
<profile
|
||||||
:user-id="userId"
|
:user-id="userId"
|
||||||
:starting-page="startingPage"
|
:starting-page="startingPage"
|
||||||
@@ -15,33 +19,62 @@
|
|||||||
</b-modal>
|
</b-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
#profile {
|
||||||
|
.modal-header {
|
||||||
|
background-color: $white;
|
||||||
|
border-bottom: none;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.modal-dialog {
|
||||||
|
max-width: 684px;
|
||||||
|
}
|
||||||
|
.modal-body {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
background: $gray-700;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.header {
|
.modal-close {
|
||||||
width: 100%;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import profile from './profile';
|
import profile from './profile';
|
||||||
|
import closeX from '../ui/closeX';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
profile,
|
profile,
|
||||||
|
closeX,
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
startingPage: undefined,
|
startingPage: undefined,
|
||||||
path: undefined,
|
fromPath: undefined,
|
||||||
|
toPath: undefined,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$root.$on('habitica:show-profile', data => {
|
this.$root.$on('habitica:show-profile', data => {
|
||||||
this.userId = data.userId;
|
this.userId = data.userId;
|
||||||
this.startingPage = data.startingPage || 'profile';
|
this.startingPage = data.startingPage || 'profile';
|
||||||
this.path = data.path;
|
this.fromPath = data.fromPath;
|
||||||
|
this.toPath = data.toPath;
|
||||||
this.$root.$emit('bv::show::modal', 'profile');
|
this.$root.$emit('bv::show::modal', 'profile');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -50,13 +83,16 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onShown () {
|
onShown () {
|
||||||
window.history.pushState('', null, this.path);
|
window.history.pushState('', null, this.toPath);
|
||||||
},
|
},
|
||||||
beforeHide () {
|
beforeHide () {
|
||||||
if (this.$route.path !== window.location.pathname) {
|
if (this.$route.path !== window.location.pathname) {
|
||||||
this.$router.back();
|
window.history.pushState('', null, this.fromPath);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
close () {
|
||||||
|
this.$root.$emit('bv::hide::modal', 'profile');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="standard-page">
|
|
||||||
<profile
|
|
||||||
:user-id="userId"
|
|
||||||
:starting-page="startingPage"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '~@/assets/scss/colors.scss';
|
|
||||||
|
|
||||||
.header {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import profile from './profile';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
profile,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
userId: String,
|
|
||||||
startingPage: {
|
|
||||||
type: String,
|
|
||||||
default: 'profile',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -8,7 +8,6 @@ import { PAGES } from '@/libs/consts';
|
|||||||
import { STATIC_ROUTES } from './static-routes';
|
import { STATIC_ROUTES } from './static-routes';
|
||||||
import { USER_ROUTES } from './user-routes';
|
import { USER_ROUTES } from './user-routes';
|
||||||
import { DEPRECATED_ROUTES } from '@/router/deprecated-routes';
|
import { DEPRECATED_ROUTES } from '@/router/deprecated-routes';
|
||||||
import { ProfilePage } from './shared-route-imports';
|
|
||||||
|
|
||||||
// NOTE: when adding a page make sure to implement the `common:setTitle` action
|
// NOTE: when adding a page make sure to implement the `common:setTitle` action
|
||||||
|
|
||||||
@@ -94,11 +93,7 @@ const router = new VueRouter({
|
|||||||
{
|
{
|
||||||
name: 'userProfile',
|
name: 'userProfile',
|
||||||
path: '/profile/:userId',
|
path: '/profile/:userId',
|
||||||
component: ProfilePage,
|
|
||||||
props: true,
|
props: true,
|
||||||
children: [
|
|
||||||
{ name: 'userProfilePage', path: ':startingPage', component: ProfilePage },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/inventory',
|
path: '/inventory',
|
||||||
@@ -319,34 +314,40 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((to.name === 'userProfile' || to.name === 'userProfilePage') && from.name !== null) {
|
if ((to.name === 'userProfile')) {
|
||||||
let startingPage = 'profile';
|
let startingPage = 'profile';
|
||||||
if (to.params.startingPage !== undefined) {
|
if (to.params.startingPage !== undefined) {
|
||||||
startingPage = to.params.startingPage;
|
startingPage = to.params.startingPage;
|
||||||
}
|
}
|
||||||
|
if (from.name === null) {
|
||||||
|
store.state.postLoadModal = `profile/${to.params.userId}`;
|
||||||
|
return next({ name: 'tasks' });
|
||||||
|
}
|
||||||
router.app.$emit('habitica:show-profile', {
|
router.app.$emit('habitica:show-profile', {
|
||||||
userId: to.params.userId,
|
userId: to.params.userId,
|
||||||
startingPage,
|
startingPage,
|
||||||
path: to.path,
|
fromPath: from.path,
|
||||||
|
toPath: to.path,
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.name === 'tasks' && to.query.openGemsModal === 'true') {
|
if (to.name === 'tasks' && to.query.openGemsModal === 'true') {
|
||||||
setTimeout(() => router.app.$emit('bv::show::modal', 'buy-gems'), 500);
|
store.state.postLoadModal = 'buy-gems';
|
||||||
return next({ name: 'tasks' });
|
return next({ name: 'tasks' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((to.name === 'stats' || to.name === 'achievements' || to.name === 'profile') && from.name !== null) {
|
if ((to.name === 'stats' || to.name === 'achievements' || to.name === 'profile') && from.name !== null) {
|
||||||
router.app.$emit('habitica:show-profile', {
|
router.app.$emit('habitica:show-profile', {
|
||||||
startingPage: to.name,
|
startingPage: to.name,
|
||||||
path: to.path,
|
fromPath: from.path,
|
||||||
|
toPath: to.path,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from.name === 'userProfile' || from.name === 'userProfilePage' || from.name === 'stats' || from.name === 'achievements' || from.name === 'profile') {
|
if (from.name === 'userProfile' || from.name === 'stats' || from.name === 'achievements' || from.name === 'profile') {
|
||||||
router.app.$root.$emit('bv::hide::modal', 'profile');
|
router.app.$root.$emit('bv::hide::modal', 'profile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
export const NotFoundPage = () => import(/* webpackChunkName: "not-found" */'@/components/404');
|
export const NotFoundPage = () => import(/* webpackChunkName: "not-found" */'@/components/404');
|
||||||
|
|
||||||
export const ProfilePage = () => import(/* webpackChunkName: "user" */'@/components/userMenu/profilePage');
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import ParentPage from '@/components/parentPage.vue';
|
import ParentPage from '@/components/parentPage.vue';
|
||||||
import { ProfilePage } from './shared-route-imports';
|
|
||||||
|
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
const Settings = () => import(/* webpackChunkName: "settings" */'@/components/settings/index');
|
const Settings = () => import(/* webpackChunkName: "settings" */'@/components/settings/index');
|
||||||
@@ -12,14 +10,10 @@ const Site = () => import(/* webpackChunkName: "settings" */'@/components/settin
|
|||||||
const Subscription = () => import(/* webpackChunkName: "settings" */'@/components/settings/subscription');
|
const Subscription = () => import(/* webpackChunkName: "settings" */'@/components/settings/subscription');
|
||||||
const Transactions = () => import(/* webpackChunkName: "settings" */'@/components/settings/purchaseHistory');
|
const Transactions = () => import(/* webpackChunkName: "settings" */'@/components/settings/purchaseHistory');
|
||||||
|
|
||||||
|
|
||||||
export const USER_ROUTES = {
|
export const USER_ROUTES = {
|
||||||
path: '/user',
|
path: '/user',
|
||||||
component: ParentPage,
|
component: ParentPage,
|
||||||
children: [
|
children: [
|
||||||
{ name: 'stats', path: 'stats', component: ProfilePage },
|
|
||||||
{ name: 'achievements', path: 'achievements', component: ProfilePage },
|
|
||||||
{ name: 'profile', path: 'profile', component: ProfilePage },
|
|
||||||
{
|
{
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
|
|||||||
@@ -114,3 +114,19 @@ export async function getPurchaseHistory (store, payload) {
|
|||||||
const response = await axios.get(`${apiv4Prefix}/members/${payload.memberId}/purchase-history`);
|
const response = await axios.get(`${apiv4Prefix}/members/${payload.memberId}/purchase-history`);
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function reportMember (store, payload) {
|
||||||
|
const url = `${apiv4Prefix}/members/${payload.memberId}/flag`;
|
||||||
|
const data = {
|
||||||
|
comment: payload.comment,
|
||||||
|
source: payload.source,
|
||||||
|
};
|
||||||
|
const response = await axios.post(url, data);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearMemberFlags (store, payload) {
|
||||||
|
const url = `${apiv4Prefix}/members/${payload.memberId}/clear-flags`;
|
||||||
|
const response = await axios.post(url);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ export default function () {
|
|||||||
bugReportOptions: {
|
bugReportOptions: {
|
||||||
question: false,
|
question: false,
|
||||||
},
|
},
|
||||||
|
postLoadModal: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -175,8 +175,9 @@
|
|||||||
"photo": "Photo",
|
"photo": "Photo",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"joined": "Joined",
|
"joined": "Joined",
|
||||||
"totalLogins": "Total Check Ins",
|
"totalLogins": "Total Log Ins",
|
||||||
"latestCheckin": "Latest Check In",
|
"latestCheckin": "Latest Log In",
|
||||||
|
"nextReward": "Next Log In Reward",
|
||||||
"editProfile": "Edit Profile",
|
"editProfile": "Edit Profile",
|
||||||
"challengesWon": "Challenges Won",
|
"challengesWon": "Challenges Won",
|
||||||
"questsCompleted": "Quests Completed",
|
"questsCompleted": "Quests Completed",
|
||||||
|
|||||||
@@ -213,6 +213,16 @@
|
|||||||
"loadEarlierMessages": "Load Earlier Messages",
|
"loadEarlierMessages": "Load Earlier Messages",
|
||||||
"askQuestion": "Ask a Question",
|
"askQuestion": "Ask a Question",
|
||||||
"emptyReportBugMessage": "Report Bug Message missing",
|
"emptyReportBugMessage": "Report Bug Message missing",
|
||||||
|
"reportPlayer": "Report Player",
|
||||||
|
"blockPlayer": "Block Player",
|
||||||
|
"unblockPlayer": "Unblock Player",
|
||||||
|
"adminTools": "Admin Tools",
|
||||||
|
"viewAdminPanel": "View Admin Panel",
|
||||||
|
"shadowMute": "Shadow Mute",
|
||||||
|
"mutePlayer": "Mute",
|
||||||
|
"banPlayer": "Ban Player",
|
||||||
|
"unbanPlayer": "Unban Player",
|
||||||
|
"bannedPlayer": "This player is banned.",
|
||||||
"refreshList": "Refresh List",
|
"refreshList": "Refresh List",
|
||||||
"leaveHabitica": "You are about to leave Habitica.com",
|
"leaveHabitica": "You are about to leave Habitica.com",
|
||||||
"leaveHabiticaText": "Habitica is not responsible for the content of any linked website that is not owned or operated by HabitRPG.<br>Please note that these websites' practices may differ from Habitica’s community guidelines.",
|
"leaveHabiticaText": "Habitica is not responsible for the content of any linked website that is not owned or operated by HabitRPG.<br>Please note that these websites' practices may differ from Habitica’s community guidelines.",
|
||||||
@@ -222,5 +232,9 @@
|
|||||||
"question": "Question",
|
"question": "Question",
|
||||||
"questionDescriptionText": "It's okay to ask your questions in your primary language if you aren't comfortable speaking in English.",
|
"questionDescriptionText": "It's okay to ask your questions in your primary language if you aren't comfortable speaking in English.",
|
||||||
"questionPlaceholder": "Ask your question here",
|
"questionPlaceholder": "Ask your question here",
|
||||||
"submitQuestion": "Submit Question"
|
"submitQuestion": "Submit Question",
|
||||||
|
"reportPlayer": "Report Player",
|
||||||
|
"whyReportingPlayer": "Why are you reporting this player?",
|
||||||
|
"whyReportingPlayerPlaceholder": "Reason for report",
|
||||||
|
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habitica’s Community Guidelines."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,10 +87,12 @@
|
|||||||
"PMCanNotReply": "You can not reply to this conversation",
|
"PMCanNotReply": "You can not reply to this conversation",
|
||||||
"PMUserDoesNotReceiveMessages": "This user is no longer receiving private messages",
|
"PMUserDoesNotReceiveMessages": "This user is no longer receiving private messages",
|
||||||
"PMUnblockUserToSendMessages": "Unblock this user to continue sending and receiving messages.",
|
"PMUnblockUserToSendMessages": "Unblock this user to continue sending and receiving messages.",
|
||||||
"block": "Block",
|
"block": "Block Player",
|
||||||
"unblock": "Un-block",
|
"blockedUser": "<strong>You blocked this player.</strong> They cannot send you Private Messages but you will still see their posts.",
|
||||||
|
"bannedUser": "<strong>This player has been banned.</strong>",
|
||||||
|
"unblock": "Unblock Player",
|
||||||
"blockYourself": "You cannot block yourself",
|
"blockYourself": "You cannot block yourself",
|
||||||
"blockWarning": "Block - This will have no effect if the player is a moderator now or becomes a moderator in future.",
|
"blockWarning": "This will have no effect if the player is an admin.",
|
||||||
"inbox": "Inbox",
|
"inbox": "Inbox",
|
||||||
"messageRequired": "A message is required.",
|
"messageRequired": "A message is required.",
|
||||||
"toUserIDRequired": "A User ID is required",
|
"toUserIDRequired": "A User ID is required",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../libs/errors';
|
} from '../../libs/errors';
|
||||||
import { removeFromArray } from '../../libs/collectionManipulators';
|
import { removeFromArray } from '../../libs/collectionManipulators';
|
||||||
import { getUserInfo, getGroupUrl, sendTxn } from '../../libs/email';
|
import { getUserInfo, getGroupUrl } from '../../libs/email';
|
||||||
import * as slack from '../../libs/slack';
|
import * as slack from '../../libs/slack';
|
||||||
import { chatReporterFactory } from '../../libs/chatReporting/chatReporterFactory';
|
import { chatReporterFactory } from '../../libs/chatReporting/chatReporterFactory';
|
||||||
import { getAuthorEmailFromMessage } from '../../libs/chat';
|
import { getAuthorEmailFromMessage } from '../../libs/chat';
|
||||||
@@ -28,7 +28,6 @@ import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService';
|
|||||||
const analytics = getAnalyticsServiceByEnvironment();
|
const analytics = getAnalyticsServiceByEnvironment();
|
||||||
|
|
||||||
const ACCOUNT_MIN_CHAT_AGE = Number(nconf.get('ACCOUNT_MIN_CHAT_AGE'));
|
const ACCOUNT_MIN_CHAT_AGE = Number(nconf.get('ACCOUNT_MIN_CHAT_AGE'));
|
||||||
const FLAG_REPORT_EMAILS = nconf.get('FLAG_REPORT_EMAIL').split(',').map(email => ({ email, canSend: true }));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @apiDefine MessageNotFound
|
* @apiDefine MessageNotFound
|
||||||
@@ -164,8 +163,6 @@ api.postChat = {
|
|||||||
{ name: 'GROUP_URL', content: groupUrl },
|
{ name: 'GROUP_URL', content: groupUrl },
|
||||||
];
|
];
|
||||||
|
|
||||||
sendTxn(FLAG_REPORT_EMAILS, 'slur-report-to-mods', report);
|
|
||||||
|
|
||||||
// Slack the mods
|
// Slack the mods
|
||||||
slack.sendSlurNotification({
|
slack.sendSlurNotification({
|
||||||
authorEmail,
|
authorEmail,
|
||||||
@@ -241,8 +238,6 @@ api.postChat = {
|
|||||||
{ name: 'GROUP_URL', content: groupUrl },
|
{ name: 'GROUP_URL', content: groupUrl },
|
||||||
];
|
];
|
||||||
|
|
||||||
sendTxn(FLAG_REPORT_EMAILS, 'shadow-muted-post-report-to-mods', report);
|
|
||||||
|
|
||||||
// Slack the mods
|
// Slack the mods
|
||||||
slack.sendShadowMutedPostNotification({
|
slack.sendShadowMutedPostNotification({
|
||||||
authorEmail,
|
authorEmail,
|
||||||
@@ -447,26 +442,6 @@ api.clearChatFlags = {
|
|||||||
const authorEmail = getAuthorEmailFromMessage(message);
|
const authorEmail = getAuthorEmailFromMessage(message);
|
||||||
const groupUrl = getGroupUrl(group);
|
const groupUrl = getGroupUrl(group);
|
||||||
|
|
||||||
sendTxn(FLAG_REPORT_EMAILS, 'unflag-report-to-mods', [
|
|
||||||
{ name: 'MESSAGE_TIME', content: (new Date(message.timestamp)).toString() },
|
|
||||||
{ name: 'MESSAGE_TEXT', content: message.text },
|
|
||||||
|
|
||||||
{ name: 'ADMIN_USERNAME', content: user.profile.name },
|
|
||||||
{ name: 'ADMIN_UUID', content: user._id },
|
|
||||||
{ name: 'ADMIN_EMAIL', content: adminEmailContent },
|
|
||||||
{ name: 'ADMIN_MODAL_URL', content: `/profile/${user._id}` },
|
|
||||||
|
|
||||||
{ name: 'AUTHOR_USERNAME', content: message.user },
|
|
||||||
{ name: 'AUTHOR_UUID', content: message.uuid },
|
|
||||||
{ name: 'AUTHOR_EMAIL', content: authorEmail },
|
|
||||||
{ name: 'AUTHOR_MODAL_URL', content: `/profile/${message.uuid}` },
|
|
||||||
|
|
||||||
{ name: 'GROUP_NAME', content: group.name },
|
|
||||||
{ name: 'GROUP_TYPE', content: group.type },
|
|
||||||
{ name: 'GROUP_ID', content: group._id },
|
|
||||||
{ name: 'GROUP_URL', content: groupUrl },
|
|
||||||
]);
|
|
||||||
|
|
||||||
res.respond(200, {});
|
res.respond(200, {});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ api.getHeroes = {
|
|||||||
// Note, while the following routes are called getHero / updateHero
|
// Note, while the following routes are called getHero / updateHero
|
||||||
// they can be used by admins to get/update any user
|
// they can be used by admins to get/update any user
|
||||||
|
|
||||||
const heroAdminFields = 'auth balance contributor flags items lastCron party preferences profile.name purchased secret permissions';
|
const heroAdminFields = 'auth balance contributor flags items lastCron party preferences profile purchased secret permissions';
|
||||||
const heroAdminFieldsToFetch = heroAdminFields; // these variables will make more sense when...
|
const heroAdminFieldsToFetch = heroAdminFields; // these variables will make more sense when...
|
||||||
const heroAdminFieldsToShow = heroAdminFields; // ... apiTokenObscured is added
|
const heroAdminFieldsToShow = heroAdminFields; // ... apiTokenObscured is added
|
||||||
|
|
||||||
@@ -200,6 +200,7 @@ api.getHero = {
|
|||||||
if (!heroRes.contributor) heroRes.contributor = {};
|
if (!heroRes.contributor) heroRes.contributor = {};
|
||||||
|
|
||||||
heroRes.secret = hero.getSecretData();
|
heroRes.secret = hero.getSecretData();
|
||||||
|
heroRes.profile.flags = hero.getFlagData();
|
||||||
|
|
||||||
res.respond(200, heroRes);
|
res.respond(200, heroRes);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { model as Group } from '../../models/group';
|
import { model as Group } from '../../models/group';
|
||||||
import { model as Challenge } from '../../models/challenge';
|
import { model as Challenge } from '../../models/challenge';
|
||||||
import {
|
import {
|
||||||
|
BadRequest,
|
||||||
NotFound,
|
NotFound,
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../libs/errors';
|
} from '../../libs/errors';
|
||||||
@@ -27,6 +28,7 @@ import {
|
|||||||
} from '../../models/message';
|
} from '../../models/message';
|
||||||
import highlightMentions from '../../libs/highlightMentions';
|
import highlightMentions from '../../libs/highlightMentions';
|
||||||
import { handleGetMembersForChallenge } from '../../libs/challenges/handleGetMembersForChallenge';
|
import { handleGetMembersForChallenge } from '../../libs/challenges/handleGetMembersForChallenge';
|
||||||
|
import { chatReporterFactory } from '../../libs/chatReporting/chatReporterFactory';
|
||||||
|
|
||||||
const { achievements } = common;
|
const { achievements } = common;
|
||||||
|
|
||||||
@@ -777,4 +779,92 @@ api.transferGems = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /api/v3/members/:memberId/flag Flag (report) a user
|
||||||
|
* @apiDescription Sends an email to staff about another user or their profile
|
||||||
|
* @apiName FlagUser
|
||||||
|
* @apiGroup Members
|
||||||
|
*
|
||||||
|
* @apiParam (Path) {UUID} memberId The unique ID of the user being flagged
|
||||||
|
* @apiParam (Body) {String} [comment] explain why the user was flagged
|
||||||
|
* @apiParam (Body) {String} [source] URL or view from which the user was flagged
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data The flagged user
|
||||||
|
* @apiSuccess {UUID} data.id The id of the flagged user
|
||||||
|
* @apiSuccess {String} data.username The username of the flagged user
|
||||||
|
* @apiSuccess {Object} data.profile The flagged user's profile information
|
||||||
|
* @apiSuccess {String} data.profile.blurb Text of the flagged user's profile bio
|
||||||
|
* @apiSuccess {Object} data.profile.flags Data about flags the profile has received.
|
||||||
|
* Restricted to the reporting user's own flag
|
||||||
|
* unless the reporting user is a moderator.
|
||||||
|
* Each key is a UUID, and fields are comment,
|
||||||
|
* source, and timestamp.
|
||||||
|
* @apiSuccess {String} data.profile.imageUrl URL of the flagged user's profile image
|
||||||
|
* @apiSuccess {String} data.profile.name The flagged user's display name
|
||||||
|
*
|
||||||
|
* @apiError (400) {BadRequest} AlreadyFlagged A profile cannot be flagged
|
||||||
|
* more than once by the same user.
|
||||||
|
* @apiError (400) {BadRequest} MemberIdRequired The `memberId` param is required
|
||||||
|
* and must be a valid `UUID`.
|
||||||
|
* @apiError (404) {NotFound} UserWithIdNotFound The `memberId` param did not
|
||||||
|
* belong to an existing user.
|
||||||
|
*/
|
||||||
|
api.flagUser = {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/members/:memberId/flag',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
async handler (req, res) {
|
||||||
|
const chatReporter = chatReporterFactory('User', req, res);
|
||||||
|
const flaggedUser = await chatReporter.flag();
|
||||||
|
res.respond(200, flaggedUser);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /api/v3/members/:memberId/clear-flags Delete flags from a user
|
||||||
|
* @apiDescription Removes any abuse reports flagged on a user profile.
|
||||||
|
* @apiPermission Admin
|
||||||
|
* @apiName ClearUserFlags
|
||||||
|
* @apiGroup Members
|
||||||
|
*
|
||||||
|
* @apiParam (Path) {UUID} memberId The unique ID of the flagged user to reset
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data An empty object
|
||||||
|
*
|
||||||
|
* @apiError (400) {BadRequest} MemberIdRequired The `memberId` param is required
|
||||||
|
* and must be a valid `UUID`.
|
||||||
|
* @apiError (400) {BadRequest} MustBeAdmin Must be a moderator to use this route
|
||||||
|
* @apiError (404) {NotFound} UserWithIdNotFound The `memberId` param did not
|
||||||
|
* belong to an existing user.
|
||||||
|
*/
|
||||||
|
|
||||||
|
api.clearUserFlags = {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/members/:memberId/clear-flags',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
async handler (req, res) {
|
||||||
|
const { user } = res.locals;
|
||||||
|
const { memberId } = req.params;
|
||||||
|
|
||||||
|
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
|
||||||
|
const validationErrors = req.validationErrors();
|
||||||
|
if (validationErrors) throw validationErrors;
|
||||||
|
|
||||||
|
if (!user.hasPermission('moderator')) {
|
||||||
|
throw new BadRequest('Only a moderator may clear reports from a profile.');
|
||||||
|
}
|
||||||
|
const flaggedUser = await User.findOne(
|
||||||
|
{ _id: memberId },
|
||||||
|
{ profile: 1 },
|
||||||
|
).exec();
|
||||||
|
if (!flaggedUser) {
|
||||||
|
throw new NotFound(res.t('userWithIDNotFound', { userId: memberId }));
|
||||||
|
}
|
||||||
|
flaggedUser.profile.flags = {};
|
||||||
|
await flaggedUser.save();
|
||||||
|
|
||||||
|
res.respond(200, {});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import GroupChatReporter from './groupChatReporter';
|
import GroupChatReporter from './groupChatReporter';
|
||||||
import InboxChatReporter from './inboxChatReporter';
|
import InboxChatReporter from './inboxChatReporter';
|
||||||
|
import ProfileReporter from './profileReporter';
|
||||||
|
|
||||||
export function chatReporterFactory (type, req, res) { // eslint-disable-line import/prefer-default-export, max-len
|
export function chatReporterFactory (type, req, res) { // eslint-disable-line import/prefer-default-export, max-len
|
||||||
if (type === 'Group') {
|
if (type === 'Group') {
|
||||||
return new GroupChatReporter(req, res);
|
return new GroupChatReporter(req, res);
|
||||||
} if (type === 'Inbox') {
|
} if (type === 'Inbox') {
|
||||||
return new InboxChatReporter(req, res);
|
return new InboxChatReporter(req, res);
|
||||||
|
} if (type === 'Profile' || type === 'User') {
|
||||||
|
return new ProfileReporter(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Invalid chat reporter type.');
|
throw new Error('Invalid chat reporter type.');
|
||||||
|
|||||||
@@ -6,17 +6,12 @@ import {
|
|||||||
BadRequest,
|
BadRequest,
|
||||||
NotFound,
|
NotFound,
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
import { sendTxn } from '../email';
|
|
||||||
import * as slack from '../slack';
|
import * as slack from '../slack';
|
||||||
import { model as Group } from '../../models/group';
|
import { model as Group } from '../../models/group';
|
||||||
import { chatModel as Chat } from '../../models/message';
|
import { chatModel as Chat } from '../../models/message';
|
||||||
import apiError from '../apiError';
|
import apiError from '../apiError';
|
||||||
|
|
||||||
const COMMUNITY_MANAGER_EMAIL = nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL');
|
const COMMUNITY_MANAGER_EMAIL = nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL');
|
||||||
const FLAG_REPORT_EMAILS = nconf
|
|
||||||
.get('FLAG_REPORT_EMAIL')
|
|
||||||
.split(',')
|
|
||||||
.map(email => ({ email, canSend: true }));
|
|
||||||
const USER_AGE_FOR_FLAGGING = 3; // accounts less than this many days old don't increment flagCount
|
const USER_AGE_FOR_FLAGGING = 3; // accounts less than this many days old don't increment flagCount
|
||||||
|
|
||||||
export default class GroupChatReporter extends ChatReporter {
|
export default class GroupChatReporter extends ChatReporter {
|
||||||
@@ -51,13 +46,6 @@ export default class GroupChatReporter extends ChatReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async notify (group, message, userComment, automatedComment = '') {
|
async notify (group, message, userComment, automatedComment = '') {
|
||||||
let emailVariables = await this.getMessageVariables(group, message);
|
|
||||||
emailVariables = emailVariables.concat([
|
|
||||||
{ name: 'REPORTER_COMMENT', content: userComment || '' },
|
|
||||||
]);
|
|
||||||
|
|
||||||
sendTxn(FLAG_REPORT_EMAILS, 'flag-report-to-mods-with-comments', emailVariables);
|
|
||||||
|
|
||||||
slack.sendFlagNotification({
|
slack.sendFlagNotification({
|
||||||
authorEmail: this.authorEmail,
|
authorEmail: this.authorEmail,
|
||||||
flagger: this.user,
|
flagger: this.user,
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import nconf from 'nconf';
|
|
||||||
import { model as User } from '../../models/user';
|
import { model as User } from '../../models/user';
|
||||||
|
|
||||||
import ChatReporter from './chatReporter';
|
import ChatReporter from './chatReporter';
|
||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
import { getUserInfo, sendTxn } from '../email';
|
import { getUserInfo } from '../email';
|
||||||
import * as slack from '../slack';
|
import * as slack from '../slack';
|
||||||
import apiError from '../apiError';
|
import apiError from '../apiError';
|
||||||
|
|
||||||
import * as inboxLib from '../inbox';
|
import * as inboxLib from '../inbox';
|
||||||
import { getAuthorEmailFromMessage } from '../chat';
|
import { getAuthorEmailFromMessage } from '../chat';
|
||||||
|
|
||||||
const FLAG_REPORT_EMAILS = nconf.get('FLAG_REPORT_EMAIL')
|
|
||||||
.split(',')
|
|
||||||
.map(email => ({ email, canSend: true }));
|
|
||||||
|
|
||||||
export default class InboxChatReporter extends ChatReporter {
|
export default class InboxChatReporter extends ChatReporter {
|
||||||
constructor (req, res) {
|
constructor (req, res) {
|
||||||
super(req, res);
|
super(req, res);
|
||||||
@@ -49,13 +44,6 @@ export default class InboxChatReporter extends ChatReporter {
|
|||||||
_id: 'N/A',
|
_id: 'N/A',
|
||||||
};
|
};
|
||||||
|
|
||||||
let emailVariables = await this.getMessageVariables(group, message);
|
|
||||||
emailVariables = emailVariables.concat([
|
|
||||||
{ name: 'REPORTER_COMMENT', content: userComment || '' },
|
|
||||||
]);
|
|
||||||
|
|
||||||
sendTxn(FLAG_REPORT_EMAILS, 'flag-report-to-mods-with-comments', emailVariables);
|
|
||||||
|
|
||||||
slack.sendInboxFlagNotification({
|
slack.sendInboxFlagNotification({
|
||||||
messageUserEmail: this.messageUserEmail,
|
messageUserEmail: this.messageUserEmail,
|
||||||
flagger: this.user,
|
flagger: this.user,
|
||||||
|
|||||||
81
website/server/libs/chatReporting/profileReporter.js
Normal file
81
website/server/libs/chatReporting/profileReporter.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { model as User } from '../../models/user';
|
||||||
|
import * as slack from '../slack';
|
||||||
|
|
||||||
|
import ChatReporter from './chatReporter';
|
||||||
|
import {
|
||||||
|
BadRequest,
|
||||||
|
NotFound,
|
||||||
|
} from '../errors';
|
||||||
|
|
||||||
|
export default class ProfileReporter extends ChatReporter {
|
||||||
|
constructor (req, res) {
|
||||||
|
super(req, res);
|
||||||
|
|
||||||
|
this.user = res.locals.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async validate () {
|
||||||
|
this.req.checkParams('memberId', this.res.t('memberIdRequired')).notEmpty().isUUID();
|
||||||
|
|
||||||
|
const validationErrors = this.req.validationErrors();
|
||||||
|
if (validationErrors) throw validationErrors;
|
||||||
|
|
||||||
|
const flaggedUser = await User.findOne(
|
||||||
|
{ _id: this.req.params.memberId },
|
||||||
|
{ auth: 1, profile: 1 },
|
||||||
|
).exec();
|
||||||
|
if (!flaggedUser) {
|
||||||
|
throw new NotFound(this.res.t('userWithIDNotFound', { userId: this.req.params.memberId }));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flaggedUser.profile.flags && flaggedUser.profile.flags[this.user._id]
|
||||||
|
&& !this.user.hasPermission('moderator')) {
|
||||||
|
throw new BadRequest('A profile can not be flagged more than once by the same user.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { comment, source } = this.req.body;
|
||||||
|
|
||||||
|
return { flaggedUser, comment, source };
|
||||||
|
}
|
||||||
|
|
||||||
|
async flagProfile (flaggedUser, comment, source) {
|
||||||
|
const timestamp = new Date();
|
||||||
|
// Log user ids that have flagged the account
|
||||||
|
if (!flaggedUser.profile.flags) {
|
||||||
|
flaggedUser.profile.flags = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
flaggedUser.profile.flags[this.user._id] = {
|
||||||
|
comment,
|
||||||
|
source,
|
||||||
|
timestamp,
|
||||||
|
};
|
||||||
|
flaggedUser.markModified('profile.flags');
|
||||||
|
await flaggedUser.save();
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
notify (flaggedUser, comment, source) {
|
||||||
|
slack.sendProfileFlagNotification({
|
||||||
|
reporter: this.user,
|
||||||
|
flaggedUser,
|
||||||
|
userComment: comment,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async flag () {
|
||||||
|
const { flaggedUser, comment, source } = await this.validate();
|
||||||
|
const timestamp = await this.flagProfile(flaggedUser, comment, source);
|
||||||
|
this.notify(flaggedUser, comment, source);
|
||||||
|
if (!this.user.hasPermission('moderator')) {
|
||||||
|
flaggedUser.profile.flags = {};
|
||||||
|
flaggedUser.profile.flags[this.user._id] = {
|
||||||
|
comment,
|
||||||
|
source,
|
||||||
|
timestamp,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return flaggedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -176,6 +176,43 @@ function sendInboxFlagNotification ({
|
|||||||
.catch(err => logger.error(err, 'Error while sending flag data to Slack.'));
|
.catch(err => logger.error(err, 'Error while sending flag data to Slack.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendProfileFlagNotification ({
|
||||||
|
reporter,
|
||||||
|
flaggedUser,
|
||||||
|
userComment,
|
||||||
|
source,
|
||||||
|
}) {
|
||||||
|
const title = 'User Profile Report';
|
||||||
|
const titleLink = `${BASE_URL}/profile/${flaggedUser._id}`;
|
||||||
|
let text = `@${reporter.auth.local.username} (${reporter._id}; language: ${reporter.preferences.language}) flagged @${flaggedUser.auth.local.username}'s profile from ${source}`;
|
||||||
|
if (userComment) {
|
||||||
|
text += ` and commented: ${userComment}`;
|
||||||
|
}
|
||||||
|
let profileData = `Display Name: ${flaggedUser.profile.name}`;
|
||||||
|
if (flaggedUser.profile.imageUrl) {
|
||||||
|
profileData += `\n\nImage URL: ${flaggedUser.profile.imageUrl}`;
|
||||||
|
}
|
||||||
|
if (flaggedUser.profile.blurb) {
|
||||||
|
profileData += `\n\nAbout: ${flaggedUser.profile.blurb}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
flagSlack
|
||||||
|
.send({
|
||||||
|
text,
|
||||||
|
attachments: [{
|
||||||
|
fallback: 'Flag Profile',
|
||||||
|
color: 'danger',
|
||||||
|
title,
|
||||||
|
title_link: titleLink,
|
||||||
|
text: profileData,
|
||||||
|
mrkdwn_in: [
|
||||||
|
'text',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
.catch(err => logger.error(err, 'Error while sending flag data to Slack.'));
|
||||||
|
}
|
||||||
|
|
||||||
function sendSubscriptionNotification ({
|
function sendSubscriptionNotification ({
|
||||||
buyer,
|
buyer,
|
||||||
recipient,
|
recipient,
|
||||||
@@ -302,6 +339,7 @@ function sendSlurNotification ({
|
|||||||
export {
|
export {
|
||||||
sendFlagNotification,
|
sendFlagNotification,
|
||||||
sendInboxFlagNotification,
|
sendInboxFlagNotification,
|
||||||
|
sendProfileFlagNotification,
|
||||||
sendSubscriptionNotification,
|
sendSubscriptionNotification,
|
||||||
sendShadowMutedPostNotification,
|
sendShadowMutedPostNotification,
|
||||||
sendSlurNotification,
|
sendSlurNotification,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ schema.plugin(baseModel, {
|
|||||||
// noSet is not used as updating uses a whitelist and creating only accepts
|
// noSet is not used as updating uses a whitelist and creating only accepts
|
||||||
// specific params (password, email, username, ...)
|
// specific params (password, email, username, ...)
|
||||||
noSet: [],
|
noSet: [],
|
||||||
private: ['auth.local.hashed_password', 'auth.local.passwordHashMethod', 'auth.local.salt', '_cronSignature', '_ABtests', 'secret'],
|
private: ['auth.local.hashed_password', 'auth.local.passwordHashMethod', 'auth.local.salt', '_cronSignature', '_ABtests', 'secret', 'profile.flags'],
|
||||||
toJSONTransform: function userToJSON (plainObj, originalDoc) {
|
toJSONTransform: function userToJSON (plainObj, originalDoc) {
|
||||||
plainObj._tmp = originalDoc._tmp; // be sure to send down drop notifs
|
plainObj._tmp = originalDoc._tmp; // be sure to send down drop notifs
|
||||||
|
|
||||||
|
|||||||
@@ -548,6 +548,12 @@ schema.methods.getSecretData = function getSecretData () {
|
|||||||
return user.secret;
|
return user.secret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
schema.methods.getFlagData = function getFlagData () {
|
||||||
|
const user = this;
|
||||||
|
|
||||||
|
return user.profile.flags;
|
||||||
|
};
|
||||||
|
|
||||||
schema.methods.updateBalance = async function updateBalance (amount,
|
schema.methods.updateBalance = async function updateBalance (amount,
|
||||||
transactionType,
|
transactionType,
|
||||||
reference,
|
reference,
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ export default new Schema({
|
|||||||
required: true,
|
required: true,
|
||||||
trim: true,
|
trim: true,
|
||||||
},
|
},
|
||||||
|
flags: { $type: Schema.Types.Mixed },
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
hp: { $type: Number, default: shared.maxHealth },
|
hp: { $type: Number, default: shared.maxHealth },
|
||||||
|
|||||||
Reference in New Issue
Block a user