Compare commits

..

75 Commits

Author SHA1 Message Date
Matteo Pagliazzi d9e85b329f 4.156.1 2020-09-10 11:17:54 +02:00
Matteo Pagliazzi 05f22ababc fix(challenge tags); change type to Mixed in preparation for migration 2020-09-10 11:14:09 +02:00
Sabe Jones 9f988acb55 4.156.0 2020-09-08 16:10:36 -05:00
Sabe Jones eec57cb9b8 chore(sprites): compile 2020-09-08 16:10:17 -05:00
Sabe Jones f5eb868763 feat(content): Backgrounds and Armoire items 2020-09-08 16:10:01 -05:00
Sabe Jones d98932e183 4.155.2 2020-09-04 17:30:54 -05:00
Sabe Jones a91c2f7c7c fix(settings): revert axios version due to account delete issue 2020-09-04 17:30:46 -05:00
Sabe Jones 70d057e66c 4.155.1 2020-09-03 17:22:54 -05:00
Sabe Jones b680b6026b fix(teams): don't adjust source task value for rewards Fixes #12523 2020-09-03 10:00:32 -05:00
Matteo Pagliazzi 0c3b16ca74 fix(task modal): make sure task is loaded when template is shown 2020-09-03 16:33:44 +02:00
Melior 7be039a35f Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (706 of 708 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (252 of 252 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (501 of 501 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2135 of 2135 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (703 of 708 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (93 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Italian)

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/

Translated using Weblate (Dutch)

Currently translated at 99.8% (2127 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/

Translated using Weblate (French)

Currently translated at 100.0% (702 of 702 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/

Translated using Weblate (French)

Currently translated at 100.0% (702 of 702 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/

Translated using Weblate (French)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/

Translated using Weblate (Greek)

Currently translated at 73.2% (41 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/el/

Translated using Weblate (Greek)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/el/

Translated using Weblate (Greek)

Currently translated at 100.0% (6 of 6 strings)

Translation: Habitica/Inventory
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/el/

Translated using Weblate (Greek)

Currently translated at 79.8% (1702 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/el/

Translated using Weblate (Greek)

Currently translated at 100.0% (70 of 70 strings)

Translation: Habitica/Contrib
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/el/

Translated using Weblate (Greek)

Currently translated at 100.0% (4 of 4 strings)

Translation: Habitica/Noscript
Translate-URL: https://translate.habitica.com/projects/habitica/noscript/el/

Translated using Weblate (Greek)

Currently translated at 100.0% (27 of 27 strings)

Translation: Habitica/Loginincentives
Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/el/

Translated using Weblate (Czech)

Currently translated at 88.9% (1895 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/cs/

Translated using Weblate (French)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/

Translated using Weblate (French)

Currently translated at 100.0% (702 of 702 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/

Translated using Weblate (Russian)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ru/

Translated using Weblate (Japanese)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ja/

Translated using Weblate (Italian)

Currently translated at 100.0% (328 of 328 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/it/

Translated using Weblate (Russian)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ru/

Translated using Weblate (Russian)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/vi/

Translated using Weblate (English (Pirate))

Currently translated at 87.5% (7 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/en@pirate/

Translated using Weblate (French)

Currently translated at 100.0% (500 of 500 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/fr/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/

Translated using Weblate (French)

Currently translated at 100.0% (134 of 134 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/

Translated using Weblate (English (Pirate))

Currently translated at 85.8% (79 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@pirate/

Translated using Weblate (French)

Currently translated at 100.0% (500 of 500 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/fr/

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/vi/

Translated using Weblate (French)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/fr/

Translated using Weblate (French)

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/fr/

Translated using Weblate (French)

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/

Translated using Weblate (French)

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/

Translated using Weblate (French)

Currently translated at 100.0% (134 of 134 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/

Translated using Weblate (French)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/

Translated using Weblate (French)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/vi/

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/vi/

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/vi/

Translated using Weblate (Vietnamese)

Currently translated at 82.5% (1760 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/vi/

Translated using Weblate (Latin)

Currently translated at 39.6% (25 of 63 strings)

Translation: Habitica/Defaulttasks
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/la/

Translated using Weblate (Russian)

Currently translated at 98.2% (56 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/ru/

Translated using Weblate (Russian)

Currently translated at 100.0% (146 of 146 strings)

Translation: Habitica/Pets
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ru/

Translated using Weblate (Russian)

Currently translated at 100.0% (298 of 298 strings)

Translation: Habitica/Generic
Translate-URL: https://translate.habitica.com/projects/habitica/generic/ru/

Translated using Weblate (Russian)

Currently translated at 99.6% (548 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/

Translated using Weblate (Russian)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/

Translated using Weblate (Russian)

Currently translated at 100.0% (212 of 212 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/

Translated using Weblate (Czech)

Currently translated at 100.0% (212 of 212 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/cs/

Translated using Weblate (English (Pirate))

Currently translated at 88.0% (191 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/en@pirate/

Translated using Weblate (Czech)

Currently translated at 88.3% (1883 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/cs/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/

Translated using Weblate (Japanese)

Currently translated at 91.0% (51 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ja/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hant/

Translated using Weblate (Czech)

Currently translated at 86.7% (1849 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/cs/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hant/

Translated using Weblate (Portuguese)

Currently translated at 87.2% (480 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hant/

Translated using Weblate (Italian)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/en_GB/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hant/

Translated using Weblate (Italian)

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/en_GB/

Translated using Weblate (Czech)

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/cs/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (185 of 185 strings)

Translation: Habitica/Limited
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (500 of 500 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/it/

Translated using Weblate (Turkish)

Currently translated at 80.0% (1706 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/tr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en_GB/

Translated using Weblate (Italian)

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/en_GB/

Translated using Weblate (Italian)

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/en_GB/

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hant/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/it/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en_GB/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 99.5% (216 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ru/

Translated using Weblate (German)

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/de/

Translated using Weblate (Russian)

Currently translated at 95.2% (239 of 251 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hans/

Translated using Weblate (German)

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/de/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (146 of 146 strings)

Translation: Habitica/Pets
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 98.4% (492 of 500 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 96.1% (2048 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2131 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (German)

Currently translated at 99.8% (2128 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/

Translated using Weblate (Chinese (Simplified))

Currently translated at 92.8% (52 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 94.6% (53 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/

Translated using Weblate (German)

Currently translated at 98.2% (55 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/

Translated using Weblate (Turkish)

Currently translated at 99.1% (228 of 230 strings)

Translation: Habitica/Character
Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/

Translated using Weblate (Turkish)

Currently translated at 99.1% (228 of 230 strings)

Translation: Habitica/Character
Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 98.7% (543 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (550 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/

Translated using Weblate (German)

Currently translated at 99.8% (549 of 550 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/

Translated using Weblate (German)

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/de/

Translated using Weblate (Turkish)

Currently translated at 99.5% (229 of 230 strings)

Translation: Habitica/Character
Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/
2020-09-01 19:42:34 +02:00
Sabe Jones 01ae56f944 Merge branch 'release' into develop 2020-09-01 11:10:26 -05:00
Sabe Jones 7b020e133f 4.155.0 2020-09-01 11:09:37 -05:00
Sabe Jones ca413ff41a chore(sprites): compile 2020-09-01 11:08:50 -05:00
Sabe Jones 81eef79da4 feat(content): Mystery Items and Challenges 2020-09-01 11:08:41 -05:00
negue f1469b52f6 hotfix datepicker size 2020-08-31 23:13:31 +02:00
Matteo Pagliazzi ef118f23c2 fix(loading): do not shift loading screen 2020-08-31 16:54:31 +02:00
dependabot-preview[bot] 964861bd6c build(deps-dev): bump axios from 0.19.2 to 0.20.0 (#12492)
Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.20.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.20.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 14:10:32 +02:00
dependabot-preview[bot] 32e9dbe1ed build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#12513)
Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-plugin-unit-mocha)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:25:28 +02:00
dependabot-preview[bot] 466fb4e42e build(deps): bump axios from 0.19.2 to 0.20.0 in /website/client (#12516)
Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.20.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.20.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:24:47 +02:00
dependabot-preview[bot] 8f923f7753 build(deps): bump mongoose from 5.9.29 to 5.10.2 (#12503)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.9.29 to 5.10.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/History.md)
- [Commits](https://github.com/Automattic/mongoose/compare/5.9.29...5.10.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:24:01 +02:00
Matteo Pagliazzi 3bb8db45fd build(deps): bump @vue/cli-plugin-eslint in /website/client (#12510)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-plugin-eslint)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:22:56 +02:00
dependabot-preview[bot] 181317dbff build(deps): bump @vue/cli-plugin-eslint in /website/client
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-plugin-eslint)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-31 11:22:44 +00:00
dependabot-preview[bot] 73a7ef8b2c build(deps): bump vue and vue-template-compiler in /website/client (#12511)
Bumps [vue](https://github.com/vuejs/vue) and [vue-template-compiler](https://github.com/vuejs/vue). These dependencies needed to be updated together.

Updates `vue` from 2.6.11 to 2.6.12
- [Release notes](https://github.com/vuejs/vue/releases)
- [Commits](https://github.com/vuejs/vue/compare/v2.6.11...v2.6.12)

Updates `vue-template-compiler` from 2.6.11 to 2.6.12
- [Release notes](https://github.com/vuejs/vue/releases)
- [Commits](https://github.com/vuejs/vue/compare/v2.6.11...v2.6.12)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:21:15 +02:00
dependabot-preview[bot] 206e3468f4 build(deps): bump vuedraggable from 2.24.0 to 2.24.1 in /website/client (#12520)
Bumps [vuedraggable](https://github.com/SortableJS/Vue.Draggable) from 2.24.0 to 2.24.1.
- [Release notes](https://github.com/SortableJS/Vue.Draggable/releases)
- [Commits](https://github.com/SortableJS/Vue.Draggable/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:17:49 +02:00
dependabot-preview[bot] 77fde9d73f build(deps): bump amplitude-js from 7.1.0 to 7.1.1 in /website/client (#12517)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/amplitude/amplitude-javascript/releases)
- [Changelog](https://github.com/amplitude/Amplitude-JavaScript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/amplitude/amplitude-javascript/compare/v7.1.0...v7.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:17:25 +02:00
dependabot-preview[bot] c1d4bcbac3 build(deps): bump @vue/cli-service in /website/client (#12514)
Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-service)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:17:05 +02:00
dependabot-preview[bot] e98d0d88d9 build(deps): bump @storybook/addon-notes in /website/client (#12512)
Bumps [@storybook/addon-notes](https://github.com/storybookjs/storybook/tree/HEAD/addons/notes) from 5.3.19 to 5.3.21.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/v5.3.21/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v5.3.21/addons/notes)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:16:39 +02:00
dependabot-preview[bot] fc3a1dd93d build(deps): bump @vue/cli-plugin-router in /website/client (#12509)
Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-plugin-router)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:16:07 +02:00
dependabot-preview[bot] 897155e4c8 build(deps): bump @vue/cli-plugin-babel in /website/client (#12506)
Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.4/packages/@vue/cli-plugin-babel)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:15:55 +02:00
dependabot-preview[bot] 689f5ad634 build(deps): bump superagent from 6.0.0 to 6.1.0 (#12502)
Bumps [superagent](https://github.com/visionmedia/superagent) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/visionmedia/superagent/releases)
- [Changelog](https://github.com/visionmedia/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/visionmedia/superagent/compare/v6.0.0...v6.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 13:15:45 +02:00
negue aa1ea74daa datepicker: add clear button (#12480)
* datepicker: add clear button

* use close icon instead of "x" as text
2020-08-29 17:22:31 +02:00
Bart Enkelaar 1b301e9c68 issue(11266) - Restyle level-up modal with sparkles (#12486)
* issue(11266) - Restyle level-up modal with sparkles

* issue(11266) - Add reward display to level up modal

At levels 15, 30, 40 and 60 the earned quests are now shown in the level-up modal.

* issue(11266) - Simplify css and don't use custom footer

* issue(11266) - Don't show pink bars and use colour variables
2020-08-29 16:33:06 +02:00
Matteo Pagliazzi c00b2247d4 fix #12498: do not score task when using a skill 2020-08-29 16:23:32 +02:00
Alys 88de5552a0 change blocked message 2020-08-29 18:03:59 +10:00
Sabe Jones 917c68d51f 4.154.1 2020-08-27 14:44:49 -05:00
Sabe Jones 44e438303a chore(news): Last Chance 2020-08-27 14:44:43 -05:00
Sabe Jones 7eeddcb033 Merge branch 'release' into develop 2020-08-25 16:05:40 -05:00
Sabe Jones 2fb8e16e8f 4.154.0 2020-08-25 16:05:13 -05:00
Sabe Jones 80ffcddb35 chore(sprites): compile 2020-08-25 16:04:35 -05:00
Sabe Jones f4c453675b feat(content): Wind-Up Potions quest 2020-08-25 16:04:28 -05:00
Alys 5165d491b0 fix some lint warnings (#12488)
* prevent some lint warnings by turning off some rules we don't seem to care about

require-prop-types has 167 violations

require-default-prop has 93 violations

* fix some lint warnings by adding eslint-disable-line comments

* prevent lint warnings by moving vue hooks to a different order

* apply some automatic lint fixes

* fix lint error by making line shorter

* prevent lint warnings from whitespace and @input, @click positioning

* revert 723fa38271

Reenables vue/require-prop-types and vue/require-default-prop
2020-08-25 18:06:39 +02:00
Sara Olson 6559353613 Update faq.json
some more android and ios faq changes
2020-08-25 18:01:37 +02:00
Matteo Pagliazzi 9caacc8f6c fix(links): restore styles changed in bootstrap@4.5.1 2020-08-25 16:17:12 +02:00
dependabot-preview[bot] b21b5a4f4b build(deps): bump jwks-rsa from 1.8.1 to 1.9.0 (#12493)
Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/auth0/node-jwks-rsa/releases)
- [Changelog](https://github.com/auth0/node-jwks-rsa/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jwks-rsa/compare/v1.8.1...v1.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-24 18:23:12 +02:00
dependabot-preview[bot] 21f3e704d4 build(deps): bump @babel/core from 7.11.1 to 7.11.4 (#12489)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.11.1 to 7.11.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.11.4/packages/babel-core)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-24 14:26:14 +02:00
Matteo Pagliazzi d0bc0dbe49 Add API Call to bulk score tasks (#11389)
* Add new API call to complete multiple task scorings in one call

* Improve API response

* Improve saving process

* Improve handling for multiple tasks scored at once

* Handle challenge task errors better

* Improve check for alias

* Improve check for task scorings

* Fix merge errors

* make nodemon ignore content_cache

* Fix completing group tasks

* fix test

* fix tests (again)

* typo

* WIP(a11y): task modal updates

* fix(tasks): borders in modal

* fix(tasks): circley locks

* fix(task-modal): placeholders

* WIP(task-modal): disabled states, hide empty options, +/- restyle

* fix(task-modal): box shadows instead of borders, habit control pointer

* fix(task-modal): button states?

* fix(modal): tighten up layout, new spacing utils

* fix(tasks): more stylin

* fix(tasks): habit hovers

* fix(css): checklist labels, a11y colors

* fix(css): one more missed hover issue

* fix(css): lock Challenges, label fixes

* fix(css): scope input/textarea changes

* fix(style): task tweakies

* fix(style): more button fixage

* WIP(component): start select list story

* working example of a templated selectList

* fix(style): more button corrections

* fix(lint): EOL

* fix(buttons): factor btn-secondary to better override Bootstrap

* fix(styles): standardize more buttons

* wip: difficulty select - style fixes

* selectDifficulty works! 🎉 - fix styles

* change the dropdown-item sizes only for the selectList ones

* selectTranslatedArray

* changed many label margins

* more correct dropdown style

* fix(modals): button corrections

* input-group styling + datetime picker without today button

* Style/margins for "repeat every" - extract selectTag.vue

* working tag-selection / update - cleanup

* fix stories

* fix svg color on create modal (purple)

* fix task modal bottom padding

* correct dropdown shadow

* update dropdown-toggle caret size / color

* fixed checklist style

* sync checked state

* selectTag padding

* fix spacing between positive/negative streak inputs

* toggle-checkbox + fix some spacings

* disable repeat-on when its a groupTask

* fix new checklist-item

* fix toggle-checkbox style - fix difficulty style

* fix checklist ui

* add tags label , when there arent any tags selected

* WORKING select-tag component 🎉

* fix taglist story

* show max 5 items in tag dropdown + "X more" label

* fix datetime clear button

* replace m-b-xs to mb-1 (bootstrap) - fix input-group-text style

* fix styles of advanced settings

* fix delete task styles

* always show grippy on hover of the item

* extract modal-text-input mixin + fix the borders/dropshadow

* fix(spacing): revert most to Bootstrap

* feat(checklists): make local copy of master checklist non-editable
also aggressively update checklists because they weren't syncing??

* fix(checklists): handle add/remove options better

* feat(teams): manager notes field

* fix select/dropdown styles

* input border + icon colors

* delete task underline color

* fix checklist "delete icon" vertical position

* selectTag fixes - normal open/close toggle working again - remove icon color

* fixing icons:

Trash can - Delete
Little X - Remove
Big X - Close
Block - Block

* fix taglist margins / icon sizes

* wip margin overview (in storybook)

* fix routerlink

* remove unused method

* new selectTag style + add markdown inside tagList + scrollable tag selection

* fix selectTag / selectList active border

* fix difficulty select (svg default color)

* fix input padding-left + fix reset habit streak fullwidth / padding + "repeat every" gray text (no border)

* feat(teams): improved approval request > approve > reward flow

* fix(tests): address failures

* fix(lint): oops only

* fix(tasks): short-circuit group related logic

* fix(tasks): more short circuiting

* fix(tasks): more lines, less lint

* fix(tasks): how do i keep missing these

* feat(teams): provide assigning user summary

* fix(teams): don't attempt to record assiging user if not supplied

* fix advanced-settings styling / margin

* fix merge + hide advanced streak settings when none enabled

* fix styles

* set Roboto font for advanced settings

* Add Challenge flag to the tag list

* add tag with enter, when no other tag is found

* fix styles + tag cancel button

* refactor footer / margin

* split repeat fields into option mt-3 groups

* button all the things

* fix(tasks): style updates
* no hover state for non-editable tasks on team board
* keep assign/claim footer on task after requesting approval
* disable more fields on user copy of team task, and remove hover states 
for them

* fix(tasks): functional revisions
* "Claim Rewards" instead of "x" in task approved notif
* Remove default transition supplied by Bootstrap, apply individually to 
some elements
* Delete individual tasks and related notifications when master task 
deleted from team board
* Manager notes now save when supplied at task initial creation
* Can no longer dismiss rewards from approved task by hitting Dismiss 
All

* fix(tasks): clean tasksOrder
also adjust related test expectation

* fix(tests): adjust integration expectations

* fix(test): ratzen fratzen only

* fix lint

* fix tests

* fix(teams): checklist, notes

* handleSharedCompletion: handle error, make sure it is run after the user task has been saved

* fix typo

* correctly handle errors in handleSharedCompletion when approving a task

* fix(teams): improve disabled states

* handleSharedCompletion: do not increase completions by 1 manually to adjust for last approval not saved yet

* revert changes to config.json.example

* fix(teams): more style fixage

* add unit tests for findMultipleByIdOrAlias

* exclude api v4 route from apidocs

* BREAKING(teams): return 202 instead of 401 for approval request

* fix(teams): better taskboard sync
also re-re-fix checklist borders

* scoreTasks: validate body

* fix tests, move string to api errors

* fix(tests): update expectations for breaking change

* start updating api docs, process tasks sequentially to avoid conflicts with user._tmp

* do not crash entire bulk operation in case of errors

* save task only if modified

* fix lint

* undo changes to error handling: either all tasks scoring are successfull or none

* remove stale code

* do not return user._tmp when bulk scoring, it would be the last version only

* make sure user._tmp.leveledUp is not lost when bulk scoring

* rewards tests

* mixed tests

* fix tests, allow scoring the same task multiple times

* finish integration tests

* fix api docs for the bulk score route

* refactor(task-modal): lockable label component

* wip loading spinner

* refactor(teams): move task scoring to mixin

* fix(teams): style corrections

* fix(btn): fix padding to have height of 32px

* implement loading spinner

* remove console.log warnings

* fix(tasks): spacing and wording corrections

* fix(teams): don't bork manager notes

* fix(teams): assignment fix and more approval flow revisions

* WIP(teams): use tag dropdown control for assignment

* finish merge - never throw an error when a group task requires approval (wip - needs tests)

* fix taskModal merge

* fix merge

* fix(task modal): add newline

* fix(column.vue): add newline at end of file

* mvp yesterdaily modal

* fix tests

* fix api docs for bulk scoring group tasks

* separate task scoring and _tmp handling

* handle _tmp when bulk scoring

* rya: close modal before calling cron API, prevents issues with modals

* rya: fix conflicts with other modals

* add sounds, support for group plans, analytics

* use asyncResource for group plans

* fix lint

* streak bonus: add comment about missing in rya

* move yesterdailyModal

* fix issues with level up modals and rya

* add comments for future use, fix level up modals not showing up at levels with a quest drop

* handle errors in rya modal

* bundle quest and crit notifications

Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Phillip Thelen <viirus@pherth.net>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: negue <eugen.bolz@gmail.com>
2020-08-21 11:46:56 +02:00
Matteo Pagliazzi 46b5efcaf6 Allow group plans for private guilds only (#12479)
* hide upgrade button for public guilds

* prevent group plans for public guilds

* fix unit tests

* fix integration and unit tests that assumed group plans could be public guilds

* more unit tests fixes

* more resilient unit test

* more resilient unit test
2020-08-21 11:46:09 +02:00
Melior 633f3df372 Translated using Weblate (Turkish)
Currently translated at 96.3% (209 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/tr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (217 of 217 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (57 of 57 strings)

Translation: Habitica/Spells
Translate-URL: https://translate.habitica.com/projects/habitica/spells/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.9% (2130 of 2131 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.2% (55 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (92 of 92 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
2020-08-20 22:45:40 +02:00
Sabe Jones fa79fb6608 4.153.1 2020-08-20 14:47:26 -05:00
Sabe Jones f9d9df5ddb chore(news): blogs 2020-08-20 14:47:18 -05:00
Sabe Jones 8dbbfcd3a1 Scheduling summary line for team Dailies and To Do's (#12439)
* WIP(dailies): summary sentence draft

* fix(dailies): hide summarized fields, handle future Daily start date

* fix(dailies): don't apply summary sentence to Challenges
...for the sake of non-English users

* fix(dailies): tweak date x Challenge logic

* refactor(dailies): use native JS forEach
2020-08-20 14:12:05 -05:00
Matteo Pagliazzi 9a07ba7417 Better XSS Fix (#12483)
* Revert "fix(test): adjust expectations"

This reverts commit 205436d5b1.

* Revert "fix(escaping): global inoffensive apostrophe"

This reverts commit 2b8f94b244.

* change <%- to <%=

* fix interpolation only where necessary

* remove unused variable
2020-08-20 13:41:46 -05:00
Phillip Thelen 8248c4ca4e Update faq.json (#12484) 2020-08-19 19:59:48 +02:00
Sabe Jones 0e9ac6d4f2 Merge branch 'release' into develop 2020-08-18 15:29:03 -05:00
Sabe Jones 56df62cf49 4.153.0 2020-08-18 15:27:12 -05:00
Sabe Jones eb16966953 fix(news): image 2020-08-18 15:26:54 -05:00
Sabe Jones 6255c5dcc7 feat(content): golden achievements 2020-08-18 15:13:06 -05:00
Matteo Pagliazzi 60ffc1fdaf fix(mongoose): revert to 5.9.29 2020-08-17 13:08:50 +02:00
Alexander Colen 0cfe0473b9 Remove Tavern from API v3 list of guilds when 'guild' or 'publicGuilds' type parameter get added. (Fixes #12407) (#12438)
* Excluding tavern from showing up in GET /groups API when 'guilds' or 'publicGuilds' type parameter is included.

* Fixed test errors.

* Resolved pull request #12438 issues.

Moved Tavern exclusion to Group model, removed Group controller back to the original and resolved test failures.
2020-08-17 12:38:07 +02:00
Matteo Pagliazzi 10f89c8d79 chore(vue deps): upgrade 2020-08-17 09:41:42 +02:00
dependabot-preview[bot] 0692eb10cc build(deps): bump lodash from 4.17.19 to 4.17.20 (#12461)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.20.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.20)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:30:30 +02:00
dependabot-preview[bot] 4ac160ab21 build(deps): bump lodash from 4.17.19 to 4.17.20 in /website/client (#12468)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.20.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.20)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:28:54 +02:00
dependabot-preview[bot] dc5163e8a0 build(deps): bump vue-router from 3.4.2 to 3.4.3 in /website/client (#12478)
Bumps [vue-router](https://github.com/vuejs/vue-router) from 3.4.2 to 3.4.3.
- [Release notes](https://github.com/vuejs/vue-router/releases)
- [Changelog](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-router/compare/v3.4.2...v3.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:28:22 +02:00
dependabot-preview[bot] d850b50009 build(deps): bump winston-loggly-bulk from 3.1.0 to 3.1.1 (#12465)
Bumps [winston-loggly-bulk](https://github.com/loggly/winston-loggly-bulk) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/loggly/winston-loggly-bulk/releases)
- [Commits](https://github.com/loggly/winston-loggly-bulk/compare/v3.1.0...v3.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:27:09 +02:00
dependabot-preview[bot] 65e00ef784 build(deps-dev): bump sinon from 9.0.2 to 9.0.3 (#12467)
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.0.2 to 9.0.3.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v9.0.2...v9.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:26:40 +02:00
dependabot-preview[bot] fd11adbb82 build(deps): bump apidoc from 0.24.0 to 0.25.0 (#12466)
Bumps [apidoc](https://github.com/apidoc/apidoc) from 0.24.0 to 0.25.0.
- [Release notes](https://github.com/apidoc/apidoc/releases)
- [Changelog](https://github.com/apidoc/apidoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apidoc/apidoc/compare/0.24.0...0.25.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:26:31 +02:00
dependabot-preview[bot] 4d64e299ef build(deps): bump mongoose from 5.9.27 to 5.10.0 (#12463)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.9.27 to 5.10.0.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/History.md)
- [Commits](https://github.com/Automattic/mongoose/compare/5.9.27...5.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 09:26:02 +02:00
Sabe Jones 29c21f09e1 4.152.3 2020-08-15 12:16:52 -05:00
Sabe Jones 205436d5b1 fix(test): adjust expectations 2020-08-15 11:56:47 -05:00
Sabe Jones 2b8f94b244 fix(escaping): global inoffensive apostrophe 2020-08-15 10:27:37 -05:00
Sabe Jones 30cedad9b2 4.152.2 2020-08-14 11:18:44 -05:00
Sabe Jones 3a67a36031 fix(escaping): Armoire and boss messages 2020-08-14 11:04:21 -05:00
Sabe Jones 9d645c1c2e fix(merge): missing string 2020-08-13 17:38:05 -05:00
Sabe Jones 6ee4c9870a fix(merge): missing string 2020-08-13 17:27:51 -05:00
1928 changed files with 94758 additions and 90933 deletions
+1
View File
@@ -38,6 +38,7 @@ yarn.lock
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
/.vscode
# webstorm fake webpack for path intellisense
+3 -3
View File
@@ -48,17 +48,17 @@ gulp.task('build:prepare-mongo', async () => {
return;
}
console.log('MongoDB data folder is missing, setting up.');
console.log('MongoDB data folder is missing, setting up.'); // eslint-disable-line no-console
// use run-rs without --keep, kill it as soon as the replica set starts
const runRsProcess = spawn('run-rs', ['-v', '4.2.8', '-l', 'ubuntu1804', '--dbpath', 'mongodb-data', '--number', '1', '--quiet']);
for await (const chunk of runRsProcess.stdout) {
const stringChunk = chunk.toString();
console.log(stringChunk);
console.log(stringChunk); // eslint-disable-line no-console
// kills the process after the replica set is setup
if (stringChunk.includes('Started replica set')) {
console.log('MongoDB setup correctly.');
console.log('MongoDB setup correctly.'); // eslint-disable-line no-console
runRsProcess.kill();
}
}
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20200218_pet_color_achievements';
const MIGRATION_NAME = '20200818_pet_color_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
@@ -14,31 +14,31 @@ async function updateUser (user) {
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['Wolf-CottonCandyPink'] > 0
&& pets['TigerCub-CottonCandyPink'] > 0
&& pets['PandaCub-CottonCandyPink'] > 0
&& pets['LionCub-CottonCandyPink'] > 0
&& pets['Fox-CottonCandyPink'] > 0
&& pets['FlyingPig-CottonCandyPink'] > 0
&& pets['Dragon-CottonCandyPink'] > 0
&& pets['Cactus-CottonCandyPink'] > 0
&& pets['BearCub-CottonCandyPink'] > 0) {
set['achievements.tickledPink'] = true;
if (pets['Wolf-Golden'] > 0
&& pets['TigerCub-Golden'] > 0
&& pets['PandaCub-Golden'] > 0
&& pets['LionCub-Golden'] > 0
&& pets['Fox-Golden'] > 0
&& pets['FlyingPig-Golden'] > 0
&& pets['Dragon-Golden'] > 0
&& pets['Cactus-Golden'] > 0
&& pets['BearCub-Golden'] > 0) {
set['achievements.goodAsGold'] = true;
}
}
if (user && user.items && user.items.mounts) {
const mounts = user.items.mounts;
if (mounts['Wolf-CottonCandyPink']
&& mounts['TigerCub-CottonCandyPink']
&& mounts['PandaCub-CottonCandyPink']
&& mounts['LionCub-CottonCandyPink']
&& mounts['Fox-CottonCandyPink']
&& mounts['FlyingPig-CottonCandyPink']
&& mounts['Dragon-CottonCandyPink']
&& mounts['Cactus-CottonCandyPink']
&& mounts['BearCub-CottonCandyPink'] ) {
set['achievements.rosyOutlook'] = true;
if (mounts['Wolf-Golden']
&& mounts['TigerCub-Golden']
&& mounts['PandaCub-Golden']
&& mounts['LionCub-Golden']
&& mounts['Fox-Golden']
&& mounts['FlyingPig-Golden']
&& mounts['Dragon-Golden']
&& mounts['Cactus-Golden']
&& mounts['BearCub-Golden'] ) {
set['achievements.allThatGlitters'] = true;
}
}
@@ -50,7 +50,7 @@ async function updateUser (user) {
module.exports = async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2020-02-01') },
'auth.timestamps.loggedin': { $gt: new Date('2020-08-01') },
};
const fields = {
+151 -91
View File
@@ -1,6 +1,6 @@
{
"name": "habitica",
"version": "4.152.1",
"version": "4.156.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -23,15 +23,15 @@
}
},
"@babel/core": {
"version": "7.11.1",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz",
"integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz",
"integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.11.0",
"@babel/generator": "^7.11.4",
"@babel/helper-module-transforms": "^7.11.0",
"@babel/helpers": "^7.10.4",
"@babel/parser": "^7.11.1",
"@babel/parser": "^7.11.4",
"@babel/template": "^7.10.4",
"@babel/traverse": "^7.11.0",
"@babel/types": "^7.11.0",
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/generator": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz",
"integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz",
"integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==",
"requires": {
"@babel/types": "^7.11.0",
"jsesc": "^2.5.1",
@@ -78,9 +78,9 @@
}
},
"@babel/parser": {
"version": "7.11.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz",
"integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA=="
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
"integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA=="
},
"@babel/traverse": {
"version": "7.11.0",
@@ -1159,9 +1159,9 @@
"integrity": "sha512-n4J+zu52VdY43kdi/XdI9DzuMr1Mur8zFL5ZRG2opCans9aiFwkPxHYFEb5Xgy7n1Z4K6WfI4FpqUqsh3E8BPQ=="
},
"@sinonjs/commons": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz",
"integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
"integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
@@ -1187,9 +1187,9 @@
}
},
"@sinonjs/samsam": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz",
"integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.1.0.tgz",
"integrity": "sha512-42nyaQOVunX5Pm6GRJobmzbS7iLI+fhERITnETXzzwDZh+TtDr/Au3yAvXVjFmZ4wEUaE4Y3NFZfKv0bV0cbtg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.6.0",
@@ -1328,9 +1328,9 @@
}
},
"@types/express-serve-static-core": {
"version": "4.17.8",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz",
"integrity": "sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==",
"version": "4.17.9",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz",
"integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==",
"requires": {
"@types/node": "*",
"@types/qs": "*",
@@ -1389,9 +1389,9 @@
}
},
"@types/mime": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz",
"integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q=="
},
"@types/minimatch": {
"version": "3.0.3",
@@ -1441,9 +1441,9 @@
"optional": true
},
"@types/qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA=="
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ=="
},
"@types/range-parser": {
"version": "1.2.3",
@@ -1464,9 +1464,9 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
},
"@types/serve-static": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz",
"integrity": "sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==",
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
"integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
"requires": {
"@types/express-serve-static-core": "*",
"@types/mime": "*"
@@ -1698,37 +1698,69 @@
}
},
"apidoc": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.24.0.tgz",
"integrity": "sha512-1aKEMOJaX9coPTwbVcDtCcxtv7VIhR6YEWxWMtoKouYaaMqmScTBikq8umIH8pjr77F2AjrNWFiLhfwsHLsvkA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.25.0.tgz",
"integrity": "sha512-5g9fp8OffXZOdBTzm4BBvV5Vw54s+NmKnGZIUKuH+gRTqqJuRJpcGN6sz6WnjJ+NcvXhB7rIRp6FhtJahazx2Q==",
"requires": {
"apidoc-core": "^0.11.1",
"apidoc-core": "^0.12.0",
"commander": "^2.20.0",
"fs-extra": "^8.1.0",
"fs-extra": "^9.0.1",
"handlebars": "^4.7.6",
"lodash": "^4.17.19",
"markdown-it": "^10.0.0",
"lodash": "^4.17.20",
"markdown-it": "^11.0.0",
"nodemon": "^2.0.4",
"winston": "^3.3.3"
},
"dependencies": {
"linkify-it": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz",
"integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"markdown-it": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.0.tgz",
"integrity": "sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg==",
"requires": {
"argparse": "^1.0.7",
"entities": "~2.0.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
}
}
},
"apidoc-core": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.11.1.tgz",
"integrity": "sha512-pt/ICBdFQCZTgL38Aw1XB3G9AajDU1JA5E3yoDEgg0mqbPTCkOL8AyWdysjvNtQS/kkXgSPazCZaZzZYqrPHog==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.12.0.tgz",
"integrity": "sha512-VMhkJWz5IAyvWM0RnEbKNi1qe8se+id3/Ki3H/ePM8ih0KYTfaaSDxqo2w4uIVB1UVVKFvrTWyYUyQs7CEcoKQ==",
"requires": {
"fs-extra": "^8.1.0",
"glob": "^7.1.4",
"iconv-lite": "^0.5.0",
"fs-extra": "^9.0.1",
"glob": "^7.1.6",
"iconv-lite": "^0.6.2",
"klaw-sync": "^6.0.0",
"lodash": "~4.17.15",
"semver": "~6.3.0"
"lodash": "^4.17.20",
"semver": "~7.3.2"
},
"dependencies": {
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
}
}
},
@@ -1784,6 +1816,16 @@
"axios": "^0.19.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1"
},
"dependencies": {
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
}
}
},
"aproba": {
@@ -2071,6 +2113,11 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
},
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -2090,6 +2137,7 @@
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"dev": true,
"requires": {
"follow-redirects": "1.5.10"
}
@@ -5969,13 +6017,14 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
"jsonfile": "^6.0.1",
"universalify": "^1.0.0"
}
},
"fs-minipass": {
@@ -7342,11 +7391,11 @@
"optional": true
},
"iconv-lite": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz",
"integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"ieee754": {
@@ -8242,11 +8291,12 @@
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
"requires": {
"graceful-fs": "^4.1.6"
"graceful-fs": "^4.1.6",
"universalify": "^1.0.0"
}
},
"jsonwebtoken": {
@@ -8325,9 +8375,9 @@
}
},
"jwks-rsa": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.8.1.tgz",
"integrity": "sha512-CcE8ypsATHwGmzELwzeFjLzPBXTXTrMmDYbn92LTQwYsZdOedp+ZIuYTofUdrWreu8CKRuXmhk17+6/li2sR6g==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.9.0.tgz",
"integrity": "sha512-UPCfQQg0s2kF2Ju6UFJrQH73f7MaVN/hKBnYBYOp+X9KN4y6TLChhLtaXS5nRKbZqshwVdrZ9OY63m/Q9CLqcg==",
"requires": {
"@types/express-jwt": "0.0.42",
"axios": "^0.19.2",
@@ -8336,6 +8386,16 @@
"limiter": "^1.1.5",
"lru-memoizer": "^2.1.2",
"ms": "^2.1.2"
},
"dependencies": {
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
}
}
},
"jws": {
@@ -8553,9 +8613,9 @@
}
},
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.clonedeep": {
"version": "4.5.0",
@@ -9391,13 +9451,13 @@
}
},
"mongoose": {
"version": "5.9.27",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.27.tgz",
"integrity": "sha512-N8zj4pj9J2xJ2BnQ4NiIHEtmjPldtbmbEZOMz4phLTQr3KFWPR0T0I6EzQxNioHwmDbHD4VFzbEd755oD2SJxA==",
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.2.tgz",
"integrity": "sha512-VO5eZawEMFh2gx9XPg9ZafzFg5eIVs4R7PW6kK1MFqBq34YD7GomkalYWVt02HctvTPDI1mkXsm52LXNZR1NxA==",
"requires": {
"bson": "^1.1.4",
"kareem": "2.3.1",
"mongodb": "3.5.10",
"mongodb": "3.6.0",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.7.0",
"mquery": "3.2.2",
@@ -9409,18 +9469,18 @@
},
"dependencies": {
"bl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"mongodb": {
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.10.tgz",
"integrity": "sha512-p/C48UvTU/dr/PQEDKfb9DsCVDJWXGmdJNFC+u5FPmTQVtog69X6D8vrWHz+sJx1zJnd96sjdh9ueo7bx2ILTw==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.0.tgz",
"integrity": "sha512-/XWWub1mHZVoqEsUppE0GV7u9kanLvHxho6EvBxQbShXTKYF9trhZC2NzbulRGeG7xMJHD8IOWRcdKx5LPjAjQ==",
"requires": {
"bl": "^2.2.0",
"bson": "^1.1.4",
@@ -12061,17 +12121,17 @@
}
},
"sinon": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz",
"integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==",
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.3.tgz",
"integrity": "sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.2",
"@sinonjs/fake-timers": "^6.0.1",
"@sinonjs/formatio": "^5.0.1",
"@sinonjs/samsam": "^5.0.3",
"@sinonjs/samsam": "^5.1.0",
"diff": "^4.0.2",
"nise": "^4.0.1",
"nise": "^4.0.4",
"supports-color": "^7.1.0"
},
"dependencies": {
@@ -12774,9 +12834,9 @@
"integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls="
},
"superagent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-6.0.0.tgz",
"integrity": "sha512-gBiyDSUR3zbYO8za+MudSNxMFSOhKcZfQ1Anya1DWzk9R32zl++cYUFHXzP3VnyvQO8h/1/uPPA9FUDDtE+qdA==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz",
"integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==",
"requires": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.2",
@@ -13570,9 +13630,9 @@
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
},
"unpipe": {
"version": "1.0.0",
@@ -14156,9 +14216,9 @@
}
},
"winston-loggly-bulk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/winston-loggly-bulk/-/winston-loggly-bulk-3.1.0.tgz",
"integrity": "sha512-W03eEzM4JIGSTwUHc50SEgWiDcYg2GWMshjqILqFeDfqHDej4f0YCr3kzDIAp/mSbAsoirGITtaQONDkYBM0qg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/winston-loggly-bulk/-/winston-loggly-bulk-3.1.1.tgz",
"integrity": "sha512-W9FxZnwIpOFnO6TIYCc0GZfm8M+I5kkS6y8+s3byPDRTPvVnJJts70CEgqXLEofSQ9hg3A307S+yIuNliSw6Xg==",
"requires": {
"lodash.clonedeep": "^4.5.0",
"node-loggly-bulk": "^2.2.4",
+9 -9
View File
@@ -1,10 +1,10 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.152.1",
"version": "4.156.1",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.11.1",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"@babel/register": "^7.10.3",
"@google-cloud/trace-agent": "^5.1.0",
@@ -12,7 +12,7 @@
"accepts": "^1.3.5",
"amazon-payments": "^0.2.8",
"amplitude": "^3.5.0",
"apidoc": "^0.24.0",
"apidoc": "^0.25.0",
"apn": "^2.2.0",
"apple-auth": "^1.0.6",
"bcrypt": "^5.0.0",
@@ -42,13 +42,13 @@
"in-app-purchase": "^1.11.3",
"js2xmlparser": "^4.0.1",
"jsonwebtoken": "^8.5.1",
"jwks-rsa": "^1.8.1",
"lodash": "^4.17.19",
"jwks-rsa": "^1.9.0",
"lodash": "^4.17.20",
"merge-stream": "^2.0.0",
"method-override": "^3.0.0",
"moment": "^2.27.0",
"moment-recur": "^1.0.7",
"mongoose": "^5.9.27",
"mongoose": "^5.10.2",
"morgan": "^1.10.0",
"nconf": "^0.10.0",
"node-gcm": "^1.0.3",
@@ -67,14 +67,14 @@
"rimraf": "^3.0.2",
"short-uuid": "^3.0.0",
"stripe": "^7.15.0",
"superagent": "^6.0.0",
"superagent": "^6.1.0",
"universal-analytics": "^0.4.23",
"useragent": "^2.1.9",
"uuid": "^8.3.0",
"validator": "^13.1.1",
"vinyl-buffer": "^1.0.1",
"winston": "^3.3.3",
"winston-loggly-bulk": "^3.1.0",
"winston-loggly-bulk": "^3.1.1",
"xml2js": "^0.4.23"
},
"private": true,
@@ -121,7 +121,7 @@
"monk": "^7.3.1",
"require-again": "^2.0.0",
"run-rs": "^0.6.2",
"sinon": "^9.0.2",
"sinon": "^9.0.3",
"sinon-chai": "^3.5.0",
"sinon-stub-promise": "^4.0.0"
},
@@ -31,11 +31,14 @@ describe('#upgradeGroupPlan', () => {
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
await group.save();
user.guilds.push(group._id);
await user.save();
spy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
spy.resolves([]);
@@ -21,11 +21,14 @@ describe('Canceling a subscription for group', () => {
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
await group.save();
user.guilds.push(group._id);
await user.save();
data = {
user,
sub: {
@@ -141,6 +144,8 @@ describe('Canceling a subscription for group', () => {
it('prevents non group leader from managing subscription', async () => {
const groupMember = new User();
groupMember.guilds.push(group._id);
await groupMember.save();
data.user = groupMember;
data.groupId = group._id;
@@ -162,7 +167,9 @@ describe('Canceling a subscription for group', () => {
let updatedGroup = await Group.findById(group._id).exec();
const newLeader = new User();
newLeader.profile.name = 'newLeader';
updatedGroup.leader = newLeader._id;
await newLeader.save();
await updatedGroup.save();
await api.cancelSubscription(data);
@@ -185,8 +192,6 @@ describe('Canceling a subscription for group', () => {
'user-agent': '',
},
};
user.guilds.push(group._id);
await user.save();
expect(group.purchased.plan.planId).to.not.exist;
data.groupId = group._id;
await api.createSubscription(data);
@@ -211,10 +216,15 @@ describe('Canceling a subscription for group', () => {
await api.createSubscription(data);
await api.cancelSubscription(data);
expect(sender.sendTxn).to.be.have.callCount(4);
expect(sender.sendTxn.thirdCall.args[0]._id).to.equal(recipient._id);
expect(sender.sendTxn.thirdCall.args[1]).to.equal('group-member-cancel');
expect(sender.sendTxn.thirdCall.args[2]).to.eql([
expect(sender.sendTxn).to.be.have.callCount(6);
const recipientCall = sender.sendTxn.getCalls().find(call => {
const isRecipient = call.args[0]._id === recipient._id;
const isGroupMemberCancel = call.args[1] === 'group-member-cancel';
return isRecipient && isGroupMemberCancel;
});
expect(recipientCall.args[0]._id).to.equal(recipient._id);
expect(recipientCall.args[1]).to.equal('group-member-cancel');
expect(recipientCall.args[2]).to.eql([
{ name: 'LEADER', content: user.profile.name },
{ name: 'GROUP_NAME', content: group.name },
]);
@@ -246,8 +256,6 @@ describe('Canceling a subscription for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -259,11 +267,13 @@ describe('Canceling a subscription for group', () => {
const group2 = generateGroup({
name: 'test group2',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
data.groupId = group2._id;
await group2.save();
user.guilds.push(group2._id);
await user.save();
recipient.guilds.push(group2._id);
await recipient.save();
@@ -285,8 +295,6 @@ describe('Canceling a subscription for group', () => {
});
it('does cancel a leader subscription with two cancelled group plans', async () => {
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -298,7 +306,7 @@ describe('Canceling a subscription for group', () => {
const group2 = generateGroup({
name: 'test group2',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
user.guilds.push(group2._id);
@@ -12,6 +12,7 @@ import { model as Group } from '../../../../../../website/server/models/group';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import i18n from '../../../../../../website/common/script/i18n';
describe('Purchasing a group plan for group', () => {
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE = 'Google_subscription';
@@ -33,11 +34,14 @@ describe('Purchasing a group plan for group', () => {
group = generateGroup({
name: groupName,
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
await group.save();
user.guilds.push(group._id);
await user.save();
data = {
user,
sub: {
@@ -112,6 +116,30 @@ describe('Purchasing a group plan for group', () => {
expect(updatedGroup.purchased.plan.dateCreated).to.exist;
});
it('does not create a group plan for a public guild', async () => {
const publicGroup = generateGroup({
name: groupName,
type: 'guild',
privacy: 'public',
leader: user._id,
});
await publicGroup.save();
expect(publicGroup.purchased.plan.planId).to.not.exist;
data.groupId = publicGroup._id;
await expect(api.createSubscription(data))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('onlyPrivateGuildsCanUpgrade'),
});
const updatedGroup = await Group.findById(publicGroup._id).exec();
expect(updatedGroup.purchased.plan.planId).to.not.exist;
});
it('sends an email', async () => {
expect(group.purchased.plan.planId).to.not.exist;
data.groupId = group._id;
@@ -148,8 +176,6 @@ describe('Purchasing a group plan for group', () => {
});
it('grants all members of a group a subscription', async () => {
user.guilds.push(group._id);
await user.save();
expect(group.purchased.plan.planId).to.not.exist;
data.groupId = group._id;
@@ -179,17 +205,28 @@ describe('Purchasing a group plan for group', () => {
await api.createSubscription(data);
expect(sender.sendTxn).to.be.calledTwice;
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
expect(sender.sendTxn.firstCall.args[2]).to.eql([
expect(sender.sendTxn).to.be.calledThrice;
const recipientCall = sender.sendTxn.getCalls().find(call => {
const isRecipient = call.args[0]._id === recipient._id;
const isJoin = call.args[1] === 'group-member-join';
return isRecipient && isJoin;
});
expect(recipientCall.args[0]._id).to.equal(recipient._id);
expect(recipientCall.args[1]).to.equal('group-member-join');
expect(recipientCall.args[2]).to.eql([
{ name: 'LEADER', content: user.profile.name },
{ name: 'GROUP_NAME', content: group.name },
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE },
]);
// confirm that the other email sent is appropriate:
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
expect(sender.sendTxn.secondCall.args[1]).to.equal('group-subscription-begins');
const leaderCall = sender.sendTxn.getCalls().find(call => {
const isLeader = call.args[0]._id === group.leader;
const isSubscriptionBegin = call.args[1] === 'group-subscription-begins';
return isLeader && isSubscriptionBegin;
});
expect(leaderCall.args[0]._id).to.equal(group.leader);
expect(leaderCall.args[1]).to.equal('group-subscription-begins');
});
it('sends one email to subscribed member of group, stating subscription is cancelled (Stripe)', async () => {
@@ -205,17 +242,28 @@ describe('Purchasing a group plan for group', () => {
await api.createSubscription(data);
expect(sender.sendTxn).to.be.calledTwice;
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
expect(sender.sendTxn.firstCall.args[2]).to.eql([
expect(sender.sendTxn).to.be.calledThrice;
const recipientCall = sender.sendTxn.getCalls().find(call => {
const isRecipient = call.args[0]._id === recipient._id;
const isJoin = call.args[1] === 'group-member-join';
return isRecipient && isJoin;
});
expect(recipientCall.args[0]._id).to.equal(recipient._id);
expect(recipientCall.args[1]).to.equal('group-member-join');
expect(recipientCall.args[2]).to.eql([
{ name: 'LEADER', content: user.profile.name },
{ name: 'GROUP_NAME', content: group.name },
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
]);
// confirm that the other email sent is not a cancel-subscription email:
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
expect(sender.sendTxn.secondCall.args[1]).to.equal('group-subscription-begins');
const leaderCall = sender.sendTxn.getCalls().find(call => {
const isLeader = call.args[0]._id === group.leader;
const isSubscriptionBegin = call.args[1] === 'group-subscription-begins';
return isLeader && isSubscriptionBegin;
});
expect(leaderCall.args[0]._id).to.equal(group.leader);
expect(leaderCall.args[1]).to.equal('group-subscription-begins');
});
it('sends one email to subscribed member of group, stating subscription is cancelled (Amazon)', async () => {
@@ -238,17 +286,28 @@ describe('Purchasing a group plan for group', () => {
await api.createSubscription(data);
expect(sender.sendTxn).to.be.calledTwice;
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
expect(sender.sendTxn.firstCall.args[2]).to.eql([
expect(sender.sendTxn).to.be.calledThrice;
const recipientCall = sender.sendTxn.getCalls().find(call => {
const isRecipient = call.args[0]._id === recipient._id;
const isJoin = call.args[1] === 'group-member-join';
return isRecipient && isJoin;
});
expect(recipientCall.args[0]._id).to.equal(recipient._id);
expect(recipientCall.args[1]).to.equal('group-member-join');
expect(recipientCall.args[2]).to.eql([
{ name: 'LEADER', content: user.profile.name },
{ name: 'GROUP_NAME', content: group.name },
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
]);
// confirm that the other email sent is not a cancel-subscription email:
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
expect(sender.sendTxn.secondCall.args[1]).to.equal('group-subscription-begins');
const leaderCall = sender.sendTxn.getCalls().find(call => {
const isLeader = call.args[0]._id === group.leader;
const isSubscriptionBegin = call.args[1] === 'group-subscription-begins';
return isLeader && isSubscriptionBegin;
});
expect(leaderCall.args[0]._id).to.equal(group.leader);
expect(leaderCall.args[1]).to.equal('group-subscription-begins');
amzLib.getBillingAgreementDetails.restore();
});
@@ -275,17 +334,28 @@ describe('Purchasing a group plan for group', () => {
await api.createSubscription(data);
expect(sender.sendTxn).to.be.calledTwice;
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-join');
expect(sender.sendTxn.firstCall.args[2]).to.eql([
expect(sender.sendTxn).to.be.calledThrice;
const recipientCall = sender.sendTxn.getCalls().find(call => {
const isRecipient = call.args[0]._id === recipient._id;
const isJoin = call.args[1] === 'group-member-join';
return isRecipient && isJoin;
});
expect(recipientCall.args[0]._id).to.equal(recipient._id);
expect(recipientCall.args[1]).to.equal('group-member-join');
expect(recipientCall.args[2]).to.eql([
{ name: 'LEADER', content: user.profile.name },
{ name: 'GROUP_NAME', content: group.name },
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL },
]);
// confirm that the other email sent is not a cancel-subscription email:
expect(sender.sendTxn.secondCall.args[0]._id).to.equal(group.leader);
expect(sender.sendTxn.secondCall.args[1]).to.equal('group-subscription-begins');
const leaderCall = sender.sendTxn.getCalls().find(call => {
const isLeader = call.args[0]._id === group.leader;
const isSubscriptionBegin = call.args[1] === 'group-subscription-begins';
return isLeader && isSubscriptionBegin;
});
expect(leaderCall.args[0]._id).to.equal(group.leader);
expect(leaderCall.args[1]).to.equal('group-subscription-begins');
paypalPayments.paypalBillingAgreementGet.restore();
paypalPayments.paypalBillingAgreementCancel.restore();
@@ -302,8 +372,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -356,8 +424,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -419,8 +485,6 @@ describe('Purchasing a group plan for group', () => {
data.gift = undefined;
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -455,8 +519,6 @@ describe('Purchasing a group plan for group', () => {
data.gift = undefined;
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -483,8 +545,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -511,8 +571,6 @@ describe('Purchasing a group plan for group', () => {
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -541,8 +599,6 @@ describe('Purchasing a group plan for group', () => {
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -566,8 +622,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await recipient.cancelSubscription();
@@ -589,8 +643,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await recipient.cancelSubscription();
@@ -611,8 +663,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -632,8 +682,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -653,8 +701,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -688,8 +734,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -713,8 +757,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -726,13 +768,15 @@ describe('Purchasing a group plan for group', () => {
const group2 = generateGroup({
name: 'test group2',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
data.groupId = group2._id;
await group2.save();
recipient.guilds.push(group2._id);
await recipient.save();
user.guilds.push(group2._id);
await user.save();
await api.createSubscription(data);
@@ -757,8 +801,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -770,17 +812,22 @@ describe('Purchasing a group plan for group', () => {
const group2 = generateGroup({
name: 'test group2',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
data.groupId = group2._id;
await group2.save();
recipient.guilds.push(group2._id);
await recipient.save();
user.guilds.push(group2._id);
await user.save();
await api.createSubscription(data);
const updatedGroup = await Group.findById(group._id).exec();
updatedGroup.memberCount = 2;
await updatedGroup.save();
await updatedGroup.leave(recipient);
updatedUser = await User.findById(recipient._id).exec();
@@ -806,8 +853,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -835,8 +880,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -864,8 +907,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -894,8 +935,6 @@ describe('Purchasing a group plan for group', () => {
recipient.guilds.push(group._id);
await recipient.save();
user.guilds.push(group._id);
await user.save();
data.groupId = group._id;
await api.createSubscription(data);
@@ -33,11 +33,14 @@ describe('Stripe - Upgrade Group Plan', () => {
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
privacy: 'private',
leader: user._id,
});
await group.save();
user.guilds.push(group._id);
await user.save();
spy = sinon.stub(stripe.subscriptions, 'update');
spy.resolves([]);
data.groupId = group._id;
+130 -3
View File
@@ -3,7 +3,6 @@ import { model as Challenge } from '../../../../website/server/models/challenge'
import { model as Group } from '../../../../website/server/models/group';
import { model as User } from '../../../../website/server/models/user';
import * as Tasks from '../../../../website/server/models/task';
import { InternalServerError } from '../../../../website/server/libs/errors';
import { generateHistory } from '../../../helpers/api-unit.helper';
describe('Task Model', () => {
@@ -99,7 +98,8 @@ describe('Task Model', () => {
throw new Error('No exception when Id is None');
} catch (err) {
expect(err).to.exist;
expect(err).to.eql(new InternalServerError('Task identifier is a required argument'));
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.eql('Task identifier is a required argument');
}
});
@@ -109,7 +109,8 @@ describe('Task Model', () => {
throw new Error('No exception when user_id is undefined');
} catch (err) {
expect(err).to.exist;
expect(err).to.eql(new InternalServerError('User identifier is a required argument'));
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.eql('User identifier is a required argument');
}
});
@@ -153,6 +154,132 @@ describe('Task Model', () => {
});
});
describe('findMultipleByIdOrAlias', () => {
let taskWithAlias;
let secondTask;
let user;
beforeEach(async () => {
user = new User();
await user.save();
taskWithAlias = new Tasks.todo({ // eslint-disable-line new-cap
text: 'some text',
alias: 'short-name',
userId: user.id,
});
await taskWithAlias.save();
secondTask = new Tasks.habit({ // eslint-disable-line new-cap
text: 'second task',
alias: 'second-short-name',
userId: user.id,
});
await secondTask.save();
sandbox.spy(Tasks.Task, 'find');
});
it('throws an error if task identifiers is not passed in', async () => {
try {
await Tasks.Task.findMultipleByIdOrAlias(null, user._id);
throw new Error('No exception when Id is None');
} catch (err) {
expect(err).to.exist;
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.eql('Task identifiers is a required array argument');
}
});
it('throws an error if task identifiers is not an array', async () => {
try {
await Tasks.Task.findMultipleByIdOrAlias('string', user._id);
throw new Error('No exception when Id is None');
} catch (err) {
expect(err).to.exist;
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.eql('Task identifiers is a required array argument');
}
});
it('throws an error if user identifier is not passed in', async () => {
try {
await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias._id]);
throw new Error('No exception when user_id is undefined');
} catch (err) {
expect(err).to.exist;
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.eql('User identifier is a required argument');
}
});
it('returns task by id', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias._id], user._id);
expect(foundTasks[0].text).to.eql(taskWithAlias.text);
});
it('returns task by alias', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias], user._id,
);
expect(foundTasks[0].text).to.eql(taskWithAlias.text);
});
it('returns multiple tasks', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias, secondTask._id], user._id,
);
expect(foundTasks.length).to.eql(2);
expect(foundTasks[0]._id).to.eql(taskWithAlias._id);
expect(foundTasks[1]._id).to.eql(secondTask._id);
});
it('returns a task only once if searched by both id and alias', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias, taskWithAlias._id], user._id,
);
expect(foundTasks.length).to.eql(1);
expect(foundTasks[0].text).to.eql(taskWithAlias.text);
});
it('scopes alias lookup to user', async () => {
await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias.alias], user._id);
expect(Tasks.Task.find).to.be.calledOnce;
expect(Tasks.Task.find).to.be.calledWithMatch({
$or: [
{ _id: { $in: [] } },
{ alias: { $in: [taskWithAlias.alias] } },
],
userId: user._id,
});
});
it('returns empty array if tasks cannot be found', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(['not-found'], user._id);
expect(foundTasks).to.eql([]);
});
it('accepts additional query parameters', async () => {
await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias.alias], user._id, { foo: 'bar' });
expect(Tasks.Task.find).to.be.calledOnce;
expect(Tasks.Task.find).to.be.calledWithMatch({
$or: [
{ _id: { $in: [] } },
{ alias: { $in: [taskWithAlias.alias] } },
],
userId: user._id,
foo: 'bar',
});
});
});
describe('sanitizeUserChallengeTask ', () => {
});
@@ -12,7 +12,7 @@ import apiError from '../../../../../website/server/libs/apiError';
describe('GET /groups', () => {
let user;
let userInGuild;
const NUMBER_OF_PUBLIC_GUILDS = 3; // 2 + the tavern
const NUMBER_OF_PUBLIC_GUILDS = 2;
const NUMBER_OF_PUBLIC_GUILDS_USER_IS_LEADER = 2;
const NUMBER_OF_PUBLIC_GUILDS_USER_IS_MEMBER = 1;
const NUMBER_OF_USERS_PRIVATE_GUILDS = 1;
@@ -236,11 +236,22 @@ describe('GET /groups', () => {
await expect(user.get('/groups?type=publicGuilds&paginate=true&page=1'))
.to.eventually.have.a.lengthOf(GUILD_PER_PAGE);
const page2 = await expect(user.get('/groups?type=publicGuilds&paginate=true&page=2'))
.to.eventually.have.a.lengthOf(1 + 4); // 1 created now, 4 by other tests
expect(page2[4].name).to.equal('guild with less members');
// 1 created now, 4 by other tests, -1 for no more tavern.
.to.eventually.have.a.lengthOf(1 + 4 - 1);
expect(page2[3].name).to.equal('guild with less members');
}).timeout(10000);
});
it('makes sure that the tavern doesn\'t show up when guilds is passed as a query', async () => {
const guilds = await user.get('/groups?type=guilds');
expect(guilds.find(g => g.id === TAVERN_ID)).to.be.undefined;
});
it('makes sure that the tavern doesn\'t show up when publicGuilds is passed as a query', async () => {
const guilds = await user.get('/groups?type=publicGuilds');
expect(guilds.find(g => g.id === TAVERN_ID)).to.be.undefined;
});
it('returns all the user\'s guilds when guilds passed in as query', async () => {
await expect(user.get('/groups?type=guilds'))
.to.eventually.have.a
@@ -254,7 +265,7 @@ describe('GET /groups', () => {
it('returns a list of groups user has access to', async () => {
await expect(user.get('/groups?type=privateGuilds,publicGuilds,party,tavern'))
.to.eventually.have.lengthOf(NUMBER_OF_GROUPS_USER_CAN_VIEW);
.to.eventually.have.lengthOf(NUMBER_OF_GROUPS_USER_CAN_VIEW - 1); // -1 for no Tavern.
});
it('returns a list of groups user has access to', async () => {
@@ -274,6 +274,7 @@ describe('POST /groups/:groupId/leave', () => {
each(typesOfGroups, (groupDetails, groupType) => {
context(`Leaving a group plan when the group is a ${groupType}`, () => {
if (groupDetails.privacy === 'public') return; // public guilds cannot be group plans
let groupWithPlan;
let leader;
let member;
@@ -341,6 +342,7 @@ describe('POST /groups/:groupId/leave', () => {
each(typesOfGroups, (groupDetails, groupType) => {
context(`Leaving a group with extraMonths left plan when the group is a ${groupType}`, () => {
if (groupDetails.privacy === 'public') return; // public guilds cannot be group plans
const extraMonths = 12;
let groupWithPlan;
let member;
@@ -32,7 +32,7 @@ describe('payments - stripe - #checkout', () => {
stripePayments.checkout.restore();
});
it('cancels a user subscription', async () => {
it('creates a user subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
@@ -48,7 +48,7 @@ describe('payments - stripe - #checkout', () => {
expect(stripeCheckoutSubscriptionStub.args[0][0].groupId).to.eql(undefined);
});
it('cancels a group subscription', async () => {
it('creates a group subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
@@ -1,4 +1,5 @@
import { v4 as generateUUID } from 'uuid';
import apiError from '../../../../../website/server/libs/apiError';
import {
generateUser,
sleep,
@@ -44,7 +45,7 @@ describe('POST /tasks/:id/score/:direction', () => {
await expect(user.post(`/tasks/${generateUUID()}/score/tt`)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
message: apiError('directionUpDown'),
});
});
@@ -261,6 +262,7 @@ describe('POST /tasks/:id/score/:direction', () => {
const task = await user.get(`/tasks/${daily._id}`);
expect(task.completed).to.equal(true);
expect(task.value).to.be.greaterThan(daily.value);
});
it('uncompletes daily when direction is down', async () => {
@@ -46,7 +46,7 @@ describe('POST /tasks/:id/score/:direction', () => {
const response = await member.post(`/tasks/${syncedTask._id}/score/${direction}`);
expect(response.data.approvalRequested).to.equal(true);
expect(response.data.requiresApproval).to.equal(true);
expect(response.message).to.equal(t('taskApprovalHasBeenRequested'));
const updatedTask = await member.get(`/tasks/${syncedTask._id}`);
@@ -107,12 +107,9 @@ describe('POST /tasks/:id/score/:direction', () => {
await member.post(`/tasks/${syncedTask._id}/score/up`);
await expect(member.post(`/tasks/${syncedTask._id}/score/up`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('taskRequiresApproval'),
});
const response = await member.post(`/tasks/${syncedTask._id}/score/up`);
expect(response.data.requiresApproval).to.equal(true);
expect(response.message).to.equal(t('taskRequiresApproval'));
});
it('allows a user to score an approved task', async () => {
@@ -73,7 +73,7 @@ describe('PUT /tasks/:id', () => {
// score up to trigger approval
const response = await member2.post(`/tasks/${syncedTask._id}/score/up`);
expect(response.data.approvalRequested).to.equal(true);
expect(response.data.requiresApproval).to.equal(true);
expect(response.message).to.equal(t('taskApprovalHasBeenRequested'));
});
@@ -0,0 +1,583 @@
import { v4 as generateUUID } from 'uuid';
import {
generateUser,
sleep,
translate as t,
server,
} from '../../../helpers/api-integration/v4';
describe('POST /tasks/bulk-score', () => {
let user;
beforeEach(async () => {
user = await generateUser({
'stats.gp': 100,
});
});
context('all', () => {
it('can use id to identify the task', async () => {
const todo = await user.post('/tasks/user', {
text: 'test todo',
type: 'todo',
alias: 'alias',
});
const res = await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
expect(res).to.be.ok;
expect(res.tasks.length).to.equal(1);
expect(res.tasks[0].id).to.equal(todo._id);
expect(res.tasks[0].delta).to.be.greaterThan(0);
});
it('can use a alias in place of the id', async () => {
const todo = await user.post('/tasks/user', {
text: 'test todo',
type: 'todo',
alias: 'alias',
});
const res = await user.post('/tasks/bulk-score', [{ id: todo.alias, direction: 'up' }]);
expect(res).to.be.ok;
expect(res.tasks.length).to.equal(1);
expect(res.tasks[0].id).to.equal(todo._id);
expect(res.tasks[0].delta).to.be.greaterThan(0);
});
it('sends task scored webhooks', async () => {
const uuid = generateUUID();
await server.start();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'taskActivity',
enabled: true,
options: {
created: false,
scored: true,
},
});
const task = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
await user.post('/tasks/bulk-score', [{ id: task.id, direction: 'up' }]);
await sleep();
await server.close();
const body = server.getWebhookData(uuid);
expect(body.user).to.have.all.keys('_id', '_tmp', 'stats');
expect(body.user.stats).to.have.all.keys('hp', 'mp', 'exp', 'gp', 'lvl', 'class', 'points', 'str', 'con', 'int', 'per', 'buffs', 'training', 'maxHealth', 'maxMP', 'toNextLevel');
expect(body.task.id).to.eql(task.id);
expect(body.direction).to.eql('up');
expect(body.delta).to.be.greaterThan(0);
});
context('sending user activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends user activity webhook when the user levels up', async () => {
const uuid = generateUUID();
await user.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'userActivity',
enabled: true,
options: {
leveledUp: true,
},
});
const initialLvl = user.stats.lvl;
await user.update({
'stats.exp': 3000,
});
const task = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
await user.post('/tasks/bulk-score', [{ id: task.id, direction: 'up' }]);
await user.sync();
await sleep();
const body = server.getWebhookData(uuid);
expect(body.type).to.eql('leveledUp');
expect(body.initialLvl).to.eql(initialLvl);
expect(body.finalLvl).to.eql(user.stats.lvl);
});
});
it('fails the entire op if one task scoring fails', async () => {
const todo = await user.post('/tasks/user', {
text: 'test todo',
type: 'todo',
});
const habit = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
await expect(user.post('/tasks/bulk-score', [
{ id: todo.id, direction: 'down' },
{ id: habit.id, direction: 'down' },
])).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
const updatedHabit = await user.get(`/tasks/${habit._id}`);
expect(updatedHabit.history.length).to.equal(0);
expect(updatedHabit.value).to.equal(0);
const updatedTodo = await user.get(`/tasks/${todo._id}`);
expect(updatedTodo.value).to.equal(0);
});
it('sends _tmp for each task', async () => {
const habit1 = await user.post('/tasks/user', {
text: 'test habit 1',
type: 'habit',
});
const habit2 = await user.post('/tasks/user', {
text: 'test habit 2',
type: 'habit',
});
await user.update({
'party.quest.key': 'gryphon',
});
const res = await user.post('/tasks/bulk-score', [
{ id: habit1._id, direction: 'up' },
{ id: habit2._id, direction: 'up' },
]);
await user.sync();
expect(res.tasks[0]._tmp.quest.progressDelta).to.be.greaterThan(0);
expect(res.tasks[1]._tmp.quest.progressDelta).to.be.greaterThan(0);
expect(user.party.quest.progress.up).to
.eql(res.tasks[0]._tmp.quest.progressDelta + res.tasks[1]._tmp.quest.progressDelta);
});
});
context('todos', () => {
let todo;
beforeEach(async () => {
todo = await user.post('/tasks/user', {
text: 'test todo',
type: 'todo',
});
});
it('completes todo when direction is up', async () => {
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
const task = await user.get(`/tasks/${todo._id}`);
expect(task.completed).to.equal(true);
expect(task.dateCompleted).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type
});
it('moves completed todos out of user.tasksOrder.todos', async () => {
const getUser = await user.get('/user');
expect(getUser.tasksOrder.todos.indexOf(todo._id)).to.not.equal(-1);
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
const updatedTask = await user.get(`/tasks/${todo._id}`);
expect(updatedTask.completed).to.equal(true);
const updatedUser = await user.get('/user');
expect(updatedUser.tasksOrder.todos.indexOf(todo._id)).to.equal(-1);
});
it('moves un-completed todos back into user.tasksOrder.todos', async () => {
const getUser = await user.get('/user');
expect(getUser.tasksOrder.todos.indexOf(todo._id)).to.not.equal(-1);
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'down' }]);
const updatedTask = await user.get(`/tasks/${todo._id}`);
expect(updatedTask.completed).to.equal(false);
const updatedUser = await user.get('/user');
const l = updatedUser.tasksOrder.todos.length;
expect(updatedUser.tasksOrder.todos.indexOf(todo._id)).not.to.equal(-1);
// Check that it was pushed at the bottom
expect(updatedUser.tasksOrder.todos.indexOf(todo._id)).to.equal(l - 1);
});
it('uncompletes todo when direction is down', async () => {
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }, { id: todo.id, direction: 'down' }]);
const updatedTask = await user.get(`/tasks/${todo._id}`);
expect(updatedTask.completed).to.equal(false);
expect(updatedTask.dateCompleted).to.be.a('undefined');
});
it('doesn\'t let a todo be uncompleted twice', async () => {
await expect(user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'down' }])).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('sessionOutdated'),
});
});
context('user stats when direction is up', () => {
let updatedUser; let res;
beforeEach(async () => {
res = await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
updatedUser = await user.get('/user');
});
it('increases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.greaterThan(user.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
});
it('increases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.greaterThan(user.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('increases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.greaterThan(user.stats.gp);
expect(res.gp).to.equal(updatedUser.stats.gp);
});
});
context('user stats when direction is down', () => {
let updatedUser; let initialUser; let res;
beforeEach(async () => {
await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'up' }]);
initialUser = await user.get('/user');
res = await user.post('/tasks/bulk-score', [{ id: todo.id, direction: 'down' }]);
updatedUser = await user.get('/user');
});
it('decreases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.lessThan(initialUser.stats.mp);
});
it('decreases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.lessThan(initialUser.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('decreases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.lessThan(initialUser.stats.gp);
expect(res.gp).to.equal(updatedUser.stats.gp);
});
});
});
context('dailys', () => {
let daily;
beforeEach(async () => {
daily = await user.post('/tasks/user', {
text: 'test daily',
type: 'daily',
});
});
it('completes daily when direction is up', async () => {
await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }]);
const task = await user.get(`/tasks/${daily._id}`);
expect(task.completed).to.equal(true);
});
it('uncompletes daily when direction is down', async () => {
await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }, { id: daily.id, direction: 'down' }]);
const task = await user.get(`/tasks/${daily._id}`);
expect(task.completed).to.equal(false);
});
it('computes isDue', async () => {
await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }]);
const task = await user.get(`/tasks/${daily._id}`);
expect(task.isDue).to.equal(true);
});
it('computes nextDue', async () => {
await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }]);
const task = await user.get(`/tasks/${daily._id}`);
expect(task.nextDue.length).to.eql(6);
});
context('user stats when direction is up', () => {
let updatedUser; let res;
beforeEach(async () => {
res = await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }]);
updatedUser = await user.get('/user');
});
it('increases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.greaterThan(user.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
});
it('increases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.greaterThan(user.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('increases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.greaterThan(user.stats.gp);
expect(res.gp).to.equal(updatedUser.stats.gp);
});
});
context('user stats when direction is down', () => {
let updatedUser; let initialUser; let res;
beforeEach(async () => {
await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'up' }]);
initialUser = await user.get('/user');
res = await user.post('/tasks/bulk-score', [{ id: daily.id, direction: 'down' }]);
updatedUser = await user.get('/user');
});
it('decreases user\'s mp', () => {
expect(updatedUser.stats.mp).to.be.lessThan(initialUser.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
});
it('decreases user\'s exp', () => {
expect(updatedUser.stats.exp).to.be.lessThan(initialUser.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('decreases user\'s gold', () => {
expect(updatedUser.stats.gp).to.be.lessThan(initialUser.stats.gp);
expect(res.gp).to.equal(updatedUser.stats.gp);
});
});
});
context('habits', () => {
let habit; let minusHabit; let plusHabit; let
neitherHabit; // eslint-disable-line no-unused-vars
beforeEach(async () => {
habit = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
minusHabit = await user.post('/tasks/user', {
text: 'test min habit',
type: 'habit',
up: false,
});
plusHabit = await user.post('/tasks/user', {
text: 'test plus habit',
type: 'habit',
down: false,
});
neitherHabit = await user.post('/tasks/user', {
text: 'test neither habit',
type: 'habit',
up: false,
down: false,
});
});
it('increases user\'s mp when direction is up', async () => {
const res = await user.post('/tasks/bulk-score', [{ id: habit.id, direction: 'up' }, {
id: plusHabit.id,
direction: 'up',
}]);
const updatedUser = await user.get('/user');
expect(updatedUser.stats.mp).to.be.greaterThan(user.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
});
it('decreases user\'s mp when direction is down', async () => {
const res = await user.post('/tasks/bulk-score', [{
id: habit.id,
direction: 'down',
}, {
id: minusHabit.id,
direction: 'down',
}]);
const updatedUser = await user.get('/user');
expect(updatedUser.stats.mp).to.be.lessThan(user.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
});
it('increases user\'s exp when direction is up', async () => {
const res = await user.post('/tasks/bulk-score', [{
id: habit.id,
direction: 'up',
}, {
id: plusHabit.id,
direction: 'up',
}]);
const updatedUser = await user.get('/user');
expect(updatedUser.stats.exp).to.be.greaterThan(user.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('increases user\'s gold when direction is up', async () => {
const res = await user.post('/tasks/bulk-score', [{
id: habit.id,
direction: 'up',
}, {
id: plusHabit.id,
direction: 'up',
}]);
const updatedUser = await user.get('/user');
expect(updatedUser.stats.gp).to.be.greaterThan(user.stats.gp);
expect(res.gp).to.equal(updatedUser.stats.gp);
});
it('records only one history entry per day', async () => {
const initialHistoryLength = habit.history.length;
await user.post('/tasks/bulk-score', [{
id: habit.id,
direction: 'up',
}, {
id: habit.id,
direction: 'up',
}, {
id: habit.id,
direction: 'down',
}, {
id: habit.id,
direction: 'up',
}]);
const updatedTask = await user.get(`/tasks/${habit._id}`);
expect(updatedTask.history.length).to.eql(initialHistoryLength + 1);
const lastHistoryEntry = updatedTask.history[updatedTask.history.length - 1];
expect(lastHistoryEntry.scoredUp).to.equal(3);
expect(lastHistoryEntry.scoredDown).to.equal(1);
});
});
context('mixed', () => {
let habit; let daily; let todo;
beforeEach(async () => {
habit = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
daily = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
todo = await user.post('/tasks/user', {
text: 'test habit',
type: 'habit',
});
});
it('scores habits, dailies, todos', async () => {
const res = await user.post('/tasks/bulk-score', [
{ id: habit.id, direction: 'down' },
{ id: daily.id, direction: 'up' },
{ id: todo.id, direction: 'up' },
]);
expect(res.tasks[0].id).to.eql(habit.id);
expect(res.tasks[0].delta).to.be.below(0);
expect(res.tasks[0]._tmp).to.exist;
expect(res.tasks[1].id).to.eql(daily.id);
expect(res.tasks[1].delta).to.be.greaterThan(0);
expect(res.tasks[1]._tmp).to.exist;
expect(res.tasks[2].id).to.eql(todo.id);
expect(res.tasks[2].delta).to.be.greaterThan(0);
expect(res.tasks[2]._tmp).to.exist;
const updatedHabit = await user.get(`/tasks/${habit._id}`);
const updatedDaily = await user.get(`/tasks/${daily._id}`);
const updatedTodo = await user.get(`/tasks/${todo._id}`);
expect(habit.value).to.be.greaterThan(updatedHabit.value);
expect(updatedHabit.counterDown).to.equal(1);
expect(updatedDaily.value).to.be.greaterThan(daily.value);
expect(updatedTodo.value).to.be.greaterThan(todo.value);
});
});
context('reward', () => {
it('correctly handles rewards', async () => {
const reward = await user.post('/tasks/user', {
text: 'test reward',
type: 'reward',
value: 5,
});
const res = await user.post('/tasks/bulk-score', [{ id: reward.id, direction: 'up' }]);
const updatedUser = await user.get('/user');
// purchases reward
expect(user.stats.gp).to.equal(updatedUser.stats.gp + 5);
expect(res.gp).to.equal(updatedUser.stats.gp);
// does not change user\'s mp
expect(user.stats.mp).to.equal(updatedUser.stats.mp);
expect(res.mp).to.equal(updatedUser.stats.mp);
// does not change user\'s exp
expect(user.stats.exp).to.equal(updatedUser.stats.exp);
expect(res.exp).to.equal(updatedUser.stats.exp);
});
it('fails if the user does not have enough gold', async () => {
const reward = await user.post('/tasks/user', {
text: 'test reward',
type: 'reward',
value: 500,
});
await expect(user.post('/tasks/bulk-score', [{ id: reward.id, direction: 'up' }])).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageNotEnoughGold'),
});
const updatedUser = await user.get('/user');
// does not purchase reward
expect(user.stats.gp).to.equal(updatedUser.stats.gp);
});
});
});
+1 -1
View File
@@ -36,7 +36,7 @@ import BootstrapVue from 'bootstrap-vue';
import StoreModule from '@/libs/store';
// couldn't inject the languages easily,
// so just a "$t()" string to show that this will be translated
// so just a "$t()" string to show that this will be translated
Vue.prototype.$t = function translateString (...args) {
return `$t(${JSON.stringify(args)})`;
};
+1884 -644
View File
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -16,15 +16,15 @@
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/addon-links": "^5.3.19",
"@storybook/addon-notes": "^5.3.19",
"@storybook/addon-notes": "^5.3.21",
"@storybook/vue": "^5.3.19",
"@vue/cli-plugin-babel": "^4.4.6",
"@vue/cli-plugin-eslint": "^4.4.6",
"@vue/cli-plugin-router": "^4.4.6",
"@vue/cli-plugin-unit-mocha": "^4.4.6",
"@vue/cli-service": "^4.4.6",
"@vue/cli-plugin-babel": "^4.5.4",
"@vue/cli-plugin-eslint": "^4.5.4",
"@vue/cli-plugin-router": "^4.5.4",
"@vue/cli-plugin-unit-mocha": "^4.5.4",
"@vue/cli-service": "^4.5.4",
"@vue/test-utils": "1.0.0-beta.29",
"amplitude-js": "^7.1.0",
"amplitude-js": "^7.1.1",
"axios": "^0.19.2",
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.1.0",
@@ -41,7 +41,7 @@
"inspectpack": "^4.5.2",
"intro.js": "^2.9.3",
"jquery": "^3.5.1",
"lodash": "^4.17.19",
"lodash": "^4.17.20",
"moment": "^2.27.0",
"nconf": "^0.10.0",
"sass": "^1.26.10",
@@ -53,12 +53,12 @@
"svgo-loader": "^2.2.1",
"uuid": "^8.3.0",
"validator": "^13.1.1",
"vue": "^2.6.11",
"vue": "^2.6.12",
"vue-cli-plugin-storybook": "^0.6.1",
"vue-mugen-scroll": "^0.2.6",
"vue-router": "^3.4.2",
"vue-template-compiler": "^2.6.11",
"vuedraggable": "^2.24.0",
"vue-router": "^3.4.3",
"vue-template-compiler": "^2.6.12",
"vuedraggable": "^2.24.1",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0",
"webpack": "^4.44.1"
}
-1
View File
@@ -119,7 +119,6 @@
#melior {
margin: 0 auto;
width: 70.9px;
margin-bottom: 1em;
}
.row {
+15 -4
View File
@@ -4,16 +4,27 @@
height: 219px;
}
.Pet_HatchingPotion_Dessert {
background: url("~@/assets/images/animated/Pet_HatchingPotion_Dessert.gif") no-repeat;
.quest_windup {
background: url("~@/assets/images/animated/quest_windup.gif") no-repeat;
width: 219px;
height: 219px;
}
.Pet_HatchingPotion_Dessert, .Pet_HatchingPotion_Veggie, .Pet_HatchingPotion_Windup {
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Dessert {
background: url("~@/assets/images/animated/Pet_HatchingPotion_Dessert.gif") no-repeat;
}
.Pet_HatchingPotion_Veggie {
background: url("~@/assets/images/animated/Pet_HatchingPotion_Veggie.gif") no-repeat;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Windup {
background: url("~@/assets/images/animated/Pet_HatchingPotion_Windup.gif") no-repeat;
}
.Gems {
@@ -6,19 +6,37 @@
}
.promo_armoire_backgrounds_202008 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -187px;
background-position: -376px -148px;
width: 423px;
height: 147px;
}
.promo_armoire_backgrounds_202009 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -383px;
width: 423px;
height: 147px;
}
.promo_golden_achievements {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -295px -531px;
width: 246px;
height: 112px;
}
.promo_mystery_202008 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -335px;
background-position: 0px -531px;
width: 294px;
height: 156px;
}
.promo_mystery_202009 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -383px;
width: 282px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -596px -187px;
background-position: -800px -537px;
width: 96px;
height: 69px;
}
@@ -28,15 +46,33 @@
width: 375px;
height: 186px;
}
.scene_CernyPie {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -688px;
width: 141px;
height: 167px;
}
.scene_achievement {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -800px 0px;
width: 210px;
height: 210px;
}
.scene_public_space {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -187px;
width: 345px;
height: 195px;
}
.scene_reading {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -187px;
background-position: -800px -392px;
width: 171px;
height: 144px;
}
.scene_rewards {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -492px;
background-position: -800px -211px;
width: 207px;
height: 180px;
}
@@ -1,42 +1,48 @@
.achievement-alien {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1323px -1628px;
background-position: -1671px -1480px;
width: 24px;
height: 26px;
}
.achievement-alien2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1655px -1480px;
background-position: -524px -1549px;
width: 48px;
height: 52px;
}
.achievement-allYourBase2x {
.achievement-allThatGlitters2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -954px -1480px;
width: 64px;
height: 56px;
}
.achievement-alpha2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1549px;
width: 48px;
height: 52px;
}
.achievement-aridAuthority2x {
.achievement-allYourBase2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1019px -1480px;
width: 64px;
height: 56px;
}
.achievement-alpha2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -573px -1549px;
width: 48px;
height: 52px;
}
.achievement-aridAuthority2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1084px -1480px;
width: 64px;
height: 56px;
}
.achievement-armor2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -475px -1549px;
background-position: -622px -1549px;
width: 48px;
height: 52px;
}
.achievement-backToBasics2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1214px -1480px;
background-position: -1279px -1480px;
width: 48px;
height: 56px;
}
@@ -48,25 +54,25 @@
}
.achievement-bewilder2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -524px -1549px;
background-position: -671px -1549px;
width: 48px;
height: 52px;
}
.achievement-birthday2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -573px -1549px;
background-position: -720px -1549px;
width: 48px;
height: 52px;
}
.achievement-boot2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -622px -1549px;
background-position: -769px -1549px;
width: 48px;
height: 52px;
}
.achievement-bow2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -671px -1549px;
background-position: -818px -1549px;
width: 48px;
height: 52px;
}
@@ -78,85 +84,85 @@
}
.achievement-burnout2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -720px -1549px;
background-position: -867px -1549px;
width: 48px;
height: 52px;
}
.achievement-cactus2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -769px -1549px;
background-position: -916px -1549px;
width: 48px;
height: 52px;
}
.achievement-cake2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -818px -1549px;
background-position: -965px -1549px;
width: 48px;
height: 52px;
}
.achievement-cave2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -867px -1549px;
background-position: -1014px -1549px;
width: 48px;
height: 52px;
}
.achievement-challenge2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -916px -1549px;
background-position: -1063px -1549px;
width: 48px;
height: 52px;
}
.achievement-comment2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -965px -1549px;
background-position: -1112px -1549px;
width: 48px;
height: 52px;
}
.achievement-completedTask2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1263px -1480px;
background-position: -1328px -1480px;
width: 48px;
height: 56px;
}
.achievement-congrats2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1014px -1549px;
background-position: -1161px -1549px;
width: 48px;
height: 52px;
}
.achievement-costumeContest2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1063px -1549px;
background-position: -1210px -1549px;
width: 48px;
height: 52px;
}
.achievement-createdTask2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1312px -1480px;
background-position: -1377px -1480px;
width: 48px;
height: 56px;
}
.achievement-dilatory2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1112px -1549px;
background-position: -1259px -1549px;
width: 48px;
height: 52px;
}
.achievement-dustDevil2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1361px -1480px;
background-position: -1426px -1480px;
width: 48px;
height: 56px;
}
.achievement-dysheartener2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1161px -1549px;
background-position: -1308px -1549px;
width: 48px;
height: 52px;
}
.achievement-fedPet2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1410px -1480px;
background-position: -1475px -1480px;
width: 48px;
height: 56px;
}
@@ -168,55 +174,61 @@
}
.achievement-friends2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1210px -1549px;
background-position: -1357px -1549px;
width: 48px;
height: 52px;
}
.achievement-getwell2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1259px -1549px;
width: 48px;
height: 52px;
}
.achievement-goodluck2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1308px -1549px;
width: 48px;
height: 52px;
}
.achievement-greeting2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1357px -1549px;
width: 48px;
height: 52px;
}
.achievement-guild2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1406px -1549px;
width: 48px;
height: 52px;
}
.achievement-habitBirthday2x {
.achievement-goodAsGold2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1524px -1480px;
width: 48px;
height: 56px;
}
.achievement-goodluck2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1455px -1549px;
width: 48px;
height: 52px;
}
.achievement-habiticaDay2x {
.achievement-greeting2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1504px -1549px;
width: 48px;
height: 52px;
}
.achievement-guild2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1553px -1549px;
width: 48px;
height: 52px;
}
.achievement-habitBirthday2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1602px -1549px;
width: 48px;
height: 52px;
}
.achievement-habiticaDay2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1651px -1549px;
width: 48px;
height: 52px;
}
.achievement-hatchedPet2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1459px -1480px;
background-position: -1573px -1480px;
width: 48px;
height: 56px;
}
.achievement-heart2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1553px -1549px;
background-position: 0px -1628px;
width: 48px;
height: 52px;
}
@@ -228,13 +240,13 @@
}
.achievement-karaoke-2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1602px -1549px;
background-position: -49px -1628px;
width: 48px;
height: 52px;
}
.achievement-karaoke {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1348px -1628px;
background-position: -1671px -1507px;
width: 24px;
height: 26px;
}
@@ -246,7 +258,7 @@
}
.achievement-lostMasterclasser2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1651px -1549px;
background-position: -98px -1628px;
width: 48px;
height: 52px;
}
@@ -258,67 +270,67 @@
}
.achievement-monsterMagus2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1508px -1480px;
background-position: -1622px -1480px;
width: 48px;
height: 56px;
}
.achievement-ninja2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1628px;
background-position: -147px -1628px;
width: 48px;
height: 52px;
}
.achievement-npc2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -49px -1628px;
background-position: -196px -1628px;
width: 48px;
height: 52px;
}
.achievement-nye2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -98px -1628px;
background-position: -245px -1628px;
width: 48px;
height: 52px;
}
.achievement-partyOn2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -147px -1628px;
background-position: -294px -1628px;
width: 48px;
height: 52px;
}
.achievement-partyUp2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -196px -1628px;
background-position: -343px -1628px;
width: 48px;
height: 52px;
}
.achievement-pearlyPro2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1084px -1480px;
background-position: -1149px -1480px;
width: 64px;
height: 56px;
}
.achievement-perfect2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -245px -1628px;
background-position: -392px -1628px;
width: 48px;
height: 52px;
}
.achievement-primedForPainting2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1557px -1480px;
background-position: -426px -1549px;
width: 48px;
height: 56px;
}
.achievement-purchasedEquipment2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1606px -1480px;
background-position: -475px -1549px;
width: 48px;
height: 56px;
}
.achievement-rat2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -294px -1628px;
background-position: -441px -1628px;
width: 48px;
height: 52px;
}
@@ -330,67 +342,67 @@
}
.achievement-royally-loyal2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -343px -1628px;
background-position: -490px -1628px;
width: 48px;
height: 52px;
}
.achievement-seafoam2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -392px -1628px;
background-position: -539px -1628px;
width: 48px;
height: 52px;
}
.achievement-shield2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -441px -1628px;
background-position: -588px -1628px;
width: 48px;
height: 52px;
}
.achievement-shinySeed2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -490px -1628px;
background-position: -637px -1628px;
width: 48px;
height: 52px;
}
.achievement-snowball2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -539px -1628px;
background-position: -686px -1628px;
width: 48px;
height: 52px;
}
.achievement-spookySparkles2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -588px -1628px;
background-position: -735px -1628px;
width: 48px;
height: 52px;
}
.achievement-stoikalm2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -637px -1628px;
background-position: -784px -1628px;
width: 48px;
height: 52px;
}
.achievement-sun2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -686px -1628px;
background-position: -833px -1628px;
width: 48px;
height: 52px;
}
.achievement-sword2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -735px -1628px;
background-position: -882px -1628px;
width: 48px;
height: 52px;
}
.achievement-thankyou2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -784px -1628px;
background-position: -931px -1628px;
width: 48px;
height: 52px;
}
.achievement-thermometer2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -833px -1628px;
background-position: -980px -1628px;
width: 48px;
height: 52px;
}
@@ -402,61 +414,61 @@
}
.achievement-tree2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -882px -1628px;
background-position: -1029px -1628px;
width: 48px;
height: 52px;
}
.achievement-triadbingo2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -931px -1628px;
background-position: -1078px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-healer2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -980px -1628px;
background-position: -1127px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-mage2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1029px -1628px;
background-position: -1176px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-rogue2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1078px -1628px;
background-position: -1225px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-warrior2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1127px -1628px;
background-position: -1274px -1628px;
width: 48px;
height: 52px;
}
.achievement-undeadUndertaker2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1149px -1480px;
background-position: -1214px -1480px;
width: 64px;
height: 56px;
}
.achievement-unearned2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1176px -1628px;
background-position: -1323px -1628px;
width: 48px;
height: 52px;
}
.achievement-valentine2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1225px -1628px;
background-position: -1372px -1628px;
width: 48px;
height: 52px;
}
.achievement-wolf2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1274px -1628px;
background-position: -1421px -1628px;
width: 48px;
height: 52px;
}
@@ -940,283 +952,283 @@
width: 141px;
height: 147px;
}
.background_flying_over_icy_steppes {
.background_flying_over_an_autumn_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -592px;
width: 141px;
height: 147px;
}
.background_flying_over_rocky_canyon {
.background_flying_over_icy_steppes {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -740px;
width: 141px;
height: 147px;
}
.background_flying_over_snowy_mountains {
.background_flying_over_rocky_canyon {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -888px;
width: 141px;
height: 147px;
}
.background_flying_over_tropical_islands {
.background_flying_over_snowy_mountains {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -1036px;
width: 141px;
height: 147px;
}
.background_foggy_moor {
.background_flying_over_tropical_islands {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1184px;
width: 141px;
height: 147px;
}
.background_forest {
.background_foggy_moor {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -142px -1184px;
width: 141px;
height: 147px;
}
.background_frigid_peak {
.background_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -284px -1184px;
width: 141px;
height: 147px;
}
.background_frosty_forest {
.background_frigid_peak {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1184px;
width: 141px;
height: 147px;
}
.background_frozen_lake {
.background_frosty_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -568px -1184px;
width: 141px;
height: 147px;
}
.background_garden_shed {
.background_frozen_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -710px -1184px;
width: 141px;
height: 147px;
}
.background_gazebo {
.background_garden_shed {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -852px -1184px;
width: 141px;
height: 147px;
}
.background_giant_birdhouse {
.background_gazebo {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -994px -1184px;
width: 141px;
height: 147px;
}
.background_giant_book {
.background_giant_autumn_leaf {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1136px -1184px;
width: 141px;
height: 147px;
}
.background_giant_dandelions {
.background_giant_birdhouse {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -1184px;
width: 141px;
height: 147px;
}
.background_giant_florals {
.background_giant_book {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px 0px;
width: 141px;
height: 147px;
}
.background_giant_seashell {
.background_giant_dandelions {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -148px;
width: 141px;
height: 147px;
}
.background_giant_wave {
.background_giant_florals {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -296px;
width: 141px;
height: 147px;
}
.background_glowing_mushroom_cave {
.background_giant_seashell {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -444px;
width: 141px;
height: 147px;
}
.background_gorgeous_greenhouse {
.background_giant_wave {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -592px;
width: 141px;
height: 147px;
}
.background_grand_staircase {
.background_glowing_mushroom_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -740px;
width: 141px;
height: 147px;
}
.background_graveyard {
.background_gorgeous_greenhouse {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -888px;
width: 141px;
height: 147px;
}
.background_green {
.background_grand_staircase {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1036px;
width: 141px;
height: 147px;
}
.background_guardian_statues {
.background_graveyard {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1184px;
width: 141px;
height: 147px;
}
.background_gumdrop_land {
.background_green {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1332px;
width: 141px;
height: 147px;
}
.background_habit_city_rooftops {
.background_guardian_statues {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -142px -1332px;
width: 141px;
height: 147px;
}
.background_habit_city_streets {
.background_gumdrop_land {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -284px -1332px;
width: 141px;
height: 147px;
}
.background_halflings_house {
.background_habit_city_rooftops {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1332px;
width: 141px;
height: 147px;
}
.background_hall_of_heroes {
.background_habit_city_streets {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -568px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_feast {
.background_halflings_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -710px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_fields {
.background_hall_of_heroes {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -852px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_moon {
.background_harvest_feast {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -994px -1332px;
width: 141px;
height: 147px;
}
.background_haunted_house {
.background_harvest_fields {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1136px -1332px;
width: 141px;
height: 147px;
}
.background_heather_field {
.background_harvest_moon {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -1332px;
width: 141px;
height: 147px;
}
.background_holiday_market {
.background_haunted_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1332px;
width: 141px;
height: 147px;
}
.background_holiday_wreath {
.background_heather_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px 0px;
width: 141px;
height: 147px;
}
.background_hot_air_balloon {
.background_herding_sheep_in_autumn {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -148px;
width: 141px;
height: 147px;
}
.background_ice_cave {
.background_holiday_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -296px;
width: 141px;
height: 147px;
}
.background_iceberg {
.background_holiday_wreath {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -444px;
width: 141px;
height: 147px;
}
.background_idyllic_cabin {
.background_hot_air_balloon {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -592px;
width: 141px;
height: 147px;
}
.background_in_a_classroom {
.background_ice_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -740px;
width: 141px;
height: 147px;
}
.background_in_an_ancient_tomb {
.background_iceberg {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -888px;
width: 141px;
height: 147px;
}
.background_island_waterfalls {
.background_idyllic_cabin {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1036px;
width: 141px;
height: 147px;
}
.background_jungle_canopy {
.background_in_a_classroom {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1184px;
width: 141px;
height: 147px;
}
.background_kelp_forest {
.background_in_an_ancient_tomb {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1332px;
width: 141px;
height: 147px;
}
.background_lake_with_floating_lanterns {
.background_island_waterfalls {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1480px;
width: 141px;
height: 147px;
}
.background_lighthouse_shore {
.background_jungle_canopy {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -142px -1480px;
width: 141px;
height: 147px;
}
.background_lilypad {
.background_kelp_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -284px -1480px;
width: 141px;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,198 +1,396 @@
.Pet_Currency_Gem {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1344px -1583px;
width: 68px;
height: 68px;
}
.Pet_Currency_Gem1x {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1477px -1287px;
width: 15px;
height: 13px;
}
.Pet_Currency_Gem2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1931px -1025px;
background-position: -1025px -838px;
width: 30px;
height: 26px;
}
.PixelPaw-Gold {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1929px -711px;
background-position: -473px -220px;
width: 51px;
height: 51px;
}
.PixelPaw {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1913px -854px;
background-position: -473px -272px;
width: 51px;
height: 51px;
}
.PixelPaw002 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1905px -923px;
background-position: -473px -324px;
width: 51px;
height: 51px;
}
.empty_bottles {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1620px -1583px;
width: 64px;
height: 54px;
}
.ghost {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -1444px;
width: 90px;
height: 90px;
}
.inventory_present {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1320px -1233px;
width: 68px;
height: 68px;
}
.inventory_present_01 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -220px -324px;
width: 68px;
height: 68px;
}
.inventory_present_02 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -660px -435px;
width: 68px;
height: 68px;
}
.inventory_present_03 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -660px -504px;
width: 68px;
height: 68px;
}
.inventory_present_04 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -660px -573px;
width: 68px;
height: 68px;
}
.inventory_present_05 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -880px -655px;
width: 68px;
height: 68px;
}
.inventory_present_06 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -880px -724px;
width: 68px;
height: 68px;
}
.inventory_present_07 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -880px -793px;
width: 68px;
height: 68px;
}
.inventory_present_08 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1100px -875px;
width: 68px;
height: 68px;
}
.inventory_present_09 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1100px -944px;
width: 68px;
height: 68px;
}
.inventory_present_10 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1100px -1013px;
width: 68px;
height: 68px;
}
.inventory_present_11 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1320px -1095px;
width: 68px;
height: 68px;
}
.inventory_present_12 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1320px -1164px;
width: 68px;
height: 68px;
}
.inventory_special_birthday {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -309px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_congrats {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -378px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_fortify {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -447px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_getwell {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -516px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_goodluck {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -585px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_greeting {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -654px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_nye {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -723px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_opaquePotion {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -792px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_seafoam {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -861px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_shinySeed {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -930px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_snowball {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -999px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_spookySparkles {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1068px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_thankyou {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1137px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_trinket {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1206px -1583px;
width: 68px;
height: 68px;
}
.inventory_special_valentine {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1275px -1583px;
width: 68px;
height: 68px;
}
.knockout {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -309px -1535px;
width: 120px;
height: 47px;
}
.pet_key {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1929px -642px;
background-position: -1413px -1583px;
width: 68px;
height: 68px;
}
.rebirth_orb {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1935px -763px;
background-position: -1482px -1583px;
width: 68px;
height: 68px;
}
.seafoam_star {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -763px;
background-position: -1718px -1444px;
width: 90px;
height: 90px;
}
.shop_armoire {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -854px;
background-position: -1551px -1583px;
width: 68px;
height: 68px;
}
.zzz {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1963px -551px;
background-position: -702px -261px;
width: 40px;
height: 40px;
}
.zzz_light {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1963px -510px;
background-position: -702px -220px;
width: 40px;
height: 40px;
}
.notif_inventory_present_01 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1963px -592px;
background-position: -1809px -1444px;
width: 28px;
height: 28px;
}
.notif_inventory_present_02 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1981px -711px;
background-position: -1809px -1473px;
width: 28px;
height: 28px;
}
.notif_inventory_present_03 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1965px -854px;
background-position: -1809px -1502px;
width: 28px;
height: 28px;
}
.notif_inventory_present_04 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1957px -923px;
background-position: -1187px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_05 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -996px;
background-position: -1216px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_06 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1873px -996px;
background-position: -1245px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_07 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1902px -996px;
background-position: -1274px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_08 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1931px -996px;
background-position: -1303px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_09 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1960px -996px;
background-position: -1332px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_10 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -1025px;
background-position: -1361px -1061px;
width: 28px;
height: 28px;
}
.notif_inventory_present_11 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1873px -1025px;
background-position: -967px -838px;
width: 28px;
height: 28px;
}
.notif_inventory_present_12 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1902px -1025px;
background-position: -996px -838px;
width: 28px;
height: 28px;
}
.notif_inventory_special_birthday {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1989px -996px;
background-position: -1102px -838px;
width: 20px;
height: 24px;
}
.notif_inventory_special_congrats {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1981px -740px;
background-position: -1165px -838px;
width: 20px;
height: 22px;
}
.notif_inventory_special_getwell {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1965px -883px;
background-position: -747px -618px;
width: 20px;
height: 22px;
}
.notif_inventory_special_goodluck {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1986px -923px;
background-position: -1081px -838px;
width: 20px;
height: 26px;
}
.notif_inventory_special_greeting {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1986px -883px;
background-position: -768px -618px;
width: 20px;
height: 22px;
}
.notif_inventory_special_nye {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1962px -1025px;
background-position: -1056px -838px;
width: 24px;
height: 26px;
}
.notif_inventory_special_thankyou {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1987px -1025px;
background-position: -1123px -838px;
width: 20px;
height: 24px;
}
.notif_inventory_special_valentine {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -1054px;
background-position: -1144px -838px;
width: 20px;
height: 24px;
}
.npc_bailey {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -923px;
background-position: -302px -1677px;
width: 60px;
height: 72px;
}
.npc_justin {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -642px;
background-position: -220px -203px;
width: 84px;
height: 120px;
}
.npc_matt {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -191px -1535px;
background-position: -1375px -1315px;
width: 195px;
height: 138px;
}
@@ -204,19 +402,19 @@
}
.banner_flair_dysheartener {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1935px -832px;
background-position: -1407px -1287px;
width: 69px;
height: 18px;
}
.phobia_dysheartener {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -1278px;
background-position: -1627px -1061px;
width: 201px;
height: 195px;
}
.quest_alligator {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -862px;
background-position: -1627px -645px;
width: 201px;
height: 213px;
}
@@ -234,19 +432,19 @@
}
.quest_atom1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -885px -1315px;
background-position: -665px -1315px;
width: 250px;
height: 150px;
}
.quest_atom2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1387px -1315px;
background-position: -1167px -1315px;
width: 207px;
height: 138px;
}
.quest_atom3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -967px -660px;
background-position: -1187px -880px;
width: 216px;
height: 180px;
}
@@ -264,13 +462,13 @@
}
.quest_basilist {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: 0px -1719px;
background-position: 0px -1535px;
width: 189px;
height: 141px;
}
.quest_beetle {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -1076px;
background-position: -1627px -859px;
width: 204px;
height: 201px;
}
@@ -282,7 +480,7 @@
}
.quest_bunny {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1187px -880px;
background-position: -1627px -1257px;
width: 210px;
height: 186px;
}
@@ -300,7 +498,7 @@
}
.quest_cow {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -307px -220px;
background-position: -527px -220px;
width: 174px;
height: 213px;
}
@@ -312,13 +510,13 @@
}
.quest_dilatoryDistress1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -651px;
background-position: -1627px -434px;
width: 210px;
height: 210px;
}
.quest_dilatoryDistress2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -208px;
background-position: 0px -1677px;
width: 150px;
height: 150px;
}
@@ -348,13 +546,13 @@
}
.quest_egg {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px 0px;
background-position: -307px -220px;
width: 165px;
height: 207px;
}
.quest_evilsanta {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -510px;
background-position: -190px -1535px;
width: 118px;
height: 131px;
}
@@ -384,7 +582,7 @@
}
.quest_frog {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -440px -1315px;
background-position: -220px -1315px;
width: 221px;
height: 213px;
}
@@ -402,7 +600,7 @@
}
.quest_goldenknight2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1136px -1315px;
background-position: -916px -1315px;
width: 250px;
height: 150px;
}
@@ -414,7 +612,7 @@
}
.quest_gryphon {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -747px -440px;
background-position: -967px -660px;
width: 216px;
height: 177px;
}
@@ -456,7 +654,7 @@
}
.quest_kraken {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -527px -220px;
background-position: -747px -440px;
width: 216px;
height: 177px;
}
@@ -480,7 +678,7 @@
}
.quest_mayhemMistiflying1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1844px -359px;
background-position: -151px -1677px;
width: 150px;
height: 150px;
}
@@ -546,7 +744,7 @@
}
.quest_octopus {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -662px -1315px;
background-position: -442px -1315px;
width: 222px;
height: 177px;
}
@@ -556,21 +754,3 @@
width: 219px;
height: 219px;
}
.quest_peacock {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -1627px -434px;
width: 216px;
height: 216px;
}
.quest_penguin {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: 0px -1535px;
width: 190px;
height: 183px;
}
.quest_pterodactyl {
background-image: url('~@/assets/images/sprites/spritesmith-main-13.png');
background-position: -220px -1315px;
width: 219px;
height: 219px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 KiB

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 152 KiB

+1 -1
View File
@@ -5,7 +5,7 @@
font-weight: bold;
line-height: 1.71;
border: 1px solid transparent;
padding: 0.25rem 1rem;
padding: 0.219rem 1rem;
border-radius: 2px;
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
color: $white;
@@ -31,5 +31,4 @@
#melior {
animation: fadeColor 2.4s infinite;
height: 4rem;
margin-left: -1rem;
}
@@ -206,5 +206,4 @@
font-style: normal;
}
}
}
@@ -15,6 +15,13 @@ body {
color: $gray-200;
}
// Restore the default styling for a elements without an href attribute
// that was changed in bootstrap 4.5.1
a:not([href]), a:not([href]):hover {
color: inherit;
text-decoration: none;
}
a, a:not([href]):not([tabindex]) {
cursor: pointer;
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="15" viewBox="0 0 32 15">
<g fill="none" fill-rule="evenodd">
<path fill="#FFA624" d="M9.074 8.485L13.333 6.364 9.074 4.242 6.944 0 4.815 4.242 0.556 6.364 4.815 8.485 6.944 12.727z" transform="rotate(90 16 16)"/>
<path fill="#FFBE5D" d="M12.634 19.632L15.19 18.359 12.634 17.087 11.356 14.541 10.079 17.087 7.523 18.359 10.079 19.632 11.356 22.177z" transform="rotate(90 16 16) rotate(53 11.356 18.36)"/>
<path fill="#FEDEAD" d="M7.111 29.091L9.667 27.818 7.111 26.545 5.833 24 4.556 26.545 2 27.818 4.556 29.091 5.833 31.636z" transform="rotate(90 16 16)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 662 B

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="64" viewBox="0 0 40 64">
<g fill="none" fill-rule="evenodd">
<path fill="#77F4C7" d="M35.667 8.667L40 6.5 35.667 4.333 33.5 0 31.333 4.333 27 6.5 31.333 8.667 33.5 13z" transform="matrix(-1 0 0 1 40 0)"/>
<path fill="#BDA8FF" d="M24.667 35.667L30 33 24.667 30.333 22 25 19.333 30.333 14 33 19.333 35.667 22 41z" transform="matrix(-1 0 0 1 40 0)"/>
<path fill="#8EEDF6" d="M35.667 60.667L39 59 35.667 57.333 34 54 32.333 57.333 29 59 32.333 60.667 34 64z" transform="matrix(-1 0 0 1 40 0)"/>
<path fill="#FFBE5D" d="M6.667 46.667L10 45 6.667 43.333 5 40 3.333 43.333 0 45 3.333 46.667 5 50z" transform="matrix(-1 0 0 1 40 0)"/>
<path fill="#FFB6B8" d="M5.667 17.667L8 16.5 5.667 15.333 4.5 13 3.333 15.333 1 16.5 3.333 17.667 4.5 20z" transform="matrix(-1 0 0 1 40 0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 889 B

@@ -216,7 +216,7 @@ export default {
this.$root.$emit('bv::hide::modal', 'choose-class');
},
clickSelectClass (heroClass) {
if (this.user.flags.classSelected && !window.confirm(this.$t('changeClassConfirmCost'))) return;
if (this.user.flags.classSelected && !window.confirm(this.$t('changeClassConfirmCost'))) return; // eslint-disable-line no-alert
this.$store.dispatch('user:changeClass', { query: { class: heroClass } });
},
clickDisableClasses () {
@@ -1,109 +1,200 @@
<template>
<b-modal
id="level-up"
:title="$t('levelUpShare')"
size="sm"
:hide-footer="true"
:hide-header="true"
:title="title"
ok-only
:ok-title="$t('onwards')"
v-bind:footer-class="{ greyed: displayRewardQuest }"
>
<div class="modal-body text-center">
<h2>{{ $t('reachedLevel', {level: user.stats.lvl}) }}</h2>
<section class="d-flex">
<span
class="star-group mirror"
v-html="icons.starGroup"
></span>
<avatar
class="avatar"
:member="user"
/>
<p class="text">
{{ $t('levelup') }}
</p>
<button
class="btn btn-primary"
@click="close()"
<span
class="star-group"
v-html="icons.starGroup"
></span>
</section>
<p
class="text"
v-once
>
{{ $t('levelup') }}
</p>
<section
v-if="displayRewardQuest"
class="greyed"
>
<div
class="your-rewards d-flex"
v-once
>
{{ $t('onwards') }}
</button>
<br>
<!-- @TODO: Keep this? .checkboxinput(type='checkbox', v-model=
<span
class="sparkles"
v-html="icons.sparkles"
></span>
<span class="text">{{ $t('yourRewards') }}</span>
<span
class="sparkles mirror"
v-html="icons.sparkles"
></span>
</div>
<div :class="questClass"></div>
</section>
<!-- @TODO: Keep this? .checkboxinput(type='checkbox', v-model=
'user.preferences.suppressModals.levelUp', @change='changeLevelupSuppress()')
label(style='display:inline-block') {{ $t('dontShowAgain') }}
-->
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#level-up {
h2 {
color: #4f2a93;
.modal-content {
border-radius: 8px;
box-shadow: 0 14px 28px 0 rgba($black, 0.24), 0 10px 10px 0 rgba($black, 0.28);
}
.modal-content {
min-width: 28em;
@media (min-width: 576px) {
.modal-sm {
max-width: 330px;
}
}
header {
padding: 0;
border: none;
h5 {
margin: 31px auto 16px;
color: $purple-200;
}
button {
position: absolute;
right: 18px;
top: 12px;
}
}
footer {
padding: 0;
border: none;
button {
margin: 0 auto 32px auto;
}
}
.greyed {
background-color: $gray-700;
}
.modal-body {
padding-top: 1em;
padding: 0;
}
.modal-footer {
margin-top: 0;
.mirror {
transform: scaleX(-1);
}
.herobox {
margin: auto 8.3em;
width: 6em;
height: 9em;
padding-top: 0;
cursor: default;
.star-group {
margin: auto;
svg {
height: 64px;
width: 40px;
}
}
.character-sprites {
margin: 0;
width: 0;
.avatar {
cursor: auto;
}
.class-badge {
display: none !important;
}
.text {
font-size: 14px;
text-align: center;
color: #686274;
margin-top: 1em;
min-height: 0px;
margin: 25px 24px 24px;
min-height: auto;
}
}
</style>
<style scoped>
.avatar {
margin-left: 6.8em;
.your-rewards {
margin: 0 auto;
width: fit-content;
.sparkles {
width: 32px;
margin-top: 12px;
}
.text {
font-weight: bold;
margin: 16px;
color: $gray-50;
}
}
section.greyed {
padding-bottom: 17px
}
.scroll {
margin: -11px auto 0;
}
}
</style>
<script>
import Avatar from '../avatar';
import { mapState } from '@/libs/store';
import { MAX_HEALTH as maxHealth } from '@/../../common/script/constants';
import styleHelper from '@/mixins/styleHelper';
import starGroup from '@/assets/svg/star-group.svg';
import sparkles from '@/assets/svg/sparkles-left.svg';
const levelQuests = {
15: 'atom1',
30: 'vice1',
40: 'goldenknight1',
60: 'moonstone1',
};
export default {
components: {
Avatar,
},
mixins: [styleHelper],
data () {
return {
statsAllocationBoxIsOpen: true,
maxHealth,
icons: Object.freeze({
starGroup,
sparkles,
}),
};
},
computed: {
...mapState({ user: 'user.data' }),
showAllocation () {
return this.$store.getters['members:hasClass'](this.user) && !this.user.preferences.automaticAllocation;
title () {
return this.$t('reachedLevel', { level: this.user.stats.lvl });
},
displayRewardQuest () {
return this.user.stats.lvl in levelQuests;
},
questClass () {
return `scroll inventory_quest_scroll_${levelQuests[this.user.stats.lvl]}`;
},
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'level-up');
},
changeLevelupSuppress () {
// @TODO: dispatch set({"preferences.suppressModals.levelUp":
// user.preferences.suppressModals.levelUp?true: false})
+1 -1
View File
@@ -530,7 +530,7 @@ export default {
});
},
async addMissedDay (numberOfDays) {
if (!window.confirm(`Are you sure you want to reset the day by ${numberOfDays} day(s)?`)) return;
if (!window.confirm(`Are you sure you want to reset the day by ${numberOfDays} day(s)?`)) return; // eslint-disable-line no-alert
const date = moment(this.user.lastCron).subtract(numberOfDays, 'days').toDate();
@@ -360,12 +360,12 @@ export default {
},
async register () {
if (!this.email) {
window.alert(this.$t('missingEmail'));
window.alert(this.$t('missingEmail')); // eslint-disable-line no-alert
return;
}
if (this.password !== this.passwordConfirm) {
window.alert(this.$t('passwordConfirmationMatch'));
window.alert(this.$t('passwordConfirmationMatch')); // eslint-disable-line no-alert
return;
}
@@ -381,7 +381,7 @@ export default {
} catch (e) {
if (e.response.data.data && e.response.data.data.errors) {
const message = e.response.data.data.errors.map(error => `${error.message}\n`);
window.alert(message);
window.alert(message); // eslint-disable-line no-alert
}
}
},
@@ -750,13 +750,13 @@ export default {
const { code } = query;
const hasError = query.hasError === 'true';
if (hasError) {
window.alert(query.message);
window.alert(query.message); // eslint-disable-line no-alert
this.$router.push({ name: 'login' });
return;
}
if (!code) {
window.alert(this.$t('invalidPasswordResetCode'));
window.alert(this.$t('invalidPasswordResetCode')); // eslint-disable-line no-alert
this.$router.push({ name: 'login' });
return;
}
@@ -797,12 +797,12 @@ export default {
async register () {
// @TODO do not use alert
if (!this.email) {
window.alert(this.$t('missingEmail'));
window.alert(this.$t('missingEmail')); // eslint-disable-line no-alert
return;
}
if (this.password !== this.passwordConfirm) {
window.alert(this.$t('passwordConfirmationMatch'));
window.alert(this.$t('passwordConfirmationMatch')); // eslint-disable-line no-alert
return;
}
@@ -918,7 +918,7 @@ export default {
},
async forgotPasswordLink () {
if (!this.username) {
window.alert(this.$t('missingEmail'));
window.alert(this.$t('missingEmail')); // eslint-disable-line no-alert
return;
}
@@ -926,17 +926,17 @@ export default {
email: this.username,
});
window.alert(this.$t('newPassSent'));
window.alert(this.$t('newPassSent')); // eslint-disable-line no-alert
},
async resetPasswordSetNewOneLink () {
if (!this.password) {
window.alert(this.$t('missingNewPassword'));
window.alert(this.$t('missingNewPassword')); // eslint-disable-line no-alert
return;
}
if (this.password !== this.passwordConfirm) {
// @TODO i18n and don't use alerts
window.alert(this.$t('passwordConfirmationMatch'));
window.alert(this.$t('passwordConfirmationMatch')); // eslint-disable-line no-alert
return;
}
@@ -947,7 +947,7 @@ export default {
});
if (res.data.message) {
window.alert(res.data.message);
window.alert(res.data.message); // eslint-disable-line no-alert
}
this.password = '';
@@ -545,7 +545,7 @@ export default {
if (this.workingChallenge.prize > this.maxPrize) errors.push(this.$t('cantAfford'));
if (errors.length > 0) {
window.alert(errors.join('\n'));
window.alert(errors.join('\n')); // eslint-disable-line no-alert
this.loading = false;
return;
}
@@ -148,7 +148,7 @@ export default {
this.$router.push('/challenges/myChallenges');
},
async deleteChallenge () {
if (!window.confirm(this.$t('sureDelCha'))) return;
if (!window.confirm(this.$t('sureDelCha'))) return; // eslint-disable-line no-alert
this.challenge = await this.$store.dispatch('challenges:deleteChallenge', {
challengeId: this.challengeId,
prize: this.prize,
@@ -329,7 +329,7 @@ export default {
});
},
async remove () {
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return;
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return; // eslint-disable-line no-alert
const message = this.msg;
this.$emit('message-removed', message);
@@ -6,7 +6,7 @@
:hide-footer="true"
>
<div class="modal-body">
<strong v-html="$t('abuseFlagModalHeading', reportData)"></strong>
<strong v-html="$t('abuseFlagModalHeading')"></strong>
<blockquote>
<div v-markdown="abuseObject.text"></div>
</blockquote>
@@ -113,14 +113,6 @@ export default {
},
computed: {
...mapState({ user: 'user.data' }),
reportData () {
let reportMessage = this.abuseObject.user;
const isSystemMessage = this.abuseObject.uuid === 'system';
if (isSystemMessage) reportMessage = this.$t('systemMessage');
return {
name: `<span class='text-danger'>${reportMessage}</span>`,
};
},
},
mounted () {
this.$root.$on('habitica::report-chat', this.handleReport);
@@ -48,7 +48,7 @@ export default {
computed: {
...mapState({
user: 'user.data',
groupPlans: 'groupPlans',
groupPlans: 'groupPlans.data',
}),
currentGroup () {
const groupFound = this.groupPlans.find(group => group._id === this.groupId);

Some files were not shown because too many files have changed in this diff Show More