Compare commits

...

222 Commits

Author SHA1 Message Date
Sabe Jones
98de7f634d 4.183.0 2021-02-25 16:04:17 -06:00
Sabe Jones
a459e54586 feat(content): March Mystery Items 2021-02-25 15:51:17 -06:00
Sabe Jones
7cc705ffcd fix(test): should hatch Desert pet to get Desert achievement 2021-02-16 17:08:59 -06:00
Sabe Jones
10a4dc5128 4.182.0 2021-02-16 17:00:46 -06:00
Sabe Jones
ee1f95bb67 feat(content): bundle and cheevo 2021-02-16 17:00:39 -06:00
Sabe Jones
0fad23ad80 4.181.3 2021-02-09 18:01:18 -06:00
Sabe Jones
05f6c6816f fix(event): Valentines does not have class outfits 2021-02-09 18:01:12 -06:00
Sabe Jones
df005d1f6b 4.181.2 2021-02-09 12:46:39 -06:00
Sabe Jones
8c59014b05 feat(event): Valentine's 2021 2021-02-08 16:12:10 -06:00
Sabe Jones
aa227f9861 fix(background): icon sprite correction from Dec 2021-02-03 13:15:05 -06:00
Sabe Jones
4525fa4401 Merge branch 'release' into develop 2021-02-03 13:01:40 -06:00
Sabe Jones
19e88448b7 4.181.1 2021-02-03 11:21:55 -06:00
Sabe Jones
1ffa6359a9 fix(backgrounds): add missing icons 2021-02-03 11:21:43 -06:00
Sabe Jones
b9bdc3aff9 Merge branch 'release' into develop 2021-02-02 17:55:24 -06:00
Sabe Jones
37f2e5e002 4.181.0 2021-02-02 17:07:28 -06:00
Sabe Jones
24904df79a chore(sprites): compile 2021-02-02 17:07:19 -06:00
Sabe Jones
10f4884505 feat(content): Armoire and Backgrounds February 2021 2021-02-02 17:07:10 -06:00
Alys
1b73c5ac0b adjust apidoc comments to say that "party" works for member routes 2021-02-02 20:13:55 +10:00
Melior
c3d76c0e23 Merge branch 'origin/develop' into Weblate. 2021-02-01 21:56:08 +01:00
Melior
b7362f6c1a Translated using Weblate (Bosnian)
Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Greek)

Currently translated at 6.6% (12 of 181 strings)

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

Translated using Weblate (Greek)

Currently translated at 87.4% (111 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/el/

Translated using Weblate (Bosnian)

Currently translated at 86.6% (110 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/bs/

Translated using Weblate (Greek)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (368 of 368 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% (203 of 203 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Greek)

Currently translated at 4.5% (5 of 111 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 60.3% (67 of 111 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (85 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/bs/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 97.2% (176 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 75.0% (439 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 75.9% (1705 of 2245 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Greek)

Currently translated at 74.7% (437 of 585 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 73.2% (41 of 56 strings)

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

Translated using Weblate (Greek)

Currently translated at 74.3% (435 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (13 of 13 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (127 of 127 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/en@pirate/
2021-02-01 21:55:55 +01:00
Sabe Jones
277224e4f9 Merge branch 'release' into develop 2021-02-01 14:54:16 -06:00
Sabe Jones
217cf493ec 4.180.0 2021-02-01 14:53:06 -06:00
Sabe Jones
10030b5281 feat(content): February 2021 Mystery Items 2021-02-01 14:52:28 -06:00
Alys
8d596ca5cd fix set item number for Light Lunar Sai in Blue Moon Rogue Set 2021-02-01 19:11:04 +10:00
Alys
9a8c34f780 remove alias from apidoc Body Parameters for creating a challenge task
https://habitica.com/apidoc/#api-Task-CreateChallengeTasks

Aliases can't be added by the challenge creator as shown by this test:
2dad540d43/test/api/v3/integration/tasks/challenges/POST-tasks_challenge_id.test.js (L77-L87)

That's a requirement because in each user's account, each alias must
be unique, and you can't enforce that if the challenge creator can
assign an alias.
2021-02-01 09:37:20 +10:00
Alys
2dad540d43 fix minor typo in FAQ 2021-01-30 20:11:22 +10:00
Sabe Jones
e70ebde392 4.179.1 2021-01-28 17:03:08 -06:00
Sabe Jones
04b4e63e80 fix(lint): puppy pressed the spacebar 2021-01-28 17:02:44 -06:00
Sabe Jones
03794f292d fix(event): Cake in shops and drops 2021-01-28 16:59:43 -06:00
Sabe Jones
b63dcf74ca 4.179.0 2021-01-28 16:56:22 -06:00
Sabe Jones
6dbbdd8070 feat(content): Habitica Birthday 2021 2021-01-28 16:56:01 -06:00
Sabe Jones
6022cb6c79 Merge branch 'develop' into release 2021-01-28 16:21:25 -06:00
Sabe Jones
8afb82ceae 4.178.4 2021-01-26 22:11:25 -06:00
Melior
3159f7d12c chore(i18n): update locale files 2021-01-26 22:11:17 -06:00
Melior
90fe57fb9c Translated using Weblate (Spanish)
Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Spanish)

Currently translated at 90.2% (2025 of 2245 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 66.0% (37 of 56 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 74.0% (433 of 585 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (61 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/bs/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Hindi)

Currently translated at 99.4% (186 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 73.6% (431 of 585 strings)

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

Translated using Weblate (Hindi)

Currently translated at 97.1% (101 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Arabic)

Currently translated at 63.0% (70 of 111 strings)

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

Translated using Weblate (Arabic)

Currently translated at 88.1% (112 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ar/

Translated using Weblate (Greek)

Currently translated at 73.3% (429 of 585 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/

Translated using Weblate (Hindi)

Currently translated at 99.4% (186 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Greek)

Currently translated at 72.9% (427 of 585 strings)

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

Translated using Weblate (Hindi)

Currently translated at 64.2% (117 of 182 strings)

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

Translated using Weblate (English)

Currently translated at 64.8% (118 of 182 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en@lolcat/

Translated using Weblate (Hindi)

Currently translated at 86.8% (53 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/hi/

Translated using Weblate (Bosnian)

Currently translated at 83.6% (51 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/bs/

Translated using Weblate (Bosnian)

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Hindi)

Currently translated at 75.8% (1703 of 2245 strings)

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

Translated using Weblate (Hindi)

Currently translated at 75.8% (1703 of 2245 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (54 of 54 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/hi/

Translated using Weblate (Hindi)

Currently translated at 88.5% (324 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/hi/

Translated using Weblate (Japanese)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Basque)

Currently translated at 1.1% (2 of 181 strings)

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

Translated using Weblate (Hindi)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Basque)

Currently translated at 100.0% (13 of 13 strings)

Translation: Habitica/Rebirth
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/eu/

Translated using Weblate (Basque)

Currently translated at 63.4% (66 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Spanish)

Currently translated at 89.3% (2005 of 2245 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (104 of 104 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
2021-01-27 05:06:40 +01:00
negue
1bccbc03fa Hotfix: moving pinned items (#12935)
* increase checks for moving pinned items - fixes #10406

* allow to move official pinneditems

* using common object instead of method import
2021-01-25 17:40:18 -06:00
Sabe Jones
91fc5a931c Revert "build(deps): bump bootstrap from 4.5.3 to 4.6.0 in /website/client (#13004)"
This reverts commit a6f0893ee4.
2021-01-25 17:02:51 -06:00
Bart Enkelaar
a543531956 Fix error logs in client unit tests from setTitle (#12967) 2021-01-25 16:52:26 -06:00
shantanu96
43fc390e28 #12970 Fixed 'String " not found' bug in categories while saving guild descr… (#12989)
* Fixed 'String " not found' bug in categories while saving guild description

* syntax changes
2021-01-25 16:44:52 -06:00
dependabot-preview[bot]
c6cf4cfc75 build(deps): bump vue-cli-plugin-storybook in /website/client (#13008)
Bumps [vue-cli-plugin-storybook](https://github.com/storybooks/vue-cli-plugin-storybook) from 0.6.1 to 2.0.0.
- [Release notes](https://github.com/storybooks/vue-cli-plugin-storybook/releases)
- [Changelog](https://github.com/storybookjs/vue-cli-plugin-storybook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/storybooks/vue-cli-plugin-storybook/compare/v0.6.1...v2.0.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 16:12:51 -06:00
dependabot-preview[bot]
f8483ef80c build(deps-dev): bump sinon from 9.2.3 to 9.2.4 (#12992)
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.2.3 to 9.2.4.
- [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.2.3...v9.2.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:55:16 -06:00
dependabot-preview[bot]
f60fd85dea build(deps): bump @storybook/vue in /website/client (#12996)
Bumps [@storybook/vue](https://github.com/storybookjs/storybook/tree/HEAD/app/vue) from 5.3.19 to 6.1.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.1.15/app/vue)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:54:45 -06:00
dependabot-preview[bot]
9a01255f41 build(deps): bump @storybook/addon-knobs in /website/client (#12994)
Bumps [@storybook/addon-knobs](https://github.com/storybookjs/storybook/tree/HEAD/addons/knobs) from 5.3.19 to 6.1.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.1.15/addons/knobs)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:35:53 -06:00
dependabot-preview[bot]
90d385c9b7 build(deps-dev): bump run-rs from 0.7.3 to 0.7.4 (#12863)
Bumps [run-rs](https://github.com/vkarpov15/run-rs) from 0.7.3 to 0.7.4.
- [Release notes](https://github.com/vkarpov15/run-rs/releases)
- [Changelog](https://github.com/vkarpov15/run-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vkarpov15/run-rs/compare/0.7.3...0.7.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:35:20 -06:00
dependabot-preview[bot]
475ad8deb1 build(deps): bump webpack from 4.45.0 to 4.46.0 in /website/client (#12983)
Bumps [webpack](https://github.com/webpack/webpack) from 4.45.0 to 4.46.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.45.0...v4.46.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:33:51 -06:00
dependabot-preview[bot]
55a17af667 build(deps): bump helmet from 4.3.1 to 4.4.1 (#12991)
Bumps [helmet](https://github.com/helmetjs/helmet) from 4.3.1 to 4.4.1.
- [Release notes](https://github.com/helmetjs/helmet/releases)
- [Changelog](https://github.com/helmetjs/helmet/blob/main/CHANGELOG.md)
- [Commits](https://github.com/helmetjs/helmet/compare/v4.3.1...v4.4.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:32:30 -06:00
dependabot-preview[bot]
92ae0ddf54 build(deps): bump @storybook/addon-links in /website/client (#12997)
Bumps [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/addons/links) from 5.3.19 to 6.1.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.1.15/addons/links)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:31:10 -06:00
dependabot-preview[bot]
f856ee6a09 build(deps): bump @vue/cli-service in /website/client (#13001)
Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.11/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.11/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>
2021-01-25 15:10:50 -06:00
dependabot-preview[bot]
b8d459be1c build(deps): bump @vue/cli-plugin-router in /website/client (#12998)
Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.11/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.11/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>
2021-01-25 15:10:10 -06:00
dependabot-preview[bot]
93ee7cd5c9 build(deps): bump @vue/cli-plugin-babel in /website/client (#13000)
Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.11/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.11/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>
2021-01-25 15:09:53 -06:00
dependabot-preview[bot]
70b016f482 build(deps): bump csv-stringify from 5.6.0 to 5.6.1 (#12976)
Bumps [csv-stringify](https://github.com/adaltas/node-csv-stringify) from 5.6.0 to 5.6.1.
- [Release notes](https://github.com/adaltas/node-csv-stringify/releases)
- [Changelog](https://github.com/adaltas/node-csv-stringify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/adaltas/node-csv-stringify/compare/v5.6.0...v5.6.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:09:18 -06:00
dependabot-preview[bot]
fced7f52d9 build(deps): bump amplitude-js from 7.4.0 to 7.4.1 in /website/client (#12985)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.4.0 to 7.4.1.
- [Release notes](https://github.com/amplitude/amplitude-javascript/releases)
- [Changelog](https://github.com/amplitude/Amplitude-JavaScript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/amplitude/amplitude-javascript/compare/v7.4.0...v7.4.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:07:55 -06:00
dependabot-preview[bot]
48db11e4a1 build(deps): bump stripe from 8.130.0 to 8.132.0 (#12993)
Bumps [stripe](https://github.com/stripe/stripe-node) from 8.130.0 to 8.132.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v8.130.0...v8.132.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:07:19 -06:00
dependabot-preview[bot]
9adb71a58f build(deps): bump mongoose from 5.11.11 to 5.11.13 (#12990)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.11.11 to 5.11.13.
- [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.11.11...5.11.13)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:06:28 -06:00
dependabot-preview[bot]
cf03bf11ae build(deps): bump sass from 1.32.2 to 1.32.5 in /website/client (#12999)
Bumps [sass](https://github.com/sass/dart-sass) from 1.32.2 to 1.32.5.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.32.2...1.32.5)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:04:24 -06:00
dependabot-preview[bot]
4b08451e53 build(deps): bump inspectpack from 4.5.2 to 4.6.1 in /website/client (#12995)
Bumps [inspectpack](https://github.com/FormidableLabs/inspectpack) from 4.5.2 to 4.6.1.
- [Release notes](https://github.com/FormidableLabs/inspectpack/releases)
- [Changelog](https://github.com/FormidableLabs/inspectpack/blob/master/HISTORY.md)
- [Commits](https://github.com/FormidableLabs/inspectpack/compare/v4.5.2...v4.6.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 15:02:41 -06:00
dependabot-preview[bot]
ca882c83ea build(deps): bump core-js from 3.8.2 to 3.8.3 in /website/client (#13003)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.8.2 to 3.8.3.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.8.2...v3.8.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 14:57:05 -06:00
dependabot-preview[bot]
a6f0893ee4 build(deps): bump bootstrap from 4.5.3 to 4.6.0 in /website/client (#13004)
Bumps [bootstrap](https://github.com/twbs/bootstrap) from 4.5.3 to 4.6.0.
- [Release notes](https://github.com/twbs/bootstrap/releases)
- [Commits](https://github.com/twbs/bootstrap/compare/v4.5.3...v4.6.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 14:56:46 -06:00
dependabot-preview[bot]
7208740fb6 build(deps): bump @storybook/addon-actions in /website/client (#13005)
Bumps [@storybook/addon-actions](https://github.com/storybookjs/storybook/tree/HEAD/addons/actions) from 5.3.19 to 6.1.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.1.15/addons/actions)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-25 14:56:00 -06:00
dependabot-preview[bot]
e596ea6f03 build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#13006)
Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.11/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.11/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>
2021-01-25 14:52:25 -06:00
dependabot-preview[bot]
5ee2d4a0e5 build(deps): bump @vue/cli-plugin-eslint in /website/client (#13007)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.11/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.11/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>
2021-01-25 14:52:03 -06:00
Melior
c001831e63 Merge branch 'origin/develop' into Weblate. 2021-01-22 21:12:20 +01:00
Sabe Jones
55550d0562 4.178.3 2021-01-22 14:09:58 -06:00
Sabe Jones
4db1b1cdfa Merge branch 'develop' into release 2021-01-22 14:09:49 -06:00
Melior
bf1f7672db Translated using Weblate (Arabic)
Currently translated at 60.3% (67 of 111 strings)

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

Translated using Weblate (Greek)

Currently translated at 72.6% (425 of 585 strings)

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

Translated using Weblate (Arabic)

Currently translated at 67.0% (122 of 182 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (13 of 13 strings)

Translation: Habitica/Rebirth
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/bs/

Translated using Weblate (Bosnian)

Currently translated at 27.7% (15 of 54 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.4% (1985 of 2245 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Arabic)

Currently translated at 3.6% (4 of 111 strings)

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

Translated using Weblate (Arabic)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Arabic)

Currently translated at 75.8% (1702 of 2245 strings)

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

Translated using Weblate (Arabic)

Currently translated at 84.1% (308 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ar/

Translated using Weblate (Greek)

Currently translated at 72.3% (423 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (127 of 127 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 71.9% (421 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (85 of 85 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (13 of 13 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (127 of 127 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2 of 2 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Greek)

Currently translated at 71.6% (419 of 585 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 70.9% (415 of 585 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 53.1% (59 of 111 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (8 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/bs/

Translated using Weblate (Bosnian)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Greek)

Currently translated at 70.5% (413 of 585 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 22.5% (25 of 111 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 99.0% (201 of 203 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.8% (2241 of 2245 strings)

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

Translated using Weblate (Greek)

Currently translated at 2.7% (3 of 111 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.7% (2239 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.7% (2239 of 2245 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

Translation: Habitica/Limited
Translate-URL: https://translate.habitica.com/projects/habitica/limited/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 (Japanese)

Currently translated at 99.5% (2236 of 2245 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.5% (2236 of 2245 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2245 of 2245 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% (2245 of 2245 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% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/

Translated using Weblate (Greek)

Currently translated at 96.1% (100 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (2232 of 2245 strings)

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

Translated using Weblate (Czech)

Currently translated at 99.0% (101 of 102 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Czech)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Czech)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Greek)

Currently translated at 94.2% (98 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 97.5% (198 of 203 strings)

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

Translated using Weblate (Persian)

Currently translated at 35.1% (19 of 54 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.2% (2228 of 2245 strings)

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

Translated using Weblate (Swedish)

Currently translated at 70.1% (73 of 104 strings)

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

Translated using Weblate (Swedish)

Currently translated at 70.1% (73 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (2 of 2 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (1 of 1 strings)

Translation: Habitica/Merch
Translate-URL: https://translate.habitica.com/projects/habitica/merch/bs/

Translated using Weblate (Dutch)

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (85 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/nl/

Translated using Weblate (Dutch)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/nl/

Translated using Weblate (Dutch)

Currently translated at 100.0% (61 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/nl/

Translated using Weblate (Dutch)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Dutch)

Currently translated at 95.5% (692 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Greek)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.0% (2224 of 2245 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (54 of 54 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/nl/

Translated using Weblate (Dutch)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Greek)

Currently translated at 87.5% (91 of 104 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/

Translated using Weblate (Japanese)

Currently translated at 98.8% (2220 of 2245 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (English)

Currently translated at 0.8% (5 of 585 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/en@lolcat/

Translated using Weblate (English)

Currently translated at 100.0% (102 of 102 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/en@lolcat/

Translated using Weblate (English)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/en@lolcat/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/

Translated using Weblate (Japanese)

Currently translated at 98.7% (2216 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Persian)

Currently translated at 12.5% (13 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 83.6% (87 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/bs/

Translated using Weblate (Bosnian)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.5% (2212 of 2245 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Greek)

Currently translated at 77.8% (81 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/cs/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2245 of 2245 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% (2245 of 2245 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% (2245 of 2245 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% (2245 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 99.6% (583 of 585 strings)

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

Translated using Weblate (English)

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/en@lolcat/

Translated using Weblate (Bengali)

Currently translated at 96.2% (180 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 73.0% (76 of 104 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 89.3% (176 of 197 strings)

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

Translated using Weblate (Urdu (Pakistan))

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Klingon)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Thai)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Tamil)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Swahili)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Sundanese)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 56.8% (112 of 197 strings)

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

Translated using Weblate (Sinhala)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Scots)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Malay)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Mongolian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Malayalam)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Macedonian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Latvian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Lingala)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Latin)

Currently translated at 57.3% (113 of 197 strings)

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

Translated using Weblate (Kurdish)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Korean)

Currently translated at 62.4% (123 of 197 strings)

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

Translated using Weblate (Javanese)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Lojban)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Hindi)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Hawaiian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Galician)

Currently translated at 55.8% (110 of 197 strings)

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

Translated using Weblate (Irish)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Frisian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Filipino)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Finnish)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Persian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Estonian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Esperanto)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (English)

Currently translated at 56.3% (111 of 197 strings)

Translation: Habitica/Limited
Translate-URL: https://translate.habitica.com/projects/habitica/limited/en@lolcat/

Translated using Weblate (Greek)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Catalan)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Bengali)

Currently translated at 58.3% (115 of 197 strings)

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

Translated using Weblate (Belarusian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Arabic)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Afrikaans)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Acholi)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Thai)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 96.4% (698 of 724 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 87.5% (7 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/pt/

Translated using Weblate (Ukrainian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Serbian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Slovak)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Romanian)

Currently translated at 83.2% (164 of 197 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 69.5% (137 of 197 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Hebrew)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Danish)

Currently translated at 56.8% (112 of 197 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Marathi)

Currently translated at 56.3% (111 of 197 strings)

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

Translated using Weblate (Greek)

Currently translated at 70.1% (73 of 104 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Dutch)

Currently translated at 97.6% (124 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/nl/

Translated using Weblate (Dutch)

Currently translated at 96.9% (191 of 197 strings)

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

Translated using Weblate (Dutch)

Currently translated at 96.1% (2158 of 2245 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Greek)

Currently translated at 68.2% (71 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 99.1% (122 of 123 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.9% (695 of 724 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Serbian)

Currently translated at 69.2% (126 of 182 strings)

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

Translated using Weblate (Russian)

Currently translated at 87.9% (160 of 182 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (182 of 182 strings)

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

Translated using Weblate (Serbian)

Currently translated at 93.6% (104 of 111 strings)

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

Translated using Weblate (Serbian)

Currently translated at 85.0% (108 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/sr/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2245 of 2245 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Serbian)

Currently translated at 85.2% (52 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/sr/

Translated using Weblate (Czech)

Currently translated at 98.3% (60 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/cs/

Translated using Weblate (Serbian)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Serbian)

Currently translated at 76.1% (1710 of 2245 strings)

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

Translated using Weblate (Russian)

Currently translated at 91.9% (2064 of 2245 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2245 of 2245 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% (2245 of 2245 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.3% (2208 of 2245 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 99.3% (2231 of 2245 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Serbian)

Currently translated at 97.5% (198 of 203 strings)

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

Translated using Weblate (German)

Currently translated at 99.5% (2234 of 2245 strings)

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

Translated using Weblate (German)

Currently translated at 99.5% (2234 of 2245 strings)

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

Translated using Weblate (Serbian)

Currently translated at 96.1% (174 of 181 strings)

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

Translated using Weblate (Serbian)

Currently translated at 35.1% (19 of 54 strings)

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

Translated using Weblate (Serbian)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Serbian)

Currently translated at 71.7% (420 of 585 strings)

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

Translated using Weblate (Russian)

Currently translated at 96.9% (567 of 585 strings)

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

Translated using Weblate (Dutch)

Currently translated at 93.5% (547 of 585 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Serbian)

Currently translated at 35.5% (37 of 104 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Serbian)

Currently translated at 92.8% (168 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (585 of 585 strings)

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

Translated using Weblate (Dutch)

Currently translated at 91.3% (95 of 104 strings)

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

Translated using Weblate (Dutch)

Currently translated at 91.3% (95 of 104 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
2021-01-22 15:15:14 +01:00
dependabot-preview[bot]
5f7e3fa4e7 build(deps): bump @vue/cli-service in /website/client (#12957)
Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.9 to 4.5.10.
- [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.10/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>
2021-01-11 12:38:24 +01:00
dependabot-preview[bot]
fde2359334 build(deps): bump @vue/cli-plugin-router in /website/client (#12960)
Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.9 to 4.5.10.
- [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.10/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>
2021-01-11 12:38:07 +01:00
dependabot-preview[bot]
95c8958e13 build(deps): bump sass from 1.32.0 to 1.32.2 in /website/client (#12961)
Bumps [sass](https://github.com/sass/dart-sass) from 1.32.0 to 1.32.2.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.32.0...1.32.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 12:37:51 +01:00
dependabot-preview[bot]
28e09d3905 build(deps): bump @vue/cli-plugin-babel in /website/client (#12954)
Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.9 to 4.5.10.
- [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.10/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>
2021-01-11 11:50:42 +01:00
dependabot-preview[bot]
85b1b49950 build(deps): bump webpack from 4.44.2 to 4.45.0 in /website/client (#12958)
Bumps [webpack](https://github.com/webpack/webpack) from 4.44.2 to 4.45.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.44.2...v4.45.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 11:34:06 +01:00
dependabot-preview[bot]
e19c24024a build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#12956)
Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.9 to 4.5.10.
- [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.10/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>
2021-01-11 11:33:48 +01:00
dependabot-preview[bot]
2cbceef84b build(deps): bump @vue/cli-plugin-eslint in /website/client (#12952)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.9 to 4.5.10.
- [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.10/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>
2021-01-11 11:33:30 +01:00
dependabot-preview[bot]
a308796672 build(deps): bump nconf from 0.11.0 to 0.11.1 in /website/client (#12953)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/flatiron/nconf/releases)
- [Changelog](https://github.com/indexzero/nconf/blob/master/CHANGELOG.md)
- [Commits](https://github.com/flatiron/nconf/compare/v0.11.0...v0.11.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 11:33:12 +01:00
dependabot-preview[bot]
b978234531 build(deps): bump amplitude-js from 7.3.3 to 7.4.0 in /website/client (#12955)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.3.3 to 7.4.0.
- [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.3.3...v7.4.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 11:32:55 +01:00
dependabot-preview[bot]
a8deeaec76 build(deps): bump @slack/webhook from 5.0.3 to 5.0.4 (#12944)
Bumps [@slack/webhook](https://github.com/slackapi/node-slack-sdk) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/slackapi/node-slack-sdk/releases)
- [Commits](https://github.com/slackapi/node-slack-sdk/compare/@slack/webhook@5.0.3...@slack/webhook@5.0.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:25:22 +01:00
dependabot-preview[bot]
38c84ae3a0 build(deps): bump apple-auth from 1.0.6 to 1.0.7 (#12942)
Bumps [apple-auth](https://github.com/ananay/apple-auth) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/ananay/apple-auth/releases)
- [Commits](https://github.com/ananay/apple-auth/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:23:34 +01:00
dependabot-preview[bot]
89f8952d76 build(deps): bump jwks-rsa from 1.12.1 to 1.12.2 (#12943)
Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.12.1 to 1.12.2.
- [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.12.1...v1.12.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:03:21 +01:00
dependabot-preview[bot]
6cccdc67b0 build(deps-dev): bump sinon from 9.2.2 to 9.2.3 (#12946)
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.2.2 to 9.2.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.2.2...v9.2.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:02:42 +01:00
dependabot-preview[bot]
ca853c9cfe build(deps): bump mongoose from 5.11.10 to 5.11.11 (#12947)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.11.10 to 5.11.11.
- [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.11.10...5.11.11)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:02:32 +01:00
dependabot-preview[bot]
d044df8e33 build(deps): bump apidoc from 0.25.0 to 0.26.0 (#12948)
Bumps [apidoc](https://github.com/apidoc/apidoc) from 0.25.0 to 0.26.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.25.0...0.26.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:02:15 +01:00
dependabot-preview[bot]
3de7951e2d build(deps): bump rate-limiter-flexible from 2.1.16 to 2.2.1 (#12949)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.16 to 2.2.1.
- [Release notes](https://github.com/animir/node-rate-limiter-flexible/releases)
- [Commits](https://github.com/animir/node-rate-limiter-flexible/commits/v2.2.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:02:03 +01:00
dependabot-preview[bot]
3721c044c8 build(deps): bump nconf from 0.11.0 to 0.11.1 (#12950)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/flatiron/nconf/releases)
- [Changelog](https://github.com/indexzero/nconf/blob/master/CHANGELOG.md)
- [Commits](https://github.com/flatiron/nconf/compare/v0.11.0...v0.11.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:01:51 +01:00
dependabot-preview[bot]
1000e283cc build(deps): bump stripe from 8.129.0 to 8.130.0 (#12951)
Bumps [stripe](https://github.com/stripe/stripe-node) from 8.129.0 to 8.130.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v8.129.0...v8.130.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-11 10:01:38 +01:00
bakerty
db3d233ae5 Make start date and day of month aware of timezones (fixes #12555) (#12696)
* WIP: #12555

-dayOfMonth takes timezone into account on task update for monthly dailys
-startDate set to start of day in user's tz on task update for monthly
dailys
-tweaked a test so that it's actually testing something

* WIP: 12555

-task.startDate gets set to start of day in user's tz on task creation
and task update
-set preferences.timezoneOffset to nonzero value in certian test user objects
-removed date literals in test:api-v3:integration:tasks:PUT
2021-01-10 16:02:40 +01:00
Mike-Antonacci
e8d3090a99 Add string blockYourself (#12939) 2021-01-09 16:11:44 +01:00
Jon Wolverton
39e7f51258 remove PER bonus for Brilliant Bloom (summer 2019 mage weapon) (#12923) 2021-01-09 15:53:31 +01:00
Sabe Jones
abf371ba12 4.178.2 2021-01-08 13:56:38 -06:00
Sabe Jones
f02b7c16e1 fix(test): d'oh 2021-01-08 13:43:27 -06:00
Sabe Jones
cec01f49bd fix(test): dummy event to test promotions 2021-01-08 13:34:04 -06:00
Sabe Jones
b88389787d 4.178.1 2021-01-08 13:11:13 -06:00
Sabe Jones
04e366d498 Merge branch 'develop' into release 2021-01-08 13:11:02 -06:00
Sabe Jones
2d5ddfdd87 fix(event): borken Gold gear
and default sub analytics to web
2021-01-08 13:10:45 -06:00
JohnJSal
2c2b776968 Update achievements.json (#12858)
Capitalized "pets" for Golden, Skeleton, and Red collection achievement text, to be consistent with all others.
2021-01-07 17:33:22 +01:00
Matteo Pagliazzi
1dc8be4842 Stripe Upgrade Cleanup (#12882)
* chore(stripe): remove manual api version from code

* upgrade minor stripe version
2021-01-07 17:32:54 +01:00
Alys
9d93821758 remove mentiod of Back Corner from Community Guidelines. (#12901)
This includes deleting the Back Corner image.
2021-01-07 17:31:42 +01:00
Óscar Carretero
14e99c6e6c Remove forum link (#12917)
* remove forum link

* remove `communityForum` from locales
2021-01-07 17:30:39 +01:00
Melior
7433eeb883 Merge branch 'origin/develop' into Weblate. 2021-01-05 22:45:54 +01:00
Melior
68ecc2eec4 Translated using Weblate (Greek)
Currently translated at 66.3% (69 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.6% (2200 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (180 of 181 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 64.4% (67 of 104 strings)

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

Translated using Weblate (Arabic)

Currently translated at 76.2% (1701 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (134 of 134 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% (8 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (368 of 368 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% (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 100.0% (54 of 54 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (180 of 181 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 76.8% (1714 of 2231 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Czech)

Currently translated at 86.1% (1921 of 2231 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 68.5% (124 of 181 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.1% (689 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.4% (2196 of 2231 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.0% (1965 of 2231 strings)

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

Translated using Weblate (Spanish)

Currently translated at 96.1% (696 of 724 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 58.6% (61 of 104 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 58.6% (61 of 104 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 58.6% (61 of 104 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 54.8% (57 of 104 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 54.8% (57 of 104 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 54.8% (57 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 58.6% (61 of 104 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Macedonian)

Currently translated at 5.7% (6 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 93.2% (343 of 368 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.0% (688 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.0% (688 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 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% (2231 of 2231 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 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% (2231 of 2231 strings)

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

Translated using Weblate (Greek)

Currently translated at 87.5% (7 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/el/

Translated using Weblate (Greek)

Currently translated at 98.3% (60 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/el/

Translated using Weblate (Japanese)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.2% (2192 of 2231 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Greek)

Currently translated at 45.1% (47 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.8% (687 of 724 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.0% (2188 of 2231 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.5% (1953 of 2231 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (2228 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (2227 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.7% (2226 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.7% (2225 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.7% (2225 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.5% (2220 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.5% (2220 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2215 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2215 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2215 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2215 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.1% (2213 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.1% (2213 of 2231 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.8% (687 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.8% (687 of 724 strings)

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

Translated using Weblate (Greek)

Currently translated at 5.5% (10 of 181 strings)

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

Translated using Weblate (Greek)

Currently translated at 66.0% (37 of 56 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.1% (2212 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.8% (2184 of 2231 strings)

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

Translated using Weblate (Slovak)

Currently translated at 53.7% (29 of 54 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/

Translated using Weblate (Slovak)

Currently translated at 96.7% (181 of 187 strings)

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

Translated using Weblate (Slovak)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.4% (575 of 578 strings)

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

Translated using Weblate (Slovak)

Currently translated at 25.0% (26 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Greek)

Currently translated at 35.5% (37 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 35.5% (37 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 76.6% (1709 of 2231 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 92.3% (12 of 13 strings)

Translation: Habitica/Rebirth
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/uk/

Translated using Weblate (Japanese)

Currently translated at 97.7% (2180 of 2231 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 98.3% (178 of 181 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 71.9% (416 of 578 strings)

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

Translated using Weblate (Greek)

Currently translated at 33.6% (35 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 33.6% (35 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 28.8% (30 of 104 strings)

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

Translated using Weblate (Greek)

Currently translated at 28.8% (30 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.3% (2172 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ru/

Translated using Weblate (Czech)

Currently translated at 98.9% (572 of 578 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Russian)

Currently translated at 94.4% (120 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ru/

Translated using Weblate (Russian)

Currently translated at 94.9% (187 of 197 strings)

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

Translated using Weblate (Russian)

Currently translated at 96.1% (354 of 368 strings)

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

Translated using Weblate (Russian)

Currently translated at 92.3% (2060 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.1% (2168 of 2231 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (85 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/ja/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es_419/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/en_GB/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.3% (2217 of 2231 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/es_419/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.9% (2164 of 2231 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/en_GB/

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Russian)

Currently translated at 98.2% (55 of 56 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/fr/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.8% (2160 of 2231 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ru/

Translated using Weblate (Russian)

Currently translated at 97.4% (563 of 578 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/

Translated using Weblate (English (Pirate))

Currently translated at 98.4% (194 of 197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.6% (2156 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 5.5% (10 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/

Translated using Weblate (Japanese)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (127 of 127 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/

Translated using Weblate (German)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (195 of 197 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (195 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.9% (193 of 197 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2206 of 2231 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2206 of 2231 strings)

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

Translated using Weblate (Dutch)

Currently translated at 95.9% (2141 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.4% (2152 of 2231 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.7% (2203 of 2231 strings)

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

Translated using Weblate (German)

Currently translated at 99.8% (2228 of 2231 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/de/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.4% (196 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.4% (196 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.4% (194 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.4% (194 of 197 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 94.9% (187 of 197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.4% (125 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/

Translated using Weblate (Italian)

Currently translated at 100.0% (127 of 127 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/it/

Translated using Weblate (Japanese)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (197 of 197 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (368 of 368 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.9% (2140 of 2231 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2231 of 2231 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ja/

Translated using Weblate (Italian)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/it/

Translated using Weblate (French)

Currently translated at 100.0% (366 of 366 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/fr/

Translated using Weblate (Italian)

Currently translated at 100.0% (181 of 181 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/it/
2021-01-05 22:45:44 +01:00
Sabe Jones
c68c8536de Merge branch 'release' into develop 2021-01-05 15:41:35 -06:00
Sabe Jones
fce8028e29 4.178.0 2021-01-05 15:41:07 -06:00
Sabe Jones
845fcd41b4 chore(sprites): compile 2021-01-04 15:30:48 -06:00
Sabe Jones
f172670aa4 feat(content): BGs and Armoire Jan 2021 2021-01-04 15:30:39 -06:00
dependabot-preview[bot]
405f744770 build(deps): bump mongoose from 5.11.8 to 5.11.9 (#12927)
* build(deps): bump mongoose from 5.11.8 to 5.11.9

Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.11.8 to 5.11.9.
- [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.11.8...5.11.9)

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

* fix(join group): update inviter once

* mongoose@5.11.10

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2021-01-04 21:37:51 +01:00
dependabot-preview[bot]
7222ee0a10 build(deps): bump core-js from 3.8.1 to 3.8.2 in /website/client (#12929)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.8.1 to 3.8.2.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.8.1...v3.8.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-04 15:28:58 +01:00
dependabot-preview[bot]
6d4da01d36 build(deps): bump rate-limiter-flexible from 2.1.15 to 2.1.16 (#12924)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.15 to 2.1.16.
- [Release notes](https://github.com/animir/node-rate-limiter-flexible/releases)
- [Commits](https://github.com/animir/node-rate-limiter-flexible/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-04 15:28:28 +01:00
dependabot-preview[bot]
84b184617f build(deps): bump jwks-rsa from 1.12.0 to 1.12.1 (#12925)
Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.12.0 to 1.12.1.
- [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.12.0...v1.12.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-04 15:28:09 +01:00
dependabot-preview[bot]
87e46da6a3 build(deps): bump sass from 1.30.0 to 1.32.0 in /website/client (#12928)
Bumps [sass](https://github.com/sass/dart-sass) from 1.30.0 to 1.32.0.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.30.0...1.32.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-04 15:26:21 +01:00
dependabot-preview[bot]
d8199f71a8 build(deps): bump bootstrap-vue from 2.21.1 to 2.21.2 in /website/client (#12930)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.21.1 to 2.21.2.
- [Release notes](https://github.com/bootstrap-vue/bootstrap-vue/releases)
- [Changelog](https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.21.1...v2.21.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-01-04 15:26:01 +01:00
Matteo Pagliazzi
20a6103457 Merge branch 'release' into develop 2021-01-02 17:51:59 +01:00
Sabe Jones
539ffbf08a 4.177.0 2020-12-30 16:43:45 -06:00
Sabe Jones
b2adc29bf6 feat(content): 2021 January Mystery 2020-12-30 16:43:32 -06:00
Sabe Jones
920ee56bdf Merge branch 'release' into develop 2020-12-29 18:59:38 -06:00
Sabe Jones
1f077451d2 4.176.0 2020-12-29 18:59:15 -06:00
Sabe Jones
595a31db99 feat(content): NYE hats 2020-12-29 18:58:57 -06:00
dependabot-preview[bot]
7e0d7a4ba0 build(deps-dev): bump axios from 0.21.0 to 0.21.1 (#12908)
Bumps [axios](https://github.com/axios/axios) from 0.21.0 to 0.21.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v0.21.1/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.21.0...v0.21.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-12-28 10:50:22 +01:00
dependabot-preview[bot]
1c66b80424 build(deps): bump helmet from 4.2.0 to 4.3.1 (#12909)
Bumps [helmet](https://github.com/helmetjs/helmet) from 4.2.0 to 4.3.1.
- [Release notes](https://github.com/helmetjs/helmet/releases)
- [Changelog](https://github.com/helmetjs/helmet/blob/main/CHANGELOG.md)
- [Commits](https://github.com/helmetjs/helmet/compare/v4.2.0...v4.3.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-12-28 10:50:11 +01:00
dependabot-preview[bot]
5274ec2cc9 build(deps): bump csv-stringify from 5.5.3 to 5.6.0 (#12910)
Bumps [csv-stringify](https://github.com/adaltas/node-csv-stringify) from 5.5.3 to 5.6.0.
- [Release notes](https://github.com/adaltas/node-csv-stringify/releases)
- [Changelog](https://github.com/adaltas/node-csv-stringify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/adaltas/node-csv-stringify/compare/v5.5.3...v5.6.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-12-28 10:49:53 +01:00
dependabot-preview[bot]
8060422991 build(deps): bump axios from 0.21.0 to 0.21.1 in /website/client (#12912)
Bumps [axios](https://github.com/axios/axios) from 0.21.0 to 0.21.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v0.21.1/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.21.0...v0.21.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-12-28 10:49:40 +01:00
Matteo Pagliazzi
69e40e2114 4.175.8 2020-12-26 16:45:42 +01:00
Matteo Pagliazzi
17d918a172 fix(stripe): use new data structure for webhooks event.request 2020-12-26 16:45:36 +01:00
Matteo Pagliazzi
bc74e40280 4.175.7 2020-12-24 18:42:46 +01:00
Matteo Pagliazzi
4487363171 Merge branch 'develop' into release 2020-12-24 18:41:56 +01:00
Matteo Pagliazzi
dc72faad6a migration(todos date); filter by updatedAt 2020-12-24 18:41:01 +01:00
Shadow
7c0b3612f0 Change $type of date for todos (#12779)
* change $type to date for task and add new test

* adjust apidocs to reflect type change

* migration test for api date $type change

* minor fixes to migration

* unset instead of set empty string

* add type filter

* fix(todo date migration): make sure the update command works and limit update ops

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-12-24 18:37:09 +01:00
Sabe Jones
9a32eabb47 fix(lint): remove unused const 2020-12-22 16:53:26 -06:00
Sabe Jones
6fe0d5568a fix(script): truly unique email for many-accounts scenarios 2020-12-22 20:40:03 +00:00
Sabe Jones
2c44f766cd Merge branch 'release' into develop 2020-12-22 09:14:38 -06:00
Sabe Jones
c79e3bea05 4.175.6 2020-12-22 09:14:07 -06:00
Sabe Jones
b56f0cfeeb fix(content): auto rollout of potion didn't work? 2020-12-22 09:14:00 -06:00
dependabot-preview[bot]
fbf1849148 build(deps): bump @babel/preset-env from 7.12.10 to 7.12.11 (#12894)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.12.10 to 7.12.11.
- [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.12.11/packages/babel-preset-env)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-21 11:43:49 +01:00
dependabot-preview[bot]
a493bb69ce build(deps): bump stripe from 8.121.0 to 8.129.0 (#12895)
Bumps [stripe](https://github.com/stripe/stripe-node) from 8.121.0 to 8.129.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v8.121.0...v8.129.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-12-21 11:43:43 +01:00
dependabot-preview[bot]
7b20d02449 build(deps): bump rate-limiter-flexible from 2.1.14 to 2.1.15 (#12896)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.14 to 2.1.15.
- [Release notes](https://github.com/animir/node-rate-limiter-flexible/releases)
- [Commits](https://github.com/animir/node-rate-limiter-flexible/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-12-21 11:42:58 +01:00
dependabot-preview[bot]
207d1b7eaa build(deps): bump mongoose from 5.11.7 to 5.11.8 (#12897)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.11.7 to 5.11.8.
- [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.11.7...5.11.8)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-21 11:42:44 +01:00
dependabot-preview[bot]
f33aed661b build(deps): bump bootstrap-vue from 2.20.1 to 2.21.1 in /website/client (#12900)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.20.1 to 2.21.1.
- [Release notes](https://github.com/bootstrap-vue/bootstrap-vue/releases)
- [Changelog](https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.20.1...v2.21.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-12-21 11:42:27 +01:00
Sabe Jones
7f1d6ffef0 Merge branch 'release' into develop 2020-12-17 12:44:06 -06:00
Sabe Jones
75f198789b 4.175.5 2020-12-17 12:43:29 -06:00
Sabe Jones
6ad20e7abb fix(event): still one more find return 2020-12-17 12:43:16 -06:00
Matteo Pagliazzi
2705539a70 4.175.4 2020-12-17 18:04:47 +01:00
Matteo Pagliazzi
8f05fc250a Merge branch 'release' into develop 2020-12-17 18:03:58 +01:00
Matteo Pagliazzi
a21295c0e1 fix(pm): correctly show sender info when a new pm is sent, fixes #12889 2020-12-17 18:03:46 +01:00
Sabe Jones
24e13ddd18 Merge branch 'release' into develop 2020-12-17 09:37:09 -06:00
Sabe Jones
4d9e03b6d2 4.175.3 2020-12-17 09:36:55 -06:00
Sabe Jones
8a64def893 fix(event): more find syntax, fix featured items, no spoilers 2020-12-17 09:36:49 -06:00
Sabe Jones
e6f40aee43 Merge branch 'release' into develop 2020-12-17 08:25:26 -06:00
Sabe Jones
dc34db98b4 4.175.2 2020-12-17 08:25:09 -06:00
Sabe Jones
bd228d5d69 fix(event): correct return value for find 2020-12-17 08:25:04 -06:00
Matteo Pagliazzi
5d054a0acd Merge branch 'release' into develop 2020-12-17 10:27:15 +01:00
Matteo Pagliazzi
9a1fbc2d2f 4.175.1 2020-12-17 10:26:20 +01:00
Matteo Pagliazzi
7b0f43b61c fix(stable & bailey); seasonalNpc: use method instead of class, components: use correct method name for npc class 2020-12-17 10:26:06 +01:00
Melior
bc115bb1f6 Translated using Weblate (Portuguese)
Currently translated at 37.0% (20 of 54 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 86.5% (90 of 104 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 86.5% (90 of 104 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 86.5% (90 of 104 strings)

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

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (English (Pirate))

Currently translated at 99.8% (2199 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.1% (2140 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.5% (2170 of 2203 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (724 of 724 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% (123 of 123 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.1% (2141 of 2203 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.2% (2120 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.1% (2140 of 2203 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.3% (705 of 724 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 96.1% (100 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.9% (2114 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 95.4% (2103 of 2203 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.7% (686 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.7% (686 of 724 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.7% (2110 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 92.4% (2037 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 99.8% (723 of 724 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.5% (2106 of 2203 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.5% (2106 of 2203 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Turkish)

Currently translated at 80.2% (464 of 578 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 85.5% (89 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 85.5% (89 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 84.6% (88 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 84.6% (88 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 75.9% (79 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 75.9% (79 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 61.5% (64 of 104 strings)

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

Translated using Weblate (Turkish)

Currently translated at 61.5% (64 of 104 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 73.2% (41 of 56 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Korean)

Currently translated at 87.1% (504 of 578 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (61 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/ko/

Translated using Weblate (Korean)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Korean)

Currently translated at 96.1% (173 of 180 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/it/

Translated using Weblate (German)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Russian)

Currently translated at 93.4% (2059 of 2203 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.0% (1940 of 2203 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.2% (562 of 578 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (French)

Currently translated at 99.1% (573 of 578 strings)

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

Translated using Weblate (French)

Currently translated at 99.1% (573 of 578 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.3% (574 of 578 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 99.8% (577 of 578 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Korean)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/

Translated using Weblate (French)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/fr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2203 of 2203 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (578 of 578 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (2199 of 2203 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% (578 of 578 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
2020-12-17 06:50:17 +01:00
Sabe Jones
cd790e7228 4.175.0 2020-12-16 22:58:53 -06:00
Sabe Jones
bc1c637023 Merge branch 'sabrecat/winter-2021' into develop 2020-12-16 22:58:05 -06:00
Sabe Jones
eadbdeb7b8 Revert "WIP(event): Test values for event range--NOT FOR PRODUCTION"
This reverts commit 0d1643eb17.
2020-12-16 22:57:08 -06:00
Sabe Jones
585359e22f fix(event): missing gear strings 2020-12-16 22:52:46 -06:00
Sabe Jones
f0d6204968 Revert "fix(event): give notif to newbies"
This reverts commit cdb5ccf76a.
2020-12-16 18:40:53 -06:00
Sabe Jones
14fed0eb43 Revert "fix(event): give notif to newbies"
This reverts commit cdb5ccf76a.
2020-12-16 18:40:03 -06:00
Sabe Jones
427654d8bd fix(event): give notif to newbies 2020-12-16 17:49:31 -06:00
Sabe Jones
cdb5ccf76a fix(event): give notif to newbies 2020-12-16 17:46:32 -06:00
Sabe Jones
bf28a46803 feat(event): one more banner 2020-12-16 16:35:03 -06:00
Sabe Jones
84c10eb92a feat(event): one more banner 2020-12-16 16:33:47 -06:00
Sabe Jones
fa197e1b57 feat(event): add banner shinies 2020-12-15 20:08:33 -06:00
Sabe Jones
993c5552e8 feat(event): add banner shinies 2020-12-15 20:06:16 -06:00
Sabe Jones
1eba72dd36 fix(messages): adjust for G1G1 banner height 2020-12-15 16:42:14 -06:00
Sabe Jones
4457b081fa fix(messages): adjust for G1G1 banner height 2020-12-15 16:41:33 -06:00
Sabe Jones
395e1c25d4 fix(g1g1): correct blank private message 2020-12-15 16:07:31 -06:00
Sabe Jones
fdef94e826 fix(g1g1): correct blank private message 2020-12-15 15:54:29 -06:00
Sabe Jones
b3cfb57933 fix(events): EST not EDT 2020-12-15 09:52:37 -06:00
Sabe Jones
b4551088c1 fix(events): EST, not EDT 2020-12-15 09:50:01 -06:00
kevechen
26e6e583ab Fixes mention link in a private message (#12883) 2020-12-14 23:00:15 +01:00
Matteo Pagliazzi
81c7036cdb Merge branch 'release' into develop 2020-12-14 16:42:55 +01:00
Matteo Pagliazzi
23906d8f94 4.174.0 2020-12-14 16:01:14 +01:00
Matteo Pagliazzi
2d091fc667 Stripe: upgrade module and API, switch to Checkout (#12785)
* upgrade stripe module

* switch stripe api to latest version

* fix api version in tests

* start upgrading client and server

* client: switch to redirect

* implement checkout session creation for gems, start implementing webhooks

* stripe: start refactoring one time payments

* working gems and gift payments

* start adding support for subscriptions

* stripe: migrate subscriptions and fix cancelling sub

* allow upgrading group plans

* remove console.log statements

* group plans: upgrade from static page / create new one

* fix #11885, correct group plan modal title

* silence more stripe webhooks

* fix group plans redirects

* implement editing payment method

* start cleaning up code

* fix(stripe): update in-code docs, fix eslint issues

* subscriptions tests

* remove and skip old tests

* skip integration tests

* fix client build

* stripe webhooks: throw error if request fails

* subscriptions: correctly pass groupId

* remove console.log

* stripe: add unit tests for one time payments

* wip: stripe checkout tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests (editing card)

* fix existing webhooks tests

* add new webhooks tests

* add more webhooks tests

* fix lint

* stripe integration tests

* better error handling when retrieving customer from stripe

* client: remove unused strings and improve error handling

* payments: limit gift message length (server)

* payments: limit gift message length (client)

* fix redirects when payment is cancelled

* add back "subUpdateCard" string

* fix redirects when editing a sub card, use proper names for products, check subs when gifting
2020-12-14 16:01:07 +01:00
Matteo Pagliazzi
6d34319455 Stripe: upgrade module and API, switch to Checkout (#12785)
* upgrade stripe module

* switch stripe api to latest version

* fix api version in tests

* start upgrading client and server

* client: switch to redirect

* implement checkout session creation for gems, start implementing webhooks

* stripe: start refactoring one time payments

* working gems and gift payments

* start adding support for subscriptions

* stripe: migrate subscriptions and fix cancelling sub

* allow upgrading group plans

* remove console.log statements

* group plans: upgrade from static page / create new one

* fix #11885, correct group plan modal title

* silence more stripe webhooks

* fix group plans redirects

* implement editing payment method

* start cleaning up code

* fix(stripe): update in-code docs, fix eslint issues

* subscriptions tests

* remove and skip old tests

* skip integration tests

* fix client build

* stripe webhooks: throw error if request fails

* subscriptions: correctly pass groupId

* remove console.log

* stripe: add unit tests for one time payments

* wip: stripe checkout tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests (editing card)

* fix existing webhooks tests

* add new webhooks tests

* add more webhooks tests

* fix lint

* stripe integration tests

* better error handling when retrieving customer from stripe

* client: remove unused strings and improve error handling

* payments: limit gift message length (server)

* payments: limit gift message length (client)

* fix redirects when payment is cancelled

* add back "subUpdateCard" string

* fix redirects when editing a sub card, use proper names for products, check subs when gifting
2020-12-14 15:59:17 +01:00
Matteo Pagliazzi
7072fbdd06 fix(client): more resilient autocomplete, possible fix for #11516 2020-12-14 15:58:12 +01:00
dependabot-preview[bot]
73cd6aec59 build(deps): bump @babel/preset-env from 7.12.7 to 7.12.10 (#12875)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.12.7 to 7.12.10.
- [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.12.10/packages/babel-preset-env)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-14 15:23:51 +01:00
dependabot-preview[bot]
d05e535c7e build(deps): bump validator from 13.5.1 to 13.5.2 in /website/client (#12880)
Bumps [validator](https://github.com/chriso/validator.js) from 13.5.1 to 13.5.2.
- [Release notes](https://github.com/chriso/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chriso/validator.js/compare/13.5.1...13.5.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-12-14 15:19:30 +01:00
dependabot-preview[bot]
e8960f1b0b build(deps): bump uuid from 8.3.1 to 8.3.2 (#12871)
Bumps [uuid](https://github.com/uuidjs/uuid) from 8.3.1 to 8.3.2.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v8.3.1...v8.3.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-12-14 15:19:18 +01:00
dependabot-preview[bot]
943ea1d8f3 build(deps): bump @babel/register from 7.12.1 to 7.12.10 (#12874)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.12.1 to 7.12.10.
- [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.12.10/packages/babel-register)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-14 15:18:19 +01:00
dependabot-preview[bot]
61172f82a3 build(deps): bump jwks-rsa from 1.11.0 to 1.12.0 (#12872)
Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.11.0 to 1.12.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/commits/v1.12.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-12-14 15:17:43 +01:00
dependabot-preview[bot]
e7faebbf40 build(deps): bump got from 11.8.0 to 11.8.1 (#12870)
Bumps [got](https://github.com/sindresorhus/got) from 11.8.0 to 11.8.1.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.8.0...v11.8.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-12-14 15:17:26 +01:00
dependabot-preview[bot]
c800f36178 build(deps): bump @babel/core from 7.12.9 to 7.12.10 (#12869)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.12.9 to 7.12.10.
- [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.12.10/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-12-14 15:17:05 +01:00
dependabot-preview[bot]
f2fff946a4 build(deps): bump rate-limiter-flexible from 2.1.13 to 2.1.14 (#12865)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.13 to 2.1.14.
- [Release notes](https://github.com/animir/node-rate-limiter-flexible/releases)
- [Commits](https://github.com/animir/node-rate-limiter-flexible/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-12-14 15:16:44 +01:00
dependabot-preview[bot]
e6b0bdb05e build(deps-dev): bump sinon from 9.2.1 to 9.2.2 (#12866)
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.2.1 to 9.2.2.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/commits/v9.2.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-12-14 15:16:16 +01:00
dependabot-preview[bot]
709fcd5ae6 build(deps): bump validator from 13.5.1 to 13.5.2 (#12868)
Bumps [validator](https://github.com/chriso/validator.js) from 13.5.1 to 13.5.2.
- [Release notes](https://github.com/chriso/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chriso/validator.js/compare/13.5.1...13.5.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-12-14 15:16:08 +01:00
dependabot-preview[bot]
1b0251a492 build(deps): bump mongoose from 5.11.4 to 5.11.7 (#12873)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.11.4 to 5.11.7.
- [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.11.4...5.11.7)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-14 15:15:52 +01:00
dependabot-preview[bot]
c5cd20de22 build(deps): bump uuid from 8.3.1 to 8.3.2 in /website/client (#12877)
Bumps [uuid](https://github.com/uuidjs/uuid) from 8.3.1 to 8.3.2.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v8.3.1...v8.3.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-12-14 15:15:19 +01:00
Vipul Khandelwal
32d3da9310 Fixed toggle menu button in development mode (#12862) 2020-12-14 11:12:08 +10:00
Vipul Khandelwal
9ebf435c82 Fixed footer layout (#12840)
* Fixed footer layout

* Fixed footer layout using bootstrap responsive typography
2020-12-13 18:39:31 +01:00
Sophie Lau
f06fefe9c0 Corrected recipient email address in reported PM Slack notification - fixes #12256 (#12838)
* Corrected recipient email address in reported PM Slack notification

Corrected the recipient email address in the Slack notification sent to moderators when a user reports their own private message.

* Installed new dependencies

* Removed personal comments

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-12-13 18:15:19 +01:00
Sabe Jones
4bdaa58592 fix(events): short-circuit when no active event 2020-12-11 16:47:16 -06:00
Sabe Jones
bcae464955 fix(events): short-circuit when no active event 2020-12-11 16:36:19 -06:00
Sabe Jones
0d1643eb17 WIP(event): Test values for event range--NOT FOR PRODUCTION 2020-12-11 16:26:53 -06:00
Sabe Jones
ccae075a4d chore(sprites): compile 2020-12-11 16:22:12 -06:00
Sabe Jones
5d275aa2a5 Merge branch 'sabrecat/winter-2021' into develop 2020-12-11 16:22:01 -06:00
Sabe Jones
26940e4054 fix(vue): spritesheet 30 temporarily removed 2020-12-11 16:21:24 -06:00
Sabe Jones
119502f285 fix(event): address code comments, add banner gradient 2020-12-11 15:59:41 -06:00
Sabe Jones
5c8817c4ef Revert "chore(sprites): compile"
This reverts commit fe109f0e00.
2020-12-11 15:57:40 -06:00
Sabe Jones
7c081c4607 fix(test): expect save false 2020-12-11 14:14:07 -06:00
Sabe Jones
f2b53f651e fix(subscriptions): don't save user during message send 2020-12-11 14:06:23 -06:00
Sabe Jones
0e1011b875 Revert "fix(subscriptions): avoid parallelSave from recursive fn call"
This reverts commit ff93dd9159.
2020-12-11 11:08:31 -06:00
Sabe Jones
cb999d9277 Revert "fix(test): promo no longer handled in library, revert test"
This reverts commit f2281efe99.
2020-12-11 11:07:51 -06:00
dependabot-preview[bot]
dcdb3efdc2 build(deps): [security] bump ini from 1.3.5 to 1.3.7 in /website/client (#12856)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7. **This update includes a security fix.**
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-11 10:37:21 +01:00
Sabe Jones
f2281efe99 fix(test): promo no longer handled in library, revert test 2020-12-10 19:34:52 -06:00
Sabe Jones
ff93dd9159 fix(subscriptions): avoid parallelSave from recursive fn call 2020-12-10 19:22:54 -06:00
Sabe Jones
0568e4f2ae WIP(test): more placeholders for unwritten content 2020-12-10 17:08:00 -06:00
Sabe Jones
fe109f0e00 chore(sprites): compile 2020-12-10 16:53:44 -06:00
Sabe Jones
53f19c4da3 feat(event): Winter Wonderland 2021 and Gift-One-Get-One Promotion 2020-12-10 16:53:37 -06:00
dependabot-preview[bot]
fa0f60d3a6 build(deps): [security] bump ini from 1.3.5 to 1.3.7 (#12855)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7. **This update includes a security fix.**
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-10 18:33:54 +01:00
Sabe Jones
74ebcf919e Merge branch 'develop' into sabrecat/winter-2021 2020-12-08 15:17:34 -06:00
Melior
0701fa4286 Translated using Weblate (English (Pirate))
Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (124 of 124 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 91.3% (2012 of 2203 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

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

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.4% (2098 of 2197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Latvian)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Korean)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Croatian)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Catalan)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Thai)

Currently translated at 65.5% (120 of 183 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 65.5% (120 of 183 strings)

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

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 65.5% (120 of 183 strings)

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

Translated using Weblate (Lingala)

Currently translated at 65.5% (120 of 183 strings)

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

Translated using Weblate (Greek)

Currently translated at 65.5% (120 of 183 strings)

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

Translated using Weblate (Korean)

Currently translated at 78.1% (1716 of 2197 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Turkish)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (85 of 85 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.9% (2196 of 2197 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.9% (2196 of 2197 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (365 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/es_419/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2197 of 2197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.3% (2094 of 2197 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.2% (1939 of 2197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 91.3% (2006 of 2197 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 92.8% (52 of 56 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.3% (683 of 724 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Malay)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Hindi)

Currently translated at 97.8% (183 of 187 strings)

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

Translated using Weblate (Finnish)

Currently translated at 98.3% (184 of 187 strings)

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

Translated using Weblate (Greek)

Currently translated at 96.7% (181 of 187 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Croatian)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Hindi)

Currently translated at 73.9% (422 of 571 strings)

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

Translated using Weblate (Finnish)

Currently translated at 72.8% (416 of 571 strings)

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

Translated using Weblate (Korean)

Currently translated at 83.5% (71 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/ko/

Translated using Weblate (Finnish)

Currently translated at 83.5% (71 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/fi/

Translated using Weblate (Persian)

Currently translated at 83.5% (71 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/fa/

Translated using Weblate (Greek)

Currently translated at 83.5% (71 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/el/

Translated using Weblate (Tagalog)

Currently translated at 77.4% (1701 of 2197 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 77.8% (1711 of 2197 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 77.5% (1703 of 2197 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 77.5% (1703 of 2197 strings)

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

Translated using Weblate (Korean)

Currently translated at 78.0% (1715 of 2197 strings)

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

Translated using Weblate (Javanese)

Currently translated at 77.8% (1711 of 2197 strings)

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

Translated using Weblate (Croatian)

Currently translated at 77.8% (1711 of 2197 strings)

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

Translated using Weblate (Galician)

Currently translated at 77.8% (1711 of 2197 strings)

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

Translated using Weblate (Catalan)

Currently translated at 77.4% (1702 of 2197 strings)

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

Translated using Weblate (Arabic)

Currently translated at 77.4% (1701 of 2197 strings)

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

Translated using Weblate (Latvian)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/lv/

Translated using Weblate (Lithuanian)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/lt/

Translated using Weblate (Hindi)

Currently translated at 86.5% (316 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/hi/

Translated using Weblate (Galician)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/gl/

Translated using Weblate (Finnish)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/fi/

Translated using Weblate (Persian)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/fa/

Translated using Weblate (Greek)

Currently translated at 84.1% (307 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/el/

Translated using Weblate (Catalan)

Currently translated at 83.8% (306 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ca/

Translated using Weblate (Urdu (Pakistan))

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Thai)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Swahili)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Sundanese)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Sinhala)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Scots)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Marathi)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Mongolian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Malayalam)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Macedonian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Lingala)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Kurdish)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Javanese)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Croatian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Hindi)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Hawaiian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Galician)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Frisian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Filipino)

Currently translated at 96.6% (174 of 180 strings)

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

Translated using Weblate (Finnish)

Currently translated at 93.8% (169 of 180 strings)

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

Translated using Weblate (Estonian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Esperanto)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Catalan)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Bengali)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Afrikaans)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Acholi)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2197 of 2197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (Romanian)

Currently translated at 93.7% (2059 of 2197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.1% (2090 of 2197 strings)

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

Translated using Weblate (Hebrew)

Currently translated at 77.5% (1704 of 2197 strings)

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

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 (Hebrew)

Currently translated at 96.7% (181 of 187 strings)

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

Translated using Weblate (Turkish)

Currently translated at 94.4% (170 of 180 strings)

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

Translated using Weblate (Serbian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Slovak)

Currently translated at 91.1% (164 of 180 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 91.1% (164 of 180 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 91.1% (164 of 180 strings)

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

Translated using Weblate (Danish)

Currently translated at 91.1% (164 of 180 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2197 of 2197 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2197 of 2197 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.0% (2089 of 2197 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (124 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/vi/

Translated using Weblate (Tagalog)

Currently translated at 89.5% (111 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/tl/

Translated using Weblate (Malay)

Currently translated at 90.3% (112 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ms/

Translated using Weblate (Galician)

Currently translated at 89.5% (111 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/

Translated using Weblate (Greek)

Currently translated at 89.5% (111 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/el/

Translated using Weblate (Malay)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Croatian)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Hindi)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Arabic)

Currently translated at 60.7% (34 of 56 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Malay)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 96.3% (550 of 571 strings)

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

Translated using Weblate (Tamil)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Malay)

Currently translated at 72.1% (412 of 571 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Irish)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Esperanto)

Currently translated at 71.8% (410 of 571 strings)

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

Translated using Weblate (Croatian)

Currently translated at 88.8% (119 of 134 strings)

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

Translated using Weblate (Hindi)

Currently translated at 87.3% (117 of 134 strings)

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

Translated using Weblate (Persian)

Currently translated at 88.0% (118 of 134 strings)

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

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 (Arabic)

Currently translated at 88.0% (118 of 134 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Croatian)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Persian)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Greek)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 90.1% (55 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/vi/

Translated using Weblate (Tagalog)

Currently translated at 83.6% (51 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/tl/

Translated using Weblate (Icelandic)

Currently translated at 83.6% (51 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/is/

Translated using Weblate (Galician)

Currently translated at 83.6% (51 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/

Translated using Weblate (Persian)

Currently translated at 83.6% (51 of 61 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/fa/

Translated using Weblate (Slovenian)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Persian)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 96.2% (179 of 186 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 61.8% (115 of 186 strings)

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

Translated using Weblate (Croatian)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Urdu (Pakistan))

Currently translated at 96.0% (195 of 203 strings)

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

Translated using Weblate (Latvian)

Currently translated at 96.0% (195 of 203 strings)

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

Translated using Weblate (Javanese)

Currently translated at 27.7% (15 of 54 strings)

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

Translated using Weblate (Croatian)

Currently translated at 27.7% (15 of 54 strings)

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

Translated using Weblate (Hindi)

Currently translated at 27.7% (15 of 54 strings)

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

Translated using Weblate (Lojban)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/jbo/

Translated using Weblate (Icelandic)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/is/

Translated using Weblate (Hindi)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/hi/

Translated using Weblate (Greek)

Currently translated at 100.0% (15 of 15 strings)

Translation: Habitica/Death
Translate-URL: https://translate.habitica.com/projects/habitica/death/el/

Translated using Weblate (Slovenian)

Currently translated at 97.5% (120 of 123 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Finnish)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Greek)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 98.8% (178 of 180 strings)

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

Translated using Weblate (Latvian)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Korean)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Croatian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 63.4% (118 of 186 strings)

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

Translated using Weblate (Swedish)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 100.0% (23 of 23 strings)

Translation: Habitica/Loginincentives
Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/id/

Translated using Weblate (Swedish)

Currently translated at 91.8% (336 of 366 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/sv/

Translated using Weblate (Portuguese)

Currently translated at 87.9% (322 of 366 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt/

Translated using Weblate (Danish)

Currently translated at 87.7% (321 of 366 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/da/

Translated using Weblate (Danish)

Currently translated at 87.7% (321 of 366 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/da/

Translated using Weblate (Japanese)

Currently translated at 94.9% (2087 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (Indonesian)

Currently translated at 27.7% (15 of 54 strings)

Translation: Habitica/Defaulttasks
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/id/

Translated using Weblate (Swedish)

Currently translated at 100.0% (47 of 47 strings)

Translation: Habitica/Contrib
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/sv/

Translated using Weblate (Ukrainian)

Currently translated at 97.0% (99 of 102 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/uk/

Translated using Weblate (Hebrew)

Currently translated at 97.0% (99 of 102 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/he/

Translated using Weblate (Hebrew)

Currently translated at 91.1% (164 of 180 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/he/

Translated using Weblate (Korean)

Currently translated at 77.6% (1705 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.9% (2195 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.0% (2176 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (8 of 8 strings)

Translation: Habitica/Inventory
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/en@pirate/

Translated using Weblate (Japanese)

Currently translated at 94.9% (2087 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (203 of 203 strings)

Translation: Habitica/Generic
Translate-URL: https://translate.habitica.com/projects/habitica/generic/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 99.7% (722 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (365 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/en@pirate/

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.9% (2175 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.9% (2173 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.8% (2172 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.8% (2171 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.7% (2170 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/
2020-12-08 19:14:53 +01:00
Sabe Jones
25d9102674 Merge branch 'release' into develop 2020-12-08 11:13:25 -06:00
dependabot-preview[bot]
dab9a9b6cb build(deps): bump validator from 13.1.17 to 13.5.1 (#12842)
Bumps [validator](https://github.com/chriso/validator.js) from 13.1.17 to 13.5.1.
- [Release notes](https://github.com/chriso/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chriso/validator.js/compare/13.1.17...13.5.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-12-07 17:14:52 +01:00
dependabot-preview[bot]
4db0002d5d build(deps): bump validator from 13.1.17 to 13.5.1 in /website/client (#12846)
Bumps [validator](https://github.com/chriso/validator.js) from 13.1.17 to 13.5.1.
- [Release notes](https://github.com/chriso/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chriso/validator.js/compare/13.1.17...13.5.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-12-07 17:14:42 +01:00
dependabot-preview[bot]
4a1c532cd3 build(deps): bump mongoose from 5.10.18 to 5.11.4 (#12844)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.18 to 5.11.4.
- [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.10.18...5.11.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-07 17:14:04 +01:00
dependabot-preview[bot]
3c1d7fce5f build(deps): bump sass from 1.29.0 to 1.30.0 in /website/client (#12851)
Bumps [sass](https://github.com/sass/dart-sass) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.29.0...1.30.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-12-07 17:10:32 +01:00
dependabot-preview[bot]
e840661da8 build(deps): bump bootstrap-vue from 2.19.0 to 2.20.1 in /website/client (#12848)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.19.0 to 2.20.1.
- [Release notes](https://github.com/bootstrap-vue/bootstrap-vue/releases)
- [Changelog](https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.19.0...v2.20.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-12-07 17:10:06 +01:00
dependabot-preview[bot]
ec912a6dda build(deps): bump core-js from 3.8.0 to 3.8.1 in /website/client (#12850)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.8.0...v3.8.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-12-07 17:09:44 +01:00
Matteo Pagliazzi
5d6583936d fix(skill casting): pass empty req on client, fixes #12839 2020-12-06 00:01:34 +01:00
Vipul Khandelwal
bc181819f4 Fixed Skill Layout (#12776)
* Fixed Skill Layout

* Fixed skill layout reponsiveness

* Fixed collapsing of drawer container

* Fixed skill card disabled state, extra white border and hover sstate

* Fixed task / member selection style

* Fixed few changes

* Fixed extra padding and box shadow

* Fixed box shadow and added popover component

* Fixed disabled state issue

* Fixed styles and skill card issues

* Fixed style issues

* Fixed style issue

* Fixed lint error

* Fixed space between drawer class

* Fixed border issue

* Fixed round border issue

* Fixed Mage issue

* auto eslint fixes

* use translated string and computed property, reorganize css

* perf: reduce calculated classes, throttle mouse moved event

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-12-04 22:05:56 +01:00
Melior
2018962eb5 Translated using Weblate (Spanish (Latin America))
Currently translated at 98.4% (2164 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 97.8% (2149 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Japanese)

Currently translated at 94.7% (2081 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en@pirate/

Translated using Weblate (Japanese)

Currently translated at 100.0% (85 of 85 strings)

Translation: Habitica/Quests
Translate-URL: https://translate.habitica.com/projects/habitica/quests/ja/

Translated using Weblate (Spanish (Latin America))

Currently translated at 97.4% (2141 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Japanese)

Currently translated at 94.5% (2078 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

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 (Spanish (Latin America))

Currently translated at 96.4% (2120 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (724 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.0% (681 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/

Translated using Weblate (French)

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/

Translated using Weblate (French)

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/

Translated using Weblate (English (Pirate))

Currently translated at 90.9% (1999 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en@pirate/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (123 of 123 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/

Translated using Weblate (Hindi)

Currently translated at 97.5% (198 of 203 strings)

Translation: Habitica/Generic
Translate-URL: https://translate.habitica.com/projects/habitica/generic/hi/

Translated using Weblate (Japanese)

Currently translated at 94.5% (2077 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (Spanish (Latin America))

Currently translated at 93.3% (676 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 96.0% (2110 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (Korean)

Currently translated at 16.1% (53 of 328 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/ko/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (134 of 134 strings)

Translation: Habitica/Tasks
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 93.4% (171 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 99.5% (202 of 203 strings)

Translation: Habitica/Generic
Translate-URL: https://translate.habitica.com/projects/habitica/generic/en@pirate/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (123 of 123 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/

Translated using Weblate (Korean)

Currently translated at 16.1% (53 of 328 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/ko/

Translated using Weblate (Japanese)

Currently translated at 94.3% (2073 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (Hindi)

Currently translated at 100.0% (102 of 102 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/hi/

Translated using Weblate (Hindi)

Currently translated at 100.0% (8 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/hi/

Translated using Weblate (Hindi)

Currently translated at 100.0% (123 of 123 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/hi/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/

Translated using Weblate (Korean)

Currently translated at 94.2% (344 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ko/

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.1% (2091 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es_419/

Translated using Weblate (English)

Currently translated at 20.9% (38 of 181 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/en@lolcat/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (111 of 111 strings)

Translation: Habitica/Pets
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/

Translated using Weblate (Japanese)

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/

Translated using Weblate (English (Pirate))

Currently translated at 79.7% (146 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en@pirate/

Translated using Weblate (Japanese)

Currently translated at 94.1% (2069 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/

Translated using Weblate (English (Pirate))

Currently translated at 90.6% (1991 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 98.8% (716 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/en@pirate/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/it/

Translated using Weblate (German)

Currently translated at 100.0% (183 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/de/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/

Translated using Weblate (German)

Currently translated at 100.0% (2197 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (181 of 181 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/en@pirate/

Translated using Weblate (Korean)

Currently translated at 65.0% (119 of 183 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ko/

Translated using Weblate (Korean)

Currently translated at 74.0% (77 of 104 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ko/

Translated using Weblate (Korean)

Currently translated at 77.5% (1703 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/

Translated using Weblate (Korean)

Currently translated at 93.9% (343 of 365 strings)

Translation: Habitica/Content
Translate-URL: https://translate.habitica.com/projects/habitica/content/ko/

Translated using Weblate (English (Pirate))

Currently translated at 99.4% (362 of 364 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 90.6% (1992 of 2197 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 78.5% (44 of 56 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/en@pirate/

Translated using Weblate (English (Pirate))

Currently translated at 98.6% (714 of 724 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/en@pirate/
2020-12-04 18:15:59 +01:00
Sabe Jones
4aa51db5ec WIP(gala): string might be nicer 2020-12-03 15:36:02 -06:00
Sabe Jones
1ed2ebb04d WIP(gala): add g1g1 flag, some refactoring 2020-12-03 15:29:11 -06:00
1010 changed files with 51350 additions and 41264 deletions

View File

@@ -71,6 +71,7 @@
"SLACK_URL": "https://hooks.slack.com/services/some-url",
"STRIPE_API_KEY": "aaaabbbbccccddddeeeeffff00001111",
"STRIPE_PUB_KEY": "22223333444455556666777788889999",
"STRIPE_WEBHOOKS_ENDPOINT_SECRET": "111111",
"TRANSIFEX_SLACK_CHANNEL": "transifex",
"WEB_CONCURRENCY": 1,
"SKIP_SSL_CHECK_KEY": "key",

View File

@@ -0,0 +1,62 @@
/*
* Fix dates in the database that were stored as $type string instead of Date
*/
/* eslint-disable no-console */
const MIGRATION_NAME = '20201111_api_date';
import * as Tasks from '../../../website/server/models/task';
const progressCount = 1000;
let count = 0;
async function updateUser (todo) {
count++;
if (count % progressCount === 0) console.warn(`${count} ${todo._id}`);
const newDate = new Date(todo.date);
if (isValidDate(newDate)) return;
return await Tasks.Task.update({_id: todo._id, type: 'todo'}, {$unset: {date: ''}}).exec();
}
module.exports = async function processUsers () {
let query = {
type: 'todo',
date: {$exists: true},
updatedAt: {$gt: new Date('2020-11-23')},
};
const fields = {
_id: 1,
type: 1,
date: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await Tasks.Task // eslint-disable-line no-await-in-loop
.find(query)
.select(fields)
.limit(250)
.sort({_id: 1})
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate tasks found and modified.');
console.warn(`\n${count} tasks processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
function isValidDate(d) {
return !isNaN(d.getTime());
}

View File

@@ -0,0 +1,126 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20201229_nye';
import { model as User } from '../../../website/server/models/user';
import { v4 as uuid } from 'uuid';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = { migration: MIGRATION_NAME };
let push;
if (typeof user.items.gear.owned.head_special_nye2019 !== 'undefined') {
set['items.gear.owned.head_special_nye2020'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2020',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye2018 !== 'undefined') {
set['items.gear.owned.head_special_nye2019'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2019',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
set['items.gear.owned.head_special_nye2018'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2018',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
set['items.gear.owned.head_special_nye2017'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2017',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
set['items.gear.owned.head_special_nye2016'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2016',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
set['items.gear.owned.head_special_nye2015'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2015',
_id: uuid(),
},
];
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
set['items.gear.owned.head_special_nye2014'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye2014',
_id: uuid(),
},
];
} else {
set['items.gear.owned.head_special_nye'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_nye',
_id: uuid(),
},
];
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$set: set, $push: {pinnedItems: {$each: push}}}).exec();
}
export default async function processUsers () {
let query = {
'auth.timestamps.loggedin': {$gt: new Date('2020-12-01')},
migration: {$ne: MIGRATION_NAME},
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,94 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20210129_habit_birthday';
import { v4 as uuid } from 'uuid';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const inc = {
'items.food.Cake_Skeleton': 1,
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Zombie': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Red': 1,
'achievements.habitBirthdays': 1,
};
const set = {};
let push;
set.migration = MIGRATION_NAME;
if (typeof user.items.gear.owned.armor_special_birthday2020 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2021'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2021', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2019 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2020'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2020', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2018 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2019'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2019', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2017 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2018'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2018', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2016 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2017'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2017', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2015 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2016'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2016', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday !== 'undefined') {
set['items.gear.owned.armor_special_birthday2015'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2015', _id: uuid()}};
} else {
set['items.gear.owned.armor_special_birthday'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday', _id: uuid()}};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: push}).exec();
}
export default async function processUsers () {
let query = {
// migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2021-01-01')},
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,108 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20210216_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['Dragon-Base']
&& pets['Dragon-CottonCandyBlue']
&& pets['Dragon-CottonCandyPink']
&& pets['Dragon-Desert']
&& pets['Dragon-Golden']
&& pets['Dragon-Red']
&& pets['Dragon-Shade']
&& pets['Dragon-Skeleton']
&& pets['Dragon-White']
&& pets['Dragon-Zombie']
&& pets['FlyingPig-Base']
&& pets['FlyingPig-CottonCandyBlue']
&& pets['FlyingPig-CottonCandyPink']
&& pets['FlyingPig-Desert']
&& pets['FlyingPig-Golden']
&& pets['FlyingPig-Red']
&& pets['FlyingPig-Shade']
&& pets['FlyingPig-Skeleton']
&& pets['FlyingPig-White']
&& pets['FlyingPig-Zombie']
&& pets['Gryphon-Base']
&& pets['Gryphon-CottonCandyBlue']
&& pets['Gryphon-CottonCandyPink']
&& pets['Gryphon-Desert']
&& pets['Gryphon-Golden']
&& pets['Gryphon-Red']
&& pets['Gryphon-Shade']
&& pets['Gryphon-Skeleton']
&& pets['Gryphon-White']
&& pets['Gryphon-Zombie']
&& pets['SeaSerpent-Base']
&& pets['SeaSerpent-CottonCandyBlue']
&& pets['SeaSerpent-CottonCandyPink']
&& pets['SeaSerpent-Desert']
&& pets['SeaSerpent-Golden']
&& pets['SeaSerpent-Red']
&& pets['SeaSerpent-Shade']
&& pets['SeaSerpent-Skeleton']
&& pets['SeaSerpent-White']
&& pets['SeaSerpent-Zombie']
&& pets['Unicorn-Base']
&& pets['Unicorn-CottonCandyBlue']
&& pets['Unicorn-CottonCandyPink']
&& pets['Unicorn-Desert']
&& pets['Unicorn-Golden']
&& pets['Unicorn-Red']
&& pets['Unicorn-Shade']
&& pets['Unicorn-Skeleton']
&& pets['Unicorn-White']
&& pets['Unicorn-Zombie']) {
set['achievements.legendaryBestiary'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-02-01') },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1]._id,
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

526
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "habitica",
"version": "4.173.0",
"version": "4.183.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -18,32 +18,41 @@
"integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw=="
},
"@babel/core": {
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz",
"integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
"@babel/generator": "^7.12.10",
"@babel/helper-module-transforms": "^7.12.1",
"@babel/helpers": "^7.12.5",
"@babel/parser": "^7.12.7",
"@babel/parser": "^7.12.10",
"@babel/template": "^7.12.7",
"@babel/traverse": "^7.12.9",
"@babel/types": "^7.12.7",
"@babel/traverse": "^7.12.10",
"@babel/types": "^7.12.10",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.1",
"json5": "^2.1.2",
"lodash": "^4.17.19",
"resolve": "^1.3.2",
"semver": "^5.4.1",
"source-map": "^0.5.0"
},
"dependencies": {
"@babel/generator": {
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
"integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"requires": {
"@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
},
"@babel/parser": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
"integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg=="
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
"integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA=="
},
"@babel/template": {
"version": "7.12.7",
@@ -56,25 +65,25 @@
}
},
"@babel/traverse": {
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
"integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
"integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
"@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
"@babel/parser": "^7.12.7",
"@babel/types": "^7.12.7",
"@babel/parser": "^7.12.10",
"@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
"integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
@@ -106,11 +115,28 @@
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz",
"integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz",
"integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==",
"requires": {
"@babel/types": "^7.10.4"
"@babel/types": "^7.12.10"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/types": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
@@ -172,12 +198,17 @@
"@babel/types": "^7.12.1"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
@@ -301,12 +332,17 @@
"@babel/types": "^7.12.1"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
@@ -364,12 +400,17 @@
"@babel/types": "^7.12.1"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
@@ -402,9 +443,9 @@
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
},
"@babel/helper-validator-option": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz",
"integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A=="
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz",
"integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw=="
},
"@babel/helper-wrap-function": {
"version": "7.12.3",
@@ -428,9 +469,9 @@
},
"dependencies": {
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
"integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
@@ -709,9 +750,9 @@
}
},
"@babel/plugin-transform-block-scoping": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz",
"integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.11.tgz",
"integrity": "sha512-atR1Rxc3hM+VPg/NvNvfYw0npQEAcHuJ+MGZnFn6h3bo+1U3BWXMdFMlvVRApBTWKQMX7SOwRJZA5FBF/JQbvA==",
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -939,9 +980,9 @@
}
},
"@babel/plugin-transform-typeof-symbol": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz",
"integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz",
"integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==",
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -964,15 +1005,15 @@
}
},
"@babel/preset-env": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz",
"integrity": "sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz",
"integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==",
"requires": {
"@babel/compat-data": "^7.12.7",
"@babel/helper-compilation-targets": "^7.12.5",
"@babel/helper-module-imports": "^7.12.5",
"@babel/helper-plugin-utils": "^7.10.4",
"@babel/helper-validator-option": "^7.12.1",
"@babel/helper-validator-option": "^7.12.11",
"@babel/plugin-proposal-async-generator-functions": "^7.12.1",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-dynamic-import": "^7.12.1",
@@ -1001,7 +1042,7 @@
"@babel/plugin-transform-arrow-functions": "^7.12.1",
"@babel/plugin-transform-async-to-generator": "^7.12.1",
"@babel/plugin-transform-block-scoped-functions": "^7.12.1",
"@babel/plugin-transform-block-scoping": "^7.12.1",
"@babel/plugin-transform-block-scoping": "^7.12.11",
"@babel/plugin-transform-classes": "^7.12.1",
"@babel/plugin-transform-computed-properties": "^7.12.1",
"@babel/plugin-transform-destructuring": "^7.12.1",
@@ -1027,21 +1068,26 @@
"@babel/plugin-transform-spread": "^7.12.1",
"@babel/plugin-transform-sticky-regex": "^7.12.7",
"@babel/plugin-transform-template-literals": "^7.12.1",
"@babel/plugin-transform-typeof-symbol": "^7.12.1",
"@babel/plugin-transform-typeof-symbol": "^7.12.10",
"@babel/plugin-transform-unicode-escapes": "^7.12.1",
"@babel/plugin-transform-unicode-regex": "^7.12.1",
"@babel/preset-modules": "^0.1.3",
"@babel/types": "^7.12.7",
"core-js-compat": "^3.7.0",
"@babel/types": "^7.12.11",
"core-js-compat": "^3.8.0",
"semver": "^5.5.0"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
@@ -1061,9 +1107,9 @@
}
},
"@babel/register": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.1.tgz",
"integrity": "sha512-XWcmseMIncOjoydKZnWvWi0/5CUCD+ZYKhRwgYlWOrA8fGZ/FjuLRpqtIhLOVD/fvR1b9DQHtZPn68VvhpYf+Q==",
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.10.tgz",
"integrity": "sha512-EvX/BvMMJRAA3jZgILWgbsrHwBQvllC5T8B29McyME8DvkdOxk4ujESfrMvME8IHSDvWXrmMXxPvA/lx2gqPLQ==",
"requires": {
"find-cache-dir": "^2.0.0",
"lodash": "^4.17.19",
@@ -1319,9 +1365,9 @@
"integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ=="
},
"@sinonjs/commons": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
"integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz",
"integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
@@ -1336,20 +1382,10 @@
"@sinonjs/commons": "^1.7.0"
}
},
"@sinonjs/formatio": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz",
"integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1",
"@sinonjs/samsam": "^5.0.2"
}
},
"@sinonjs/samsam": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz",
"integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz",
"integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.6.0",
@@ -1369,23 +1405,13 @@
"integrity": "sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg=="
},
"@slack/webhook": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@slack/webhook/-/webhook-5.0.3.tgz",
"integrity": "sha512-51vnejJ2zABNumPVukOLyerpHQT39/Lt0TYFtOEz/N2X77bPofOgfPj2atB3etaM07mxWHLT9IRJ4Zuqx38DkQ==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@slack/webhook/-/webhook-5.0.4.tgz",
"integrity": "sha512-IC1dpVSc2F/pmwCxOb0QzH2xnGKmyT7MofPGhNkeaoiMrLMU+Oc7xV/AxGnz40mURtCtaDchZSM3tDo9c9x6BA==",
"requires": {
"@slack/types": "^1.2.1",
"@types/node": ">=8.9.0",
"axios": "^0.19.0"
},
"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"
}
}
"axios": "^0.21.1"
}
},
"@szmarczak/http-timer": {
@@ -1414,7 +1440,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
"integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
@@ -1436,17 +1461,17 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"@types/connect": {
"version": "3.4.33",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
"version": "3.4.34",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
"integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
"requires": {
"@types/node": "*"
}
},
"@types/express": {
"version": "4.17.8",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
"integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==",
"version": "4.17.9",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.9.tgz",
"integrity": "sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw==",
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "*",
@@ -1464,9 +1489,9 @@
}
},
"@types/express-serve-static-core": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz",
"integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==",
"version": "4.17.17",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.17.tgz",
"integrity": "sha512-YYlVaCni5dnHc+bLZfY908IG1+x5xuibKZMGv8srKkvtul3wUuanYvpIj9GXXoWkQbaAdR+kgX46IETKUALWNQ==",
"requires": {
"@types/node": "*",
"@types/qs": "*",
@@ -1522,7 +1547,6 @@
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.27.tgz",
"integrity": "sha512-1jxKDgdfJEOO9zp+lv43p8jOqRs02xPrdUTzAZIVK9tVEySfCEmktL2jEu9A3wOBEOs18yKzpVIKUh8b8ALk3w==",
"dev": true,
"requires": {
"@types/bson": "*",
"@types/node": "*"
@@ -1558,9 +1582,9 @@
}
},
"@types/serve-static": {
"version": "1.13.6",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.6.tgz",
"integrity": "sha512-nuRJmv7jW7VmCVTn+IgYDkkbbDGyIINOeu/G0d74X3lm6E5KfMeQPJhxIt1ayQeQB3cSxvYs1RA/wipYoFB4EA==",
"version": "1.13.8",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
"integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==",
"requires": {
"@types/mime": "*",
"@types/node": "*"
@@ -1729,9 +1753,9 @@
}
},
"apidoc": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.25.0.tgz",
"integrity": "sha512-5g9fp8OffXZOdBTzm4BBvV5Vw54s+NmKnGZIUKuH+gRTqqJuRJpcGN6sz6WnjJ+NcvXhB7rIRp6FhtJahazx2Q==",
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.26.0.tgz",
"integrity": "sha512-IEw/Z7HMMbjeVjK2sZvZSwAln8AqalLzf3qLDtkcedXVhdxGm6W7UgIW6fshegqNTMLzm8CFEMi4Lxbeu0xKTw==",
"requires": {
"apidoc-core": "^0.12.0",
"commander": "^2.20.0",
@@ -1751,15 +1775,10 @@
"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==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz",
"integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==",
"requires": {
"argparse": "^1.0.7",
"entities": "~2.0.0",
@@ -1783,15 +1802,13 @@
"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": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
@@ -1813,23 +1830,13 @@
}
},
"apple-auth": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/apple-auth/-/apple-auth-1.0.6.tgz",
"integrity": "sha512-dICsYIHBTX+7/1xdJZ4y4U08zOxEnL67GQ77l/HSKqEx9uC1wsY5dNjgbZf2F/1QnzAxDbAAHo0DgUCrA1k7zQ==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/apple-auth/-/apple-auth-1.0.7.tgz",
"integrity": "sha512-vfJqy4KtT5KHflxBSemc0mkWuy2GU2wHWaZ6xVWUjPmiXkJcLj5jB3IeCbDLF4wN+ZStjOQXZWfGwccBjclVlA==",
"requires": {
"axios": "^0.19.0",
"axios": "^0.21.1",
"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": {
@@ -2133,17 +2140,17 @@
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
},
"axios": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==",
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
},
"dependencies": {
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
}
}
},
@@ -3003,15 +3010,15 @@
"dev": true
},
"browserslist": {
"version": "4.14.7",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz",
"integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==",
"version": "4.16.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz",
"integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==",
"requires": {
"caniuse-lite": "^1.0.30001157",
"caniuse-lite": "^1.0.30001165",
"colorette": "^1.2.1",
"electron-to-chromium": "^1.3.591",
"electron-to-chromium": "^1.3.621",
"escalade": "^3.1.1",
"node-releases": "^1.1.66"
"node-releases": "^1.1.67"
}
},
"bson": {
@@ -3033,7 +3040,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"optional": true,
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
@@ -3042,8 +3048,7 @@
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
"optional": true
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-crc32": {
"version": "0.2.13",
@@ -3063,8 +3068,7 @@
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
"optional": true
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"buffer-from": {
"version": "1.1.1",
@@ -3098,9 +3102,9 @@
}
},
"cacheable-lookup": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz",
"integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w=="
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="
},
"cacheable-request": {
"version": "6.1.0",
@@ -3160,9 +3164,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001159",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001159.tgz",
"integrity": "sha512-w9Ph56jOsS8RL20K9cLND3u/+5WASWdhC/PPrf+V3/HsM3uHOavWOR1Xzakbv4Puo/srmPHudkmCRWM7Aq+/UA=="
"version": "1.0.30001170",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz",
"integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA=="
},
"caseless": {
"version": "0.12.0",
@@ -3854,11 +3858,11 @@
"dev": true
},
"core-js-compat": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.7.0.tgz",
"integrity": "sha512-V8yBI3+ZLDVomoWICO6kq/CD28Y4r1M7CWeO4AGpMdMfseu8bkSubBmUPySMGKRTS+su4XQ07zUkAsiu9FCWTg==",
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz",
"integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==",
"requires": {
"browserslist": "^4.14.6",
"browserslist": "^4.15.0",
"semver": "7.0.0"
},
"dependencies": {
@@ -4001,9 +4005,9 @@
}
},
"csv-stringify": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.5.3.tgz",
"integrity": "sha512-JKG8vIHpWPzdilp2SAmvjmAiIhD+XGKGdhZBGi8QIECgJAsFr7k5CmJIW2QkSxBBsctvmojM25s+UINzQ5NLTg=="
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.1.tgz",
"integrity": "sha512-JlQlNZMiuRGSFbLXFNGoBtsORXlkqf4Dfq8Ee0Jo4RVJj3YAUzevagUx24mDrQJLDF7aYz6Ne8kqA8WWBaYt2A=="
},
"currently-unhandled": {
"version": "0.4.1",
@@ -4611,9 +4615,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"electron-to-chromium": {
"version": "1.3.603",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.603.tgz",
"integrity": "sha512-J8OHxOeJkoSLgBXfV9BHgKccgfLMHh+CoeRo6wJsi6m0k3otaxS/5vrHpMNSEYY4MISwewqanPOuhAtuE8riQQ=="
"version": "1.3.629",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz",
"integrity": "sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ=="
},
"emitter-listener": {
"version": "1.1.2",
@@ -5868,29 +5872,6 @@
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -6658,9 +6639,9 @@
}
},
"got": {
"version": "11.8.0",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz",
"integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==",
"version": "11.8.1",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.1.tgz",
"integrity": "sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q==",
"requires": {
"@sindresorhus/is": "^4.0.0",
"@szmarczak/http-timer": "^4.0.5",
@@ -7191,9 +7172,9 @@
"dev": true
},
"helmet": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.2.0.tgz",
"integrity": "sha512-aoiSxXMd0ks1ojYpSCFoCRzgv4rY/uB9jKStaw8PkXwsdLYa/Gq+Nc5l0soH0cwBIsLAlujPnx4HLQs+LaXCrQ=="
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.4.1.tgz",
"integrity": "sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw=="
},
"hex2dec": {
"version": "1.1.2",
@@ -7511,9 +7492,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
"integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="
},
"inquirer": {
"version": "7.3.2",
@@ -8185,12 +8166,19 @@
}
},
"jsonfile": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^1.0.0"
"universalify": "^2.0.0"
},
"dependencies": {
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
}
}
},
"jsonwebtoken": {
@@ -8269,12 +8257,12 @@
}
},
"jwks-rsa": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.11.0.tgz",
"integrity": "sha512-G7ZgXZ3dlGbOUBQwgF+U/SVzOlI9KxJ9Uzp61bue2S5TV0h7c+kJRCl3bEPkC5PVmeu7/h82B3uQALVJMjzt/Q==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.12.2.tgz",
"integrity": "sha512-6gPo/mQUxXJt75oPtjhM3Jm3FSXnmwg73QDA8dpgP7YmIKlIY+2StngFxt4w4Y1podtSbtV3jttNOdctuxAX1Q==",
"requires": {
"@types/express-jwt": "0.0.42",
"axios": "^0.19.2",
"axios": "^0.21.1",
"debug": "^4.1.0",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
@@ -8283,16 +8271,6 @@
"lru-memoizer": "^2.1.2",
"ms": "^2.1.2",
"proxy-from-env": "^1.1.0"
},
"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": {
@@ -8310,9 +8288,9 @@
"integrity": "sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg=="
},
"kareem": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
"integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
},
"kerberos": {
"version": "1.1.4",
@@ -8637,9 +8615,9 @@
}
},
"lru-memoizer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.2.tgz",
"integrity": "sha512-N5L5xlnVcbIinNn/TJ17vHBZwBMt9t7aJDz2n97moWubjNl6VO9Ao2XuAGBBddkYdjrwR9HfzXbT6NfMZXAZ/A==",
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz",
"integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==",
"requires": {
"lodash.clonedeep": "^4.5.0",
"lru-cache": "~4.0.0"
@@ -9330,16 +9308,17 @@
}
},
"mongoose": {
"version": "5.10.18",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.18.tgz",
"integrity": "sha512-vaLUzBpUxqacoCqP/xXWMg/uVwCDrlc8LvYjDXCf8hdApvX/CXa0HLa7v2ieFaVd5Fgv3W2QXODLoC4Z/abbNw==",
"version": "5.11.13",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.13.tgz",
"integrity": "sha512-rXbaxSJfLnKKO2RTm8MKt65glrtfKDc4ATEb6vEbbzsVGCiLut753K5axdpyvE7KeTH7GOh4LzmuQLOvaaWOmA==",
"requires": {
"@types/mongodb": "^3.5.27",
"bson": "^1.1.4",
"kareem": "2.3.1",
"kareem": "2.3.2",
"mongodb": "3.6.3",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.7.0",
"mquery": "3.2.2",
"mpath": "0.8.3",
"mquery": "3.2.3",
"ms": "2.1.2",
"regexp-clone": "1.0.0",
"safe-buffer": "5.2.1",
@@ -9515,14 +9494,14 @@
}
},
"mpath": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz",
"integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg=="
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA=="
},
"mquery": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
"integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz",
"integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==",
"requires": {
"bluebird": "3.5.1",
"debug": "3.1.0",
@@ -9596,9 +9575,9 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
},
"nconf": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/nconf/-/nconf-0.11.0.tgz",
"integrity": "sha512-c4W7QqYF6p5BC7J/eVTOvtUlQgvS5CgbJ11xgjhSr8yyius7km7xgdIYHkFLR4TWY1HjsFkia/3l5OprGqCHvA==",
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/nconf/-/nconf-0.11.1.tgz",
"integrity": "sha512-2XY+7x3GwkkTnmkEVxsKykg0GUqCAtBZUA87FwbcUSaYBfaGCeVSf+82zap16j93B21J2AhpxrsF57jio36t0w==",
"requires": {
"async": "^1.4.0",
"ini": "^1.3.0",
@@ -9676,9 +9655,9 @@
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg=="
},
"yargs": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz",
"integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==",
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
@@ -11131,9 +11110,9 @@
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"rate-limiter-flexible": {
"version": "2.1.13",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.1.13.tgz",
"integrity": "sha512-EDzvV/ee/rCBKNL5Jw0Rr0rjneT/L4zLGgVS9xB6ShfVMkV5iviWKr+2tjzgBg5kd9by5F08C9DfXfH6v/kz3w=="
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.2.1.tgz",
"integrity": "sha512-rxCP6kDDdn0cZmVqVlF06yLU+mG3TuwaHV/fUIw3OQyYhza7pzVBtdMhUmfXbBzMS+O464XP+x33pfTDGRGYVA=="
},
"raw-body": {
"version": "2.4.0",
@@ -11667,9 +11646,9 @@
"integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q=="
},
"run-rs": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/run-rs/-/run-rs-0.7.3.tgz",
"integrity": "sha512-/JmHX4rhHNeLn+F/RqhPwYUmcnbX2Qjm8g77flhKbL6Ak9wpyq+d/a87qb1nBR72r15LT0IRf87sbLWZ/x39QA==",
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/run-rs/-/run-rs-0.7.4.tgz",
"integrity": "sha512-6VP6zOPvl6uiC+Qe+yXY0G5BbLcelO6lhkMlAuM+syOSUIsiI2mQB2NBhqv1g1I0k8bPQ2KgIa4qe6nTuXYU+g==",
"dev": true,
"requires": {
"chalk": "2.4.1",
@@ -11999,15 +11978,14 @@
}
},
"sinon": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.1.tgz",
"integrity": "sha512-naPfsamB5KEE1aiioaoqJ6MEhdUs/2vtI5w1hPAXX/UwvoPjXcwh1m5HiKx0HGgKR8lQSoFIgY5jM6KK8VrS9w==",
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz",
"integrity": "sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.8.1",
"@sinonjs/fake-timers": "^6.0.1",
"@sinonjs/formatio": "^5.0.1",
"@sinonjs/samsam": "^5.2.0",
"@sinonjs/samsam": "^5.3.1",
"diff": "^4.0.2",
"nise": "^4.0.4",
"supports-color": "^7.1.0"
@@ -12692,17 +12670,18 @@
}
},
"stripe": {
"version": "7.15.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-7.15.0.tgz",
"integrity": "sha512-TmouNGv1rIU7cgw7iFKjdQueJSwYKdPRPBuO7eNjrRliZUnsf2bpJqYe+n6ByarUJr38KmhLheVUxDyRawByPQ==",
"version": "8.132.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.132.0.tgz",
"integrity": "sha512-VFKQJWgPt2X0r/jh4wS6Kgx6/VH1IHw1466wIwahgWzgSANme5iNaJ+1AW45hvRUZJ+T15f2hTfQkQGyP73ZCg==",
"requires": {
"@types/node": ">=8.1.0",
"qs": "^6.6.0"
},
"dependencies": {
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ=="
}
}
},
@@ -12894,7 +12873,6 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -12909,7 +12887,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -13086,8 +13063,7 @@
"to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
"optional": true
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
},
"to-fast-properties": {
"version": "2.0.0",
@@ -13709,9 +13685,9 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"v8-compile-cache": {
"version": "2.1.1",
@@ -13736,9 +13712,9 @@
}
},
"validator": {
"version": "13.1.17",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.1.17.tgz",
"integrity": "sha512-zL5QBoemJ3jYFb2/j38y7ljhwYGXVLUp8H6W1nVxadnAOvUOytec+L7BHh1oBQ82/TzWXHd+GSaxUWp4lROkLg=="
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz",
"integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ=="
},
"value-or-function": {
"version": "3.0.0",

View File

@@ -1,26 +1,26 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.173.0",
"version": "4.183.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.12.9",
"@babel/preset-env": "^7.12.7",
"@babel/register": "^7.12.1",
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/register": "^7.12.10",
"@google-cloud/trace-agent": "^5.1.1",
"@slack/webhook": "^5.0.3",
"@parse/node-apn": "^4.0.0",
"@slack/webhook": "^5.0.4",
"accepts": "^1.3.5",
"amazon-payments": "^0.2.8",
"amplitude": "^5.1.4",
"apidoc": "^0.25.0",
"apple-auth": "^1.0.6",
"apidoc": "^0.26.0",
"apple-auth": "^1.0.7",
"bcrypt": "^5.0.0",
"body-parser": "^1.18.3",
"compression": "^1.7.4",
"cookie-session": "^1.4.0",
"coupon-code": "^0.4.5",
"csv-stringify": "^5.5.3",
"csv-stringify": "^5.6.1",
"cwait": "^1.1.1",
"domain-middleware": "~0.1.0",
"eslint": "^6.8.0",
@@ -30,27 +30,27 @@
"express-basic-auth": "^1.1.5",
"express-validator": "^5.2.0",
"glob": "^7.1.6",
"got": "^11.8.0",
"got": "^11.8.1",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-nodemon": "^2.5.0",
"gulp.spritesmith": "^6.9.0",
"habitica-markdown": "^3.0.0",
"helmet": "^4.2.0",
"helmet": "^4.4.1",
"image-size": "^0.9.3",
"in-app-purchase": "^1.11.3",
"js2xmlparser": "^4.0.1",
"jsonwebtoken": "^8.5.1",
"jwks-rsa": "^1.11.0",
"jwks-rsa": "^1.12.2",
"lodash": "^4.17.20",
"merge-stream": "^2.0.0",
"method-override": "^3.0.0",
"moment": "^2.29.1",
"moment-recur": "^1.0.7",
"mongoose": "^5.10.18",
"mongoose": "^5.11.13",
"morgan": "^1.10.0",
"nconf": "^0.11.0",
"nconf": "^0.11.1",
"node-gcm": "^1.0.3",
"on-headers": "^1.0.2",
"passport": "^0.4.1",
@@ -60,18 +60,18 @@
"paypal-rest-sdk": "^1.8.1",
"pp-ipn": "^1.1.0",
"ps-tree": "^1.0.0",
"rate-limiter-flexible": "^2.1.13",
"rate-limiter-flexible": "^2.2.1",
"redis": "^3.0.2",
"regenerator-runtime": "^0.13.7",
"remove-markdown": "^0.3.0",
"rimraf": "^3.0.2",
"short-uuid": "^4.1.0",
"stripe": "^7.15.0",
"stripe": "^8.132.0",
"superagent": "^6.1.0",
"universal-analytics": "^0.4.23",
"useragent": "^2.1.9",
"uuid": "^8.3.1",
"validator": "^13.1.17",
"uuid": "^8.3.2",
"validator": "^13.5.2",
"vinyl-buffer": "^1.0.1",
"winston": "^3.3.3",
"winston-loggly-bulk": "^3.1.1",
@@ -109,7 +109,7 @@
"apidoc": "gulp apidoc"
},
"devDependencies": {
"axios": "^0.21.0",
"axios": "^0.21.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chai-moment": "^0.1.0",
@@ -120,8 +120,8 @@
"mocha": "^5.1.1",
"monk": "^7.3.2",
"require-again": "^2.0.0",
"run-rs": "^0.7.3",
"sinon": "^9.2.1",
"run-rs": "^0.7.4",
"sinon": "^9.2.4",
"sinon-chai": "^3.5.0",
"sinon-stub-promise": "^4.0.0"
},

View File

@@ -35,13 +35,12 @@ async function deleteAmplitudeData (userId, email) {
}
async function deleteHabiticaData (user, email) {
const truncatedEmail = email.slice(0, email.indexOf('@'));
const set = {
'auth.blocked': false,
'auth.local.hashed_password': '$2a$10$QDnNh1j1yMPnTXDEOV38xOePEWFd4X8DSYwAM8XTmqmacG5X0DKjW',
'auth.local.passwordHashMethod': 'bcrypt',
};
if (!user.auth.local.email) set['auth.local.email'] = `${truncatedEmail}-gdpr@example.com`;
if (!user.auth.local.email) set['auth.local.email'] = `${user._id}@example.com`;
await User.update(
{ _id: user._id },
{ $set: set },

View File

@@ -3,6 +3,7 @@ import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../website/common';
import apiError from '../../../../../../website/server/libs/apiError';
import * as gems from '../../../../../../website/server/libs/payments/gems';
const { i18n } = common;
@@ -88,6 +89,7 @@ describe('Amazon Payments - Checkout', () => {
paymentCreateSubscritionStub.resolves({});
sinon.stub(common, 'uuid').returns('uuid-generated');
sandbox.stub(gems, 'validateGiftMessage');
});
afterEach(() => {
@@ -111,7 +113,10 @@ describe('Amazon Payments - Checkout', () => {
if (gift) {
expectedArgs.gift = gift;
expectedArgs.gemsBlock = undefined;
expect(gems.validateGiftMessage).to.be.calledOnce;
expect(gems.validateGiftMessage).to.be.calledWith(gift, user);
} else {
expect(gems.validateGiftMessage).to.not.be.called;
expectedArgs.gemsBlock = gemsBlock;
}
expect(paymentBuyGemsStub).to.be.calledWith(expectedArgs);

View File

@@ -5,6 +5,7 @@ import applePayments from '../../../../../website/server/libs/payments/apple';
import iap from '../../../../../website/server/libs/inAppPurchases';
import { model as User } from '../../../../../website/server/models/user';
import common from '../../../../../website/common';
import * as gems from '../../../../../website/server/libs/payments/gems';
const { i18n } = common;
@@ -15,7 +16,7 @@ describe('Apple Payments', () => {
let sku; let user; let token; let receipt; let
headers;
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let paymentBuyGemsStub; let
iapGetPurchaseDataStub;
iapGetPurchaseDataStub; let validateGiftMessageStub;
beforeEach(() => {
token = 'testToken';
@@ -36,6 +37,7 @@ describe('Apple Payments', () => {
transactionId: token,
}]);
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
validateGiftMessageStub = sinon.stub(gems, 'validateGiftMessage');
});
afterEach(() => {
@@ -44,6 +46,7 @@ describe('Apple Payments', () => {
iap.isValidated.restore();
iap.getPurchaseData.restore();
payments.buyGems.restore();
gems.validateGiftMessage.restore();
});
it('should throw an error if receipt is invalid', async () => {
@@ -143,6 +146,7 @@ describe('Apple Payments', () => {
expect(iapIsValidatedStub).to.be.calledOnce;
expect(iapIsValidatedStub).to.be.calledWith({});
expect(iapGetPurchaseDataStub).to.be.calledOnce;
expect(validateGiftMessageStub).to.not.be.called;
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
@@ -180,6 +184,9 @@ describe('Apple Payments', () => {
expect(iapIsValidatedStub).to.be.calledWith({});
expect(iapGetPurchaseDataStub).to.be.calledOnce;
expect(validateGiftMessageStub).to.be.calledOnce;
expect(validateGiftMessageStub).to.be.calledWith(gift, user);
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
user,

View File

@@ -1,5 +1,11 @@
import common from '../../../../../website/common';
import { getGemsBlock } from '../../../../../website/server/libs/payments/gems';
import {
getGemsBlock,
validateGiftMessage,
} from '../../../../../website/server/libs/payments/gems';
import { model as User } from '../../../../../website/server/models/user';
const { i18n } = common;
describe('payments/gems', () => {
describe('#getGemsBlock', () => {
@@ -11,4 +17,50 @@ describe('payments/gems', () => {
expect(getGemsBlock('21gems')).to.equal(common.content.gems['21gems']);
});
});
describe('#validateGiftMessage', () => {
let user;
let gift;
beforeEach(() => {
user = new User();
gift = {
message: (` // exactly 201 chars
A gift message that is over the 200 chars limit.
A gift message that is over the 200 chars limit.
A gift message that is over the 200 chars limit.
A gift message that is over the 200 chars limit. 1
`).trim().substring(0, 201),
};
expect(gift.message.length).to.equal(201);
});
it('throws if the gift message is too long', () => {
let expectedErr;
try {
validateGiftMessage(gift, user);
} catch (err) {
expectedErr = err;
}
expect(expectedErr).to.exist;
expect(expectedErr).to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('giftMessageTooLong', { maxGiftMessageLength: 200 }),
});
});
it('does not throw if the gift message is not too long', () => {
gift.message = gift.message.substring(0, 200);
expect(() => validateGiftMessage(gift, user)).to.not.throw;
});
it('does not throw if it is not a gift', () => {
expect(() => validateGiftMessage(null, user)).to.not.throw;
});
});
});

View File

@@ -5,6 +5,7 @@ import googlePayments from '../../../../../website/server/libs/payments/google';
import iap from '../../../../../website/server/libs/inAppPurchases';
import { model as User } from '../../../../../website/server/models/user';
import common from '../../../../../website/common';
import * as gems from '../../../../../website/server/libs/payments/gems';
const { i18n } = common;
@@ -15,7 +16,7 @@ describe('Google Payments', () => {
let sku; let user; let token; let receipt; let signature; let
headers; const gemsBlock = common.content.gems['21gems'];
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let
paymentBuyGemsStub;
paymentBuyGemsStub; let validateGiftMessageStub;
beforeEach(() => {
sku = 'com.habitrpg.android.habitica.iap.21gems';
@@ -31,6 +32,7 @@ describe('Google Payments', () => {
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
.returns(true);
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
validateGiftMessageStub = sinon.stub(gems, 'validateGiftMessage');
});
afterEach(() => {
@@ -38,6 +40,7 @@ describe('Google Payments', () => {
iap.validate.restore();
iap.isValidated.restore();
payments.buyGems.restore();
gems.validateGiftMessage.restore();
});
it('should throw an error if receipt is invalid', async () => {
@@ -89,6 +92,8 @@ describe('Google Payments', () => {
user, receipt, signature, headers,
});
expect(validateGiftMessageStub).to.not.be.called;
expect(iapSetupStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledWith(iap.GOOGLE, {
@@ -119,6 +124,9 @@ describe('Google Payments', () => {
user, gift, receipt, signature, headers,
});
expect(validateGiftMessageStub).to.be.calledOnce;
expect(validateGiftMessageStub).to.be.calledWith(gift, user);
expect(iapSetupStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledWith(iap.GOOGLE, {

View File

@@ -209,17 +209,6 @@ describe('payments/index', () => {
expect(user.purchased.txnCount).to.eql(1);
});
it('sends a private message about the gift', async () => {
await api.createSubscription(data);
const msg = '`Hello recipient, sender has sent you 3 months of subscription!`';
expect(user.sendMessage).to.be.calledOnce;
expect(user.sendMessage).to.be.calledWith(
recipient,
{ receiverMsg: msg, senderMsg: msg, save: false },
);
});
it('sends an email about the gift', async () => {
await api.createSubscription(data);
@@ -255,6 +244,109 @@ describe('payments/index', () => {
},
});
});
context('No Active Promotion', () => {
beforeEach(() => {
sinon.stub(worldState, 'getCurrentEvent').returns(null);
});
afterEach(() => {
worldState.getCurrentEvent.restore();
});
it('sends a private message about the gift', async () => {
await api.createSubscription(data);
const msg = '`Hello recipient, sender has sent you 3 months of subscription!`';
expect(user.sendMessage).to.be.calledOnce;
expect(user.sendMessage).to.be.calledWith(
recipient,
{ receiverMsg: msg, senderMsg: msg, save: false },
);
});
});
context('Active Promotion', () => {
beforeEach(() => {
sinon.stub(worldState, 'getCurrentEvent').returns({
...common.content.events.winter2021Promo,
event: 'winter2021',
});
});
afterEach(() => {
worldState.getCurrentEvent.restore();
});
it('creates a gift subscription for purchaser and recipient if none exist', async () => {
await api.createSubscription(data);
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(user.purchased.plan.customerId).to.eql('Gift');
expect(user.purchased.plan.dateTerminated).to.exist;
expect(user.purchased.plan.dateUpdated).to.exist;
expect(user.purchased.plan.dateCreated).to.exist;
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(recipient.purchased.plan.customerId).to.eql('Gift');
expect(recipient.purchased.plan.dateTerminated).to.exist;
expect(recipient.purchased.plan.dateUpdated).to.exist;
expect(recipient.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscription for purchaser and creates a gift subscription for recipient without sub', async () => {
user.purchased.plan = plan;
expect(user.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(user.purchased.plan.extraMonths).to.eql(3);
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(recipient.purchased.plan.customerId).to.eql('Gift');
expect(recipient.purchased.plan.dateTerminated).to.exist;
expect(recipient.purchased.plan.dateUpdated).to.exist;
expect(recipient.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscription for recipient and creates a gift subscription for purchaser without sub', async () => {
recipient.purchased.plan = plan;
expect(recipient.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(recipient.purchased.plan.extraMonths).to.eql(3);
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(user.purchased.plan.customerId).to.eql('Gift');
expect(user.purchased.plan.dateTerminated).to.exist;
expect(user.purchased.plan.dateUpdated).to.exist;
expect(user.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscriptions for purchaser and recipient', async () => {
user.purchased.plan = plan;
recipient.purchased.plan = plan;
expect(user.purchased.plan.extraMonths).to.eql(0);
expect(recipient.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(user.purchased.plan.extraMonths).to.eql(3);
expect(recipient.purchased.plan.extraMonths).to.eql(3);
});
it('sends a private message about the promotion', async () => {
await api.createSubscription(data);
const msg = '`Hello sender, you received 3 months of subscription as part of our holiday gift-giving promotion!`';
expect(user.sendMessage).to.be.calledTwice;
expect(user.sendMessage).to.be.calledWith(user, { receiverMsg: msg, save: false });
});
});
});
context('Purchasing a subscription for self', () => {

View File

@@ -5,6 +5,7 @@ import paypalPayments from '../../../../../../website/server/libs/payments/paypa
import { model as User } from '../../../../../../website/server/models/user';
import common from '../../../../../../website/common';
import apiError from '../../../../../../website/server/libs/apiError';
import * as gems from '../../../../../../website/server/libs/payments/gems';
const BASE_URL = nconf.get('BASE_URL');
const { i18n } = common;
@@ -48,6 +49,7 @@ describe('paypal - checkout', () => {
.resolves({
links: [{ rel: 'approval_url', href: approvalHerf }],
});
sandbox.stub(gems, 'validateGiftMessage');
});
afterEach(() => {
@@ -57,6 +59,7 @@ describe('paypal - checkout', () => {
it('creates a link for gem purchases', async () => {
const link = await paypalPayments.checkout({ user: new User(), gemsBlock: gemsBlockKey });
expect(gems.validateGiftMessage).to.not.be.called;
expect(paypalPaymentCreateStub).to.be.calledOnce;
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('Habitica Gems', 4.99));
expect(link).to.eql(approvalHerf);
@@ -105,6 +108,7 @@ describe('paypal - checkout', () => {
});
it('creates a link for gifting gems', async () => {
const user = new User();
const receivingUser = new User();
await receivingUser.save();
const gift = {
@@ -115,14 +119,17 @@ describe('paypal - checkout', () => {
},
};
const link = await paypalPayments.checkout({ gift });
const link = await paypalPayments.checkout({ user, gift });
expect(gems.validateGiftMessage).to.be.calledOnce;
expect(gems.validateGiftMessage).to.be.calledWith(gift, user);
expect(paypalPaymentCreateStub).to.be.calledOnce;
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('Habitica Gems (Gift)', '4.00'));
expect(link).to.eql(approvalHerf);
});
it('creates a link for gifting a subscription', async () => {
const user = new User();
const receivingUser = new User();
receivingUser.save();
const gift = {
@@ -133,7 +140,10 @@ describe('paypal - checkout', () => {
},
};
const link = await paypalPayments.checkout({ gift });
const link = await paypalPayments.checkout({ user, gift });
expect(gems.validateGiftMessage).to.be.calledOnce;
expect(gems.validateGiftMessage).to.be.calledWith(gift, user);
expect(paypalPaymentCreateStub).to.be.calledOnce;
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('mo. Habitica Subscription (Gift)', '15.00'));

View File

@@ -1,149 +0,0 @@
import stripeModule from 'stripe';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../website/common';
const { i18n } = common;
describe('stripe - cancel subscription', () => {
const subKey = 'basic_3mo';
const stripe = stripeModule('test');
let user; let groupId; let
group;
beforeEach(async () => {
user = new User();
user.profile.name = 'sender';
user.purchased.plan.customerId = 'customer-id';
user.purchased.plan.planId = subKey;
user.purchased.plan.lastBillingDate = new Date();
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
group.purchased.plan.customerId = 'customer-id';
group.purchased.plan.planId = subKey;
await group.save();
groupId = group._id;
});
it('throws an error if there is no customer id', async () => {
user.purchased.plan.customerId = undefined;
await expect(stripePayments.cancelSubscription({
user,
groupId: undefined,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('throws an error if the group is not found', async () => {
await expect(stripePayments.cancelSubscription({
user,
groupId: 'fake-group',
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('groupNotFound'),
});
});
it('throws an error if user is not the group leader', async () => {
const nonLeader = new User();
nonLeader.guilds.push(groupId);
await nonLeader.save();
await expect(stripePayments.cancelSubscription({
user: nonLeader,
groupId,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
});
});
describe('success', () => {
let stripeDeleteCustomerStub; let paymentsCancelSubStub;
let stripeRetrieveStub; let subscriptionId; let
currentPeriodEndTimeStamp;
beforeEach(() => {
subscriptionId = 'subId';
stripeDeleteCustomerStub = sinon.stub(stripe.customers, 'del').resolves({});
paymentsCancelSubStub = sinon.stub(payments, 'cancelSubscription').resolves({});
currentPeriodEndTimeStamp = (new Date()).getTime();
stripeRetrieveStub = sinon.stub(stripe.customers, 'retrieve')
.resolves({
subscriptions: {
data: [{
id: subscriptionId,
current_period_end: currentPeriodEndTimeStamp,
}], // eslint-disable-line camelcase
},
});
});
afterEach(() => {
stripe.customers.del.restore();
stripe.customers.retrieve.restore();
payments.cancelSubscription.restore();
});
it('cancels a user subscription', async () => {
await stripePayments.cancelSubscription({
user,
groupId: undefined,
}, stripe);
expect(stripeDeleteCustomerStub).to.be.calledOnce;
expect(stripeDeleteCustomerStub).to.be.calledWith(user.purchased.plan.customerId);
expect(stripeRetrieveStub).to.be.calledOnce;
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
expect(paymentsCancelSubStub).to.be.calledOnce;
expect(paymentsCancelSubStub).to.be.calledWith({
user,
groupId: undefined,
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
paymentMethod: 'Stripe',
cancellationReason: undefined,
});
});
it('cancels a group subscription', async () => {
await stripePayments.cancelSubscription({
user,
groupId,
}, stripe);
expect(stripeDeleteCustomerStub).to.be.calledOnce;
expect(stripeDeleteCustomerStub).to.be.calledWith(group.purchased.plan.customerId);
expect(stripeRetrieveStub).to.be.calledOnce;
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
expect(paymentsCancelSubStub).to.be.calledOnce;
expect(paymentsCancelSubStub).to.be.calledWith({
user,
groupId,
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
paymentMethod: 'Stripe',
cancellationReason: undefined,
});
});
});
});

View File

@@ -1,321 +0,0 @@
import stripeModule from 'stripe';
import cc from 'coupon-code';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import { model as Coupon } from '../../../../../../website/server/models/coupon';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../website/common';
const { i18n } = common;
describe('stripe - checkout with subscription', () => {
const subKey = 'basic_3mo';
const stripe = stripeModule('test');
let user; let group; let data; let gift; let sub;
let groupId; let email; let headers; let coupon;
let customerIdResponse; let subscriptionId; let
token;
let spy;
let stripeCreateCustomerSpy;
let stripePaymentsCreateSubSpy;
beforeEach(async () => {
user = new User();
user.profile.name = 'sender';
user.purchased.plan.customerId = 'customer-id';
user.purchased.plan.planId = subKey;
user.purchased.plan.lastBillingDate = new Date();
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
group.purchased.plan.customerId = 'customer-id';
group.purchased.plan.planId = subKey;
await group.save();
sub = {
key: 'basic_3mo',
};
data = {
user,
sub,
customerId: 'customer-id',
paymentMethod: 'Payment Method',
};
email = 'example@example.com';
customerIdResponse = 'test-id';
subscriptionId = 'test-sub-id';
token = 'test-token';
spy = sinon.stub(stripe.subscriptions, 'update');
spy.resolves;
stripeCreateCustomerSpy = sinon.stub(stripe.customers, 'create');
const stripCustomerResponse = {
id: customerIdResponse,
subscriptions: {
data: [{ id: subscriptionId }],
},
};
stripeCreateCustomerSpy.resolves(stripCustomerResponse);
stripePaymentsCreateSubSpy = sinon.stub(payments, 'createSubscription');
stripePaymentsCreateSubSpy.resolves({});
data.groupId = group._id;
data.sub.quantity = 3;
});
afterEach(() => {
stripe.subscriptions.update.restore();
stripe.customers.create.restore();
payments.createSubscription.restore();
});
it('should throw an error if we are missing a token', async () => {
await expect(stripePayments.checkout({
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: 'Missing req.body.id',
});
});
it('should throw an error when coupon code is missing', async () => {
sub.discount = 40;
await expect(stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('couponCodeRequired'),
});
});
it('should throw an error when coupon code is invalid', async () => {
sub.discount = 40;
sub.key = 'google_6mo';
coupon = 'example-coupon';
const couponModel = new Coupon();
couponModel.event = 'google_6mo';
await couponModel.save();
sinon.stub(cc, 'validate').returns('invalid');
await expect(stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('invalidCoupon'),
});
cc.validate.restore();
});
it('subscribes with stripe with a coupon', async () => {
sub.discount = 40;
sub.key = 'google_6mo';
coupon = 'example-coupon';
const couponModel = new Coupon();
couponModel.event = 'google_6mo';
const updatedCouponModel = await couponModel.save();
sinon.stub(cc, 'validate').returns(updatedCouponModel._id);
await stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeCreateCustomerSpy).to.be.calledOnce;
expect(stripeCreateCustomerSpy).to.be.calledWith({
email,
metadata: { uuid: user._id },
card: token,
plan: sub.key,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Stripe',
sub,
headers,
groupId: undefined,
subscriptionId: undefined,
});
cc.validate.restore();
});
it('subscribes a user', async () => {
sub = data.sub;
await stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeCreateCustomerSpy).to.be.calledOnce;
expect(stripeCreateCustomerSpy).to.be.calledWith({
email,
metadata: { uuid: user._id },
card: token,
plan: sub.key,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Stripe',
sub,
headers,
groupId: undefined,
subscriptionId: undefined,
});
});
it('subscribes a group', async () => {
token = 'test-token';
sub = data.sub;
groupId = group._id;
email = 'test@test.com';
// Add user to group
user.guilds.push(groupId);
await user.save();
headers = {};
await stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeCreateCustomerSpy).to.be.calledOnce;
expect(stripeCreateCustomerSpy).to.be.calledWith({
email,
metadata: { uuid: user._id },
card: token,
plan: sub.key,
quantity: 3,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Stripe',
sub,
headers,
groupId,
subscriptionId,
});
});
it('subscribes a group with the correct number of group members', async () => {
token = 'test-token';
sub = data.sub;
groupId = group._id;
email = 'test@test.com';
headers = {};
// Add user to group
user.guilds.push(groupId);
await user.save();
user = new User();
user.guilds.push(groupId);
await user.save();
group.memberCount = 2;
await group.save();
await stripePayments.checkout({
token,
user,
gift,
sub,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeCreateCustomerSpy).to.be.calledOnce;
expect(stripeCreateCustomerSpy).to.be.calledWith({
email,
metadata: { uuid: user._id },
card: token,
plan: sub.key,
quantity: 4,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Stripe',
sub,
headers,
groupId,
subscriptionId,
});
});
});

View File

@@ -1,235 +1,482 @@
import stripeModule from 'stripe';
import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../website/server/libs/payments/payments';
import nconf from 'nconf';
import common from '../../../../../../website/common';
import apiError from '../../../../../../website/server/libs/apiError';
import * as subscriptions from '../../../../../../website/server/libs/payments/stripe/subscriptions';
import * as oneTimePayments from '../../../../../../website/server/libs/payments/stripe/oneTimePayments';
import {
createCheckoutSession,
createEditCardCheckoutSession,
} from '../../../../../../website/server/libs/payments/stripe/checkout';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../website/server/models/group';
import * as gems from '../../../../../../website/server/libs/payments/gems';
const { i18n } = common;
describe('stripe - checkout', () => {
const subKey = 'basic_3mo';
describe('Stripe - Checkout', () => {
const stripe = stripeModule('test');
let stripeChargeStub; let paymentBuyGemsStub; let
paymentCreateSubscritionStub;
let user; let gift; let groupId; let email; let headers; let coupon; let customerIdResponse; let
token; const gemsBlockKey = '21gems'; const gemsBlock = common.content.gems[gemsBlockKey];
const BASE_URL = nconf.get('BASE_URL');
const redirectUrls = {
success_url: `${BASE_URL}/redirect/stripe-success-checkout`,
cancel_url: `${BASE_URL}/redirect/stripe-error-checkout`,
};
beforeEach(() => {
user = new User();
user.profile.name = 'sender';
user.purchased.plan.customerId = 'customer-id';
user.purchased.plan.planId = subKey;
user.purchased.plan.lastBillingDate = new Date();
describe('createCheckoutSession', () => {
let user;
const sessionId = 'session-id';
token = 'test-token';
beforeEach(() => {
user = new User();
sandbox.stub(stripe.checkout.sessions, 'create').returns(sessionId);
sandbox.stub(gems, 'validateGiftMessage');
});
customerIdResponse = 'example-customerIdResponse';
const stripCustomerResponse = {
id: customerIdResponse,
};
stripeChargeStub = sinon.stub(stripe.charges, 'create').resolves(stripCustomerResponse);
paymentBuyGemsStub = sinon.stub(payments, 'buyGems').resolves({});
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
});
afterEach(() => {
stripe.charges.create.restore();
payments.buyGems.restore();
payments.createSubscription.restore();
});
it('should error if there is no token', async () => {
await expect(stripePayments.checkout({
user,
gift,
groupId,
email,
headers,
coupon,
}, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: 'Missing req.body.id',
name: 'BadRequest',
it('gems', async () => {
const amount = 999;
const gemsBlockKey = '21gems';
sandbox.stub(oneTimePayments, 'getOneTimePaymentInfo').returns({
amount,
gemsBlock: common.content.gems[gemsBlockKey],
});
});
it('should error if gem amount is too low', async () => {
const receivingUser = new User();
receivingUser.save();
gift = {
type: 'gems',
gems: {
amount: 0,
uuid: receivingUser._id,
},
};
const res = await createCheckoutSession({ user, gemsBlock: gemsBlockKey }, stripe);
expect(res).to.equal(sessionId);
await expect(stripePayments.checkout({
token,
user,
gift,
groupId,
email,
headers,
coupon,
}, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: 'Amount must be at least 1.',
name: 'BadRequest',
const metadata = {
type: 'gems',
userId: user._id,
gift: undefined,
sub: undefined,
gemsBlock: gemsBlockKey,
};
expect(gems.validateGiftMessage).to.not.be.called;
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledWith(gemsBlockKey, undefined, user);
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
payment_method_types: ['card'],
metadata,
line_items: [{
price_data: {
product_data: {
name: common.i18n.t('nGems', { nGems: 21 }),
},
unit_amount: amount,
currency: 'usd',
},
quantity: 1,
}],
mode: 'payment',
...redirectUrls,
});
});
it('should error if user cannot get gems', async () => {
gift = undefined;
sinon.stub(user, 'canGetGems').resolves(false);
await expect(stripePayments.checkout({
token,
user,
gemsBlock: gemsBlockKey,
gift,
groupId,
email,
headers,
coupon,
}, stripe)).to.eventually.be.rejected.and.to.eql({
httpCode: 401,
message: i18n.t('groupPolicyCannotGetGems'),
name: 'NotAuthorized',
});
});
it('should error if the gems block is invalid', async () => {
gift = undefined;
await expect(stripePayments.checkout({
token,
user,
gemsBlock: 'invalid',
gift,
groupId,
email,
headers,
coupon,
}, stripe)).to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: apiError('invalidGemsBlock'),
name: 'BadRequest',
});
});
it('should purchase gems', async () => {
gift = undefined;
sinon.stub(user, 'canGetGems').resolves(true);
await stripePayments.checkout({
token,
user,
gemsBlock: gemsBlockKey,
gift,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeChargeStub).to.be.calledOnce;
expect(stripeChargeStub).to.be.calledWith({
amount: 499,
currency: 'usd',
card: token,
});
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Stripe',
gift,
gemsBlock,
});
expect(user.canGetGems).to.be.calledOnce;
user.canGetGems.restore();
});
it('gems gift', async () => {
const receivingUser = new User();
await receivingUser.save();
it('should gift gems', async () => {
const receivingUser = new User();
await receivingUser.save();
gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 16,
},
};
await stripePayments.checkout({
token,
user,
gift,
groupId,
email,
headers,
coupon,
}, stripe);
expect(stripeChargeStub).to.be.calledOnce;
expect(stripeChargeStub).to.be.calledWith({
amount: '400',
currency: 'usd',
card: token,
});
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Gift',
gift,
gemsBlock: undefined,
});
});
it('should gift a subscription', async () => {
const receivingUser = new User();
receivingUser.save();
gift = {
type: 'subscription',
subscription: {
key: subKey,
const gift = {
type: 'gems',
uuid: receivingUser._id,
},
};
gems: {
amount: 4,
},
};
const amount = 100;
sandbox.stub(oneTimePayments, 'getOneTimePaymentInfo').returns({
amount,
gemsBlock: null,
});
await stripePayments.checkout({
token,
user,
gift,
groupId,
email,
headers,
coupon,
}, stripe);
const res = await createCheckoutSession({ user, gift }, stripe);
expect(res).to.equal(sessionId);
gift.member = receivingUser;
expect(stripeChargeStub).to.be.calledOnce;
expect(stripeChargeStub).to.be.calledWith({
amount: '1500',
currency: 'usd',
card: token,
const metadata = {
type: 'gift-gems',
userId: user._id,
gift: JSON.stringify(gift),
sub: undefined,
gemsBlock: undefined,
};
expect(gems.validateGiftMessage).to.be.calledOnce;
expect(gems.validateGiftMessage).to.be.calledWith(gift, user);
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledWith(undefined, gift, user);
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
payment_method_types: ['card'],
metadata,
line_items: [{
price_data: {
product_data: {
name: common.i18n.t('nGemsGift', { nGems: 4 }),
},
unit_amount: amount,
currency: 'usd',
},
quantity: 1,
}],
mode: 'payment',
...redirectUrls,
});
});
expect(paymentCreateSubscritionStub).to.be.calledOnce;
expect(paymentCreateSubscritionStub).to.be.calledWith({
user,
customerId: customerIdResponse,
paymentMethod: 'Gift',
gift,
gemsBlock: undefined,
it('subscription gift', async () => {
const receivingUser = new User();
await receivingUser.save();
const subKey = 'basic_3mo';
const gift = {
type: 'subscription',
uuid: receivingUser._id,
subscription: {
key: subKey,
},
};
const amount = 1500;
sandbox.stub(oneTimePayments, 'getOneTimePaymentInfo').returns({
amount,
gemsBlock: null,
subscription: common.content.subscriptionBlocks[subKey],
});
const res = await createCheckoutSession({ user, gift }, stripe);
expect(res).to.equal(sessionId);
const metadata = {
type: 'gift-sub',
userId: user._id,
gift: JSON.stringify(gift),
sub: undefined,
gemsBlock: undefined,
};
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledWith(undefined, gift, user);
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
payment_method_types: ['card'],
metadata,
line_items: [{
price_data: {
product_data: {
name: common.i18n.t('nMonthsSubscriptionGift', { nMonths: 3 }),
},
unit_amount: amount,
currency: 'usd',
},
quantity: 1,
}],
mode: 'payment',
...redirectUrls,
});
});
it('subscription', async () => {
const subKey = 'basic_3mo';
const coupon = null;
sandbox.stub(subscriptions, 'checkSubData').returns(undefined);
const sub = common.content.subscriptionBlocks[subKey];
const res = await createCheckoutSession({ user, sub, coupon }, stripe);
expect(res).to.equal(sessionId);
const metadata = {
type: 'subscription',
userId: user._id,
gift: undefined,
sub: JSON.stringify(sub),
};
expect(subscriptions.checkSubData).to.be.calledOnce;
expect(subscriptions.checkSubData).to.be.calledWith(sub, false, coupon);
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
payment_method_types: ['card'],
metadata,
line_items: [{
price: sub.key,
quantity: 1,
// @TODO proper copy
}],
mode: 'subscription',
...redirectUrls,
});
});
it('throws if group does not exists', async () => {
const groupId = 'invalid';
sandbox.stub(Group.prototype, 'getMemberCount').resolves(4);
const subKey = 'group_monthly';
const coupon = null;
const sub = common.content.subscriptionBlocks[subKey];
await expect(createCheckoutSession({
user, sub, coupon, groupId,
}, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('groupNotFound'),
});
});
it('group plan', async () => {
const group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
const groupId = group._id;
await group.save();
sandbox.stub(Group.prototype, 'getMemberCount').resolves(4);
// Add user to group
user.guilds.push(groupId);
await user.save();
const subKey = 'group_monthly';
const coupon = null;
sandbox.stub(subscriptions, 'checkSubData').returns(undefined);
const sub = common.content.subscriptionBlocks[subKey];
const res = await createCheckoutSession({
user, sub, coupon, groupId,
}, stripe);
expect(res).to.equal(sessionId);
const metadata = {
type: 'subscription',
userId: user._id,
gift: undefined,
sub: JSON.stringify(sub),
groupId,
};
expect(Group.prototype.getMemberCount).to.be.calledOnce;
expect(subscriptions.checkSubData).to.be.calledOnce;
expect(subscriptions.checkSubData).to.be.calledWith(sub, true, coupon);
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
payment_method_types: ['card'],
metadata,
line_items: [{
price: sub.key,
quantity: 6,
// @TODO proper copy
}],
mode: 'subscription',
...redirectUrls,
});
});
// no gift, sub or gem payment
it('throws if type is invalid', async () => {
await expect(createCheckoutSession({ user }, stripe))
.to.eventually.be.rejected;
});
});
describe('createEditCardCheckoutSession', () => {
let user;
const sessionId = 'session-id';
const customerId = 'customerId';
const subscriptionId = 'subscription-id';
let subscriptionsListStub;
beforeEach(() => {
user = new User();
sandbox.stub(stripe.checkout.sessions, 'create').returns(sessionId);
subscriptionsListStub = sandbox.stub(stripe.subscriptions, 'list');
subscriptionsListStub.resolves({ data: [{ id: subscriptionId }] });
});
it('throws if no valid data is supplied', async () => {
await expect(createEditCardCheckoutSession({}, stripe))
.to.eventually.be.rejected;
});
it('throws if customer does not exists', async () => {
await expect(createEditCardCheckoutSession({ user }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('throws if subscription does not exists', async () => {
user.purchased.plan.customerId = customerId;
subscriptionsListStub.resolves({ data: [] });
await expect(createEditCardCheckoutSession({ user }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('change card for user subscription', async () => {
user.purchased.plan.customerId = customerId;
const metadata = {
userId: user._id,
type: 'edit-card-user',
};
const res = await createEditCardCheckoutSession({ user }, stripe);
expect(res).to.equal(sessionId);
expect(subscriptionsListStub).to.be.calledOnce;
expect(subscriptionsListStub).to.be.calledWith({ customer: customerId });
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
mode: 'setup',
payment_method_types: ['card'],
metadata,
customer: customerId,
setup_intent_data: {
metadata: {
customer_id: customerId,
subscription_id: subscriptionId,
},
},
...redirectUrls,
});
});
it('throws if group does not exists', async () => {
const groupId = 'invalid';
await expect(createEditCardCheckoutSession({ user, groupId }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('groupNotFound'),
});
});
describe('with group', () => {
let group; let groupId;
beforeEach(async () => {
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
groupId = group._id;
await group.save();
});
it('throws if user is not allowed to change group plan', async () => {
const anotherUser = new User();
anotherUser.guilds.push(groupId);
await anotherUser.save();
await expect(createEditCardCheckoutSession({ user: anotherUser, groupId }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
});
});
it('throws if customer does not exists (group)', async () => {
await expect(createEditCardCheckoutSession({ user, groupId }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('throws if subscription does not exists (group)', async () => {
group.purchased.plan.customerId = customerId;
subscriptionsListStub.resolves({ data: [] });
await expect(createEditCardCheckoutSession({ user, groupId }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('change card for group plans - leader', async () => {
group.purchased.plan.customerId = customerId;
await group.save();
const metadata = {
userId: user._id,
type: 'edit-card-group',
groupId,
};
const res = await createEditCardCheckoutSession({ user, groupId }, stripe);
expect(res).to.equal(sessionId);
expect(subscriptionsListStub).to.be.calledOnce;
expect(subscriptionsListStub).to.be.calledWith({ customer: customerId });
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
mode: 'setup',
payment_method_types: ['card'],
metadata,
customer: customerId,
setup_intent_data: {
metadata: {
customer_id: customerId,
subscription_id: subscriptionId,
},
},
...redirectUrls,
});
});
it('change card for group plans - plan owner', async () => {
const anotherUser = new User();
anotherUser.guilds.push(groupId);
await anotherUser.save();
group.purchased.plan.customerId = customerId;
group.purchased.plan.owner = anotherUser._id;
await group.save();
const metadata = {
userId: anotherUser._id,
type: 'edit-card-group',
groupId,
};
const res = await createEditCardCheckoutSession({ user: anotherUser, groupId }, stripe);
expect(res).to.equal(sessionId);
expect(subscriptionsListStub).to.be.calledOnce;
expect(subscriptionsListStub).to.be.calledWith({ customer: customerId });
expect(stripe.checkout.sessions.create).to.be.calledOnce;
expect(stripe.checkout.sessions.create).to.be.calledWith({
mode: 'setup',
payment_method_types: ['card'],
metadata,
customer: customerId,
setup_intent_data: {
metadata: {
customer_id: customerId,
subscription_id: subscriptionId,
},
},
...redirectUrls,
});
});
});
});
});

View File

@@ -1,151 +0,0 @@
import stripeModule from 'stripe';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import common from '../../../../../../website/common';
const { i18n } = common;
describe('stripe - edit subscription', () => {
const subKey = 'basic_3mo';
const stripe = stripeModule('test');
let user; let groupId; let group; let
token;
beforeEach(async () => {
user = new User();
user.profile.name = 'sender';
user.purchased.plan.customerId = 'customer-id';
user.purchased.plan.planId = subKey;
user.purchased.plan.lastBillingDate = new Date();
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
group.purchased.plan.customerId = 'customer-id';
group.purchased.plan.planId = subKey;
await group.save();
groupId = group._id;
token = 'test-token';
});
it('throws an error if there is no customer id', async () => {
user.purchased.plan.customerId = undefined;
await expect(stripePayments.editSubscription({
user,
groupId: undefined,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('throws an error if a token is not provided', async () => {
await expect(stripePayments.editSubscription({
user,
groupId: undefined,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: 'Missing req.body.id',
});
});
it('throws an error if the group is not found', async () => {
await expect(stripePayments.editSubscription({
token,
user,
groupId: 'fake-group',
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('groupNotFound'),
});
});
it('throws an error if user is not the group leader', async () => {
const nonLeader = new User();
nonLeader.guilds.push(groupId);
await nonLeader.save();
await expect(stripePayments.editSubscription({
token,
user: nonLeader,
groupId,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
});
});
describe('success', () => {
let stripeListSubscriptionStub; let stripeUpdateSubscriptionStub; let
subscriptionId;
beforeEach(() => {
subscriptionId = 'subId';
stripeListSubscriptionStub = sinon.stub(stripe.subscriptions, 'list')
.resolves({
data: [{ id: subscriptionId }],
});
stripeUpdateSubscriptionStub = sinon.stub(stripe.subscriptions, 'update').resolves({});
});
afterEach(() => {
stripe.subscriptions.list.restore();
stripe.subscriptions.update.restore();
});
it('edits a user subscription', async () => {
await stripePayments.editSubscription({
token,
user,
groupId: undefined,
}, stripe);
expect(stripeListSubscriptionStub).to.be.calledOnce;
expect(stripeListSubscriptionStub).to.be.calledWith({
customer: user.purchased.plan.customerId,
});
expect(stripeUpdateSubscriptionStub).to.be.calledOnce;
expect(stripeUpdateSubscriptionStub).to.be.calledWith(
subscriptionId,
{ card: token },
);
});
it('edits a group subscription', async () => {
await stripePayments.editSubscription({
token,
user,
groupId,
}, stripe);
expect(stripeListSubscriptionStub).to.be.calledOnce;
expect(stripeListSubscriptionStub).to.be.calledWith({
customer: group.purchased.plan.customerId,
});
expect(stripeUpdateSubscriptionStub).to.be.calledOnce;
expect(stripeUpdateSubscriptionStub).to.be.calledWith(
subscriptionId,
{ card: token },
);
});
});
});

View File

@@ -0,0 +1,316 @@
import apiError from '../../../../../../website/server/libs/apiError';
import common from '../../../../../../website/common';
import {
getOneTimePaymentInfo,
applyGemPayment,
} from '../../../../../../website/server/libs/payments/stripe/oneTimePayments';
import * as subscriptions from '../../../../../../website/server/libs/payments/stripe/subscriptions';
import { model as User } from '../../../../../../website/server/models/user';
import payments from '../../../../../../website/server/libs/payments/payments';
const { i18n } = common;
describe('Stripe - One Time Payments', () => {
describe('getOneTimePaymentInfo', () => {
let user;
beforeEach(() => {
user = new User();
sandbox.stub(subscriptions, 'checkSubData');
});
describe('gemsBlock', () => {
it('returns the gemsBlock and amount', async () => {
const { gemsBlock, amount, subscription } = await getOneTimePaymentInfo('21gems', null, user);
expect(gemsBlock).to.equal(common.content.gems['21gems']);
expect(amount).to.equal(gemsBlock.price);
expect(amount).to.equal(499);
expect(subscription).to.be.null;
expect(subscriptions.checkSubData).to.not.be.called;
});
it('throws if the gemsBlock does not exist', async () => {
await expect(getOneTimePaymentInfo('not existant', null, user))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: apiError('invalidGemsBlock'),
});
});
it('throws if the user cannot receive gems', async () => {
sandbox.stub(user, 'canGetGems').resolves(false);
await expect(getOneTimePaymentInfo('21gems', null, user))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('groupPolicyCannotGetGems'),
});
});
});
describe('gift', () => {
it('throws if the receiver does not exist', async () => {
const gift = {
type: 'gems',
uuid: 'invalid',
gems: {
amount: 3,
},
};
await expect(getOneTimePaymentInfo(null, gift, user))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('userWithIDNotFound', { userId: 'invalid' }),
});
});
it('throws if the user cannot receive gems', async () => {
const receivingUser = new User();
await receivingUser.save();
sandbox.stub(User.prototype, 'canGetGems').resolves(false);
const gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 2,
},
};
await expect(getOneTimePaymentInfo(null, gift, user))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('groupPolicyCannotGetGems'),
});
});
it('throws if the amount of gems is <= 0', async () => {
const receivingUser = new User();
await receivingUser.save();
const gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 0,
},
};
await expect(getOneTimePaymentInfo(null, gift, user))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('badAmountOfGemsToPurchase'),
});
});
it('throws if the subscription block does not exist', async () => {
const receivingUser = new User();
await receivingUser.save();
const gift = {
type: 'subscription',
uuid: receivingUser._id,
subscription: {
key: 'invalid',
},
};
await expect(getOneTimePaymentInfo(null, gift, user))
.to.eventually.throw;
});
it('returns the amount (gems)', async () => {
const receivingUser = new User();
await receivingUser.save();
const gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 4,
},
};
expect(subscriptions.checkSubData).to.not.be.called;
const { gemsBlock, amount, subscription } = await getOneTimePaymentInfo(null, gift, user);
expect(gemsBlock).to.equal(null);
expect(amount).to.equal('100');
expect(subscription).to.be.null;
});
it('returns the amount (subscription)', async () => {
const receivingUser = new User();
await receivingUser.save();
const gift = {
type: 'subscription',
uuid: receivingUser._id,
subscription: {
key: 'basic_3mo',
},
};
const sub = common.content.subscriptionBlocks['basic_3mo']; // eslint-disable-line dot-notation
const { gemsBlock, amount, subscription } = await getOneTimePaymentInfo(null, gift, user);
expect(subscriptions.checkSubData).to.be.calledOnce;
expect(subscriptions.checkSubData).to.be.calledWith(sub, false, null);
expect(gemsBlock).to.equal(null);
expect(amount).to.equal('1500');
expect(Number(amount)).to.equal(sub.price * 100);
expect(subscription).to.equal(sub);
});
});
});
describe('applyGemPayment', () => {
let user;
let customerId;
let subKey;
let userFindByIdStub;
let paymentsCreateSubSpy;
let paymentBuyGemsStub;
beforeEach(async () => {
subKey = 'basic_3mo';
user = new User();
await user.save();
customerId = 'test-id';
paymentsCreateSubSpy = sandbox.stub(payments, 'createSubscription');
paymentsCreateSubSpy.resolves({});
paymentBuyGemsStub = sandbox.stub(payments, 'buyGems');
paymentBuyGemsStub.resolves({});
});
it('throws if the user does not exist', async () => {
const metadata = { userId: 'invalid' };
const session = { metadata, customer: customerId };
await expect(applyGemPayment(session))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('userWithIDNotFound', { userId: metadata.userId }),
});
});
it('throws if the receiving user does not exist', async () => {
const metadata = { userId: 'invalid' };
const session = { metadata, customer: customerId };
await expect(applyGemPayment(session))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('userWithIDNotFound', { userId: metadata.userId }),
});
});
it('throws if the gems block does not exist', async () => {
const gift = {
type: 'gems',
uuid: 'invalid',
gems: {
amount: 16,
},
};
const metadata = { userId: user._id, gift: JSON.stringify(gift) };
const session = { metadata, customer: customerId };
await expect(applyGemPayment(session))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('userWithIDNotFound', { userId: 'invalid' }),
});
});
describe('with existing user', () => {
beforeEach(() => {
const execStub = sandbox.stub().resolves(user);
userFindByIdStub = sandbox.stub(User, 'findById');
userFindByIdStub.withArgs(user._id).returns({ exec: execStub });
});
it('buys gems', async () => {
const metadata = { userId: user._id, gemsBlock: '21gems' };
const session = { metadata, customer: customerId };
await applyGemPayment(session);
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
user,
customerId,
paymentMethod: 'Stripe',
gift: undefined,
gemsBlock: common.content.gems['21gems'],
});
});
it('gift gems', async () => {
const receivingUser = new User();
const execStub = sandbox.stub().resolves(receivingUser);
userFindByIdStub.withArgs(receivingUser._id).returns({ exec: execStub });
const gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 16,
},
};
sandbox.stub(JSON, 'parse').returns(gift);
const metadata = { userId: user._id, gift: JSON.stringify(gift) };
const session = { metadata, customer: customerId };
await applyGemPayment(session);
expect(paymentBuyGemsStub).to.be.calledOnce;
expect(paymentBuyGemsStub).to.be.calledWith({
user,
customerId,
paymentMethod: 'Gift',
gift,
gemsBlock: undefined,
});
});
it('gift sub', async () => {
const receivingUser = new User();
const execStub = sandbox.stub().resolves(receivingUser);
userFindByIdStub.withArgs(receivingUser._id).returns({ exec: execStub });
const gift = {
type: 'subscription',
uuid: receivingUser._id,
subscription: {
key: subKey,
},
};
sandbox.stub(JSON, 'parse').returns(gift);
const metadata = { userId: user._id, gift: JSON.stringify(gift) };
const session = { metadata, customer: customerId };
await applyGemPayment(session);
expect(paymentsCreateSubSpy).to.be.calledOnce;
expect(paymentsCreateSubSpy).to.be.calledWith({
user,
customerId,
paymentMethod: 'Gift',
gift,
gemsBlock: undefined,
});
});
});
});
});

View File

@@ -0,0 +1,436 @@
import cc from 'coupon-code';
import stripeModule from 'stripe';
import { model as Coupon } from '../../../../../../website/server/models/coupon';
import common from '../../../../../../website/common';
import {
checkSubData,
applySubscription,
chargeForAdditionalGroupMember,
handlePaymentMethodChange,
} from '../../../../../../website/server/libs/payments/stripe/subscriptions';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import payments from '../../../../../../website/server/libs/payments/payments';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
const { i18n } = common;
describe('Stripe - Subscriptions', () => {
describe('checkSubData', () => {
it('does not throw if the subscription can be used', async () => {
const sub = common.content.subscriptionBlocks['basic_3mo']; // eslint-disable-line dot-notation
const res = await checkSubData(sub);
expect(res).to.equal(undefined);
});
it('throws if the subscription does not exists', async () => {
await expect(checkSubData())
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('missingSubscriptionCode'),
});
});
it('throws if the subscription can\'t be used', async () => {
const sub = common.content.subscriptionBlocks['group_plan_auto']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, true))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('missingSubscriptionCode'),
});
});
it('throws if the subscription targets a group and an user is making the request', async () => {
const sub = common.content.subscriptionBlocks['group_monthly']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, false))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('missingSubscriptionCode'),
});
});
it('throws if the subscription targets an user and a group is making the request', async () => {
const sub = common.content.subscriptionBlocks['basic_3mo']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, true))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('missingSubscriptionCode'),
});
});
it('throws if the coupon is required but not passed', async () => {
const sub = common.content.subscriptionBlocks['google_6mo']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, false))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('couponCodeRequired'),
});
});
it('throws if the coupon is required but does not exist', async () => {
const coupon = 'not-valid';
const sub = common.content.subscriptionBlocks['google_6mo']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, false, coupon))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('invalidCoupon'),
});
});
it('throws if the coupon is required but is invalid', async () => {
const couponModel = new Coupon();
couponModel.event = 'google_6mo';
await couponModel.save();
sandbox.stub(cc, 'validate').returns('invalid');
const sub = common.content.subscriptionBlocks['google_6mo']; // eslint-disable-line dot-notation
await expect(checkSubData(sub, false, couponModel._id))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: i18n.t('invalidCoupon'),
});
});
it('works if the coupon is required and valid', async () => {
const couponModel = new Coupon();
couponModel.event = 'google_6mo';
await couponModel.save();
sandbox.stub(cc, 'validate').returns(couponModel._id);
const sub = common.content.subscriptionBlocks['google_6mo']; // eslint-disable-line dot-notation
await checkSubData(sub, false, couponModel._id);
});
});
describe('applySubscription', () => {
let user; let group; let sub;
let groupId;
let customerId; let subscriptionId;
let subKey;
let userFindByIdStub;
let stripePaymentsCreateSubSpy;
beforeEach(async () => {
subKey = 'basic_3mo';
sub = common.content.subscriptionBlocks[subKey];
user = new User();
await user.save();
const execStub = sandbox.stub().resolves(user);
userFindByIdStub = sandbox.stub(User, 'findById');
userFindByIdStub.withArgs(user._id).returns({ exec: execStub });
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
groupId = group._id;
await group.save();
// Add user to group
user.guilds.push(groupId);
await user.save();
customerId = 'test-id';
subscriptionId = 'test-sub-id';
stripePaymentsCreateSubSpy = sandbox.stub(payments, 'createSubscription');
stripePaymentsCreateSubSpy.resolves({});
});
it('subscribes a user', async () => {
await applySubscription({
customer: customerId,
subscription: subscriptionId,
metadata: {
sub: JSON.stringify(sub),
userId: user._id,
groupId: null,
},
user,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId,
subscriptionId,
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId: null,
});
});
it('subscribes a group', async () => {
sub = common.content.subscriptionBlocks['group_monthly']; // eslint-disable-line dot-notation
await applySubscription({
customer: customerId,
subscription: subscriptionId,
metadata: {
sub: JSON.stringify(sub),
userId: user._id,
groupId,
},
user,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId,
subscriptionId,
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId,
});
});
it('subscribes a group with multiple users', async () => {
const user2 = new User();
user2.guilds.push(groupId);
await user2.save();
const execStub2 = sandbox.stub().resolves(user);
userFindByIdStub.withArgs(user2._id).returns({ exec: execStub2 });
group.memberCount = 2;
await group.save();
sub = common.content.subscriptionBlocks['group_monthly']; // eslint-disable-line dot-notation
await applySubscription({
customer: customerId,
subscription: subscriptionId,
metadata: {
sub: JSON.stringify(sub),
userId: user._id,
groupId,
},
user,
});
expect(stripePaymentsCreateSubSpy).to.be.calledOnce;
expect(stripePaymentsCreateSubSpy).to.be.calledWith({
user,
customerId,
subscriptionId,
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId,
});
});
});
describe('handlePaymentMethodChange', () => {
const stripe = stripeModule('test');
it('updates the plan quantity based on the number of group members', async () => {
const stripeIntentRetrieveStub = sandbox.stub(stripe.setupIntents, 'retrieve').resolves({
payment_method: 1,
metadata: {
subscription_id: 2,
},
});
const stripeSubUpdateStub = sandbox.stub(stripe.subscriptions, 'update');
await handlePaymentMethodChange({}, stripe);
expect(stripeIntentRetrieveStub).to.be.calledOnce;
expect(stripeSubUpdateStub).to.be.calledOnce;
expect(stripeSubUpdateStub).to.be.calledWith(2, {
default_payment_method: 1,
});
});
});
describe('chargeForAdditionalGroupMember', () => {
const stripe = stripeModule('test');
let stripeUpdateSubStub;
const plan = common.content.subscriptionBlocks['group_monthly']; // eslint-disable-line dot-notation
let user; let group;
beforeEach(async () => {
user = new User();
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
group.purchased.plan.customerId = 'customer-id';
group.purchased.plan.planId = plan.key;
group.purchased.plan.subscriptionId = 'sub-id';
await group.save();
stripeUpdateSubStub = sandbox.stub(stripe.subscriptions, 'update').resolves({});
});
it('updates the plan quantity based on the number of group members', async () => {
group.memberCount = 4;
const newQuantity = group.memberCount + plan.quantity - 1;
await chargeForAdditionalGroupMember(group, stripe);
expect(stripeUpdateSubStub).to.be.calledWithMatch(
group.purchased.plan.subscriptionId,
sinon.match({
plan: group.purchased.plan.planId,
quantity: newQuantity,
}),
);
expect(group.purchased.plan.quantity).to.equal(newQuantity);
});
});
describe('cancelSubscription', () => {
const subKey = 'basic_3mo';
const stripe = stripeModule('test');
let user; let groupId; let
group;
beforeEach(async () => {
user = new User();
user.profile.name = 'sender';
user.purchased.plan.customerId = 'customer-id';
user.purchased.plan.planId = subKey;
user.purchased.plan.lastBillingDate = new Date();
group = generateGroup({
name: 'test group',
type: 'guild',
privacy: 'public',
leader: user._id,
});
group.purchased.plan.customerId = 'customer-id';
group.purchased.plan.planId = subKey;
await group.save();
groupId = group._id;
});
it('throws an error if there is no customer id', async () => {
user.purchased.plan.customerId = undefined;
await expect(stripePayments.cancelSubscription({
user,
groupId: undefined,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('missingSubscription'),
});
});
it('throws an error if the group is not found', async () => {
await expect(stripePayments.cancelSubscription({
user,
groupId: 'fake-group',
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 404,
name: 'NotFound',
message: i18n.t('groupNotFound'),
});
});
it('throws an error if user is not the group leader', async () => {
const nonLeader = new User();
nonLeader.guilds.push(groupId);
await nonLeader.save();
await expect(stripePayments.cancelSubscription({
user: nonLeader,
groupId,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
});
});
describe('success', () => {
let stripeDeleteCustomerStub; let paymentsCancelSubStub;
let stripeRetrieveStub; let subscriptionId; let
currentPeriodEndTimeStamp;
beforeEach(() => {
subscriptionId = 'subId';
stripeDeleteCustomerStub = sinon.stub(stripe.customers, 'del').resolves({});
paymentsCancelSubStub = sinon.stub(payments, 'cancelSubscription').resolves({});
currentPeriodEndTimeStamp = (new Date()).getTime();
stripeRetrieveStub = sinon.stub(stripe.customers, 'retrieve')
.resolves({
subscriptions: {
data: [{
id: subscriptionId,
current_period_end: currentPeriodEndTimeStamp,
}], // eslint-disable-line camelcase
},
});
});
afterEach(() => {
stripe.customers.del.restore();
stripe.customers.retrieve.restore();
payments.cancelSubscription.restore();
});
it('cancels a user subscription', async () => {
await stripePayments.cancelSubscription({
user,
groupId: undefined,
}, stripe);
expect(stripeDeleteCustomerStub).to.be.calledOnce;
expect(stripeDeleteCustomerStub).to.be.calledWith(user.purchased.plan.customerId);
expect(stripeRetrieveStub).to.be.calledOnce;
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
expect(paymentsCancelSubStub).to.be.calledOnce;
expect(paymentsCancelSubStub).to.be.calledWith({
user,
groupId: undefined,
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
paymentMethod: 'Stripe',
cancellationReason: undefined,
});
});
it('cancels a group subscription', async () => {
await stripePayments.cancelSubscription({
user,
groupId,
}, stripe);
expect(stripeDeleteCustomerStub).to.be.calledOnce;
expect(stripeDeleteCustomerStub).to.be.calledWith(group.purchased.plan.customerId);
expect(stripeRetrieveStub).to.be.calledOnce;
expect(stripeRetrieveStub).to.be.calledWith(user.purchased.plan.customerId);
expect(paymentsCancelSubStub).to.be.calledOnce;
expect(paymentsCancelSubStub).to.be.calledWith({
user,
groupId,
nextBill: currentPeriodEndTimeStamp * 1000, // timestamp in seconds
paymentMethod: 'Stripe',
cancellationReason: undefined,
});
});
});
});
});

View File

@@ -1,70 +0,0 @@
import stripeModule from 'stripe';
import {
generateGroup,
} from '../../../../../helpers/api-unit.helper';
import { model as User } from '../../../../../../website/server/models/user';
import { model as Group } from '../../../../../../website/server/models/group';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import payments from '../../../../../../website/server/libs/payments/payments';
describe('Stripe - Upgrade Group Plan', () => {
const stripe = stripeModule('test');
let spy; let data; let user; let
group;
beforeEach(async () => {
user = new User();
user.profile.name = 'sender';
data = {
user,
sub: {
key: 'basic_3mo', // @TODO: Validate that this is group
},
customerId: 'customer-id',
paymentMethod: 'Payment Method',
headers: {
'x-client': 'habitica-web',
'user-agent': '',
},
};
group = generateGroup({
name: 'test group',
type: 'guild',
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;
data.sub.quantity = 3;
stripePayments.setStripeApi(stripe);
});
afterEach(() => {
stripe.subscriptions.update.restore();
});
it('updates a group plan quantity', async () => {
data.paymentMethod = 'Stripe';
await payments.createSubscription(data);
const updatedGroup = await Group.findById(group._id).exec();
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
updatedGroup.memberCount += 1;
await updatedGroup.save();
await stripePayments.chargeForAdditionalGroupMember(updatedGroup);
expect(spy.calledOnce).to.be.true;
expect(updatedGroup.purchased.plan.quantity).to.eql(4);
});
});

View File

@@ -1,5 +1,5 @@
import stripeModule from 'stripe';
import nconf from 'nconf';
import { v4 as uuid } from 'uuid';
import moment from 'moment';
import {
@@ -10,76 +10,102 @@ import stripePayments from '../../../../../../website/server/libs/payments/strip
import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../website/common';
import logger from '../../../../../../website/server/libs/logger';
import * as oneTimePayments from '../../../../../../website/server/libs/payments/stripe/oneTimePayments';
import * as subscriptions from '../../../../../../website/server/libs/payments/stripe/subscriptions';
const { i18n } = common;
describe('Stripe - Webhooks', () => {
const stripe = stripeModule('test');
const endpointSecret = nconf.get('STRIPE_WEBHOOKS_ENDPOINT_SECRET');
const headers = {};
const body = {};
describe('all events', () => {
const eventType = 'account.updated';
const event = { id: 123 };
const eventRetrieved = { type: eventType };
let event;
let constructEventStub;
beforeEach(() => {
sinon.stub(stripe.events, 'retrieve').resolves(eventRetrieved);
sinon.stub(logger, 'error');
event = { type: 'payment_intent.created' };
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
constructEventStub.returns(event);
sandbox.stub(logger, 'error');
});
afterEach(() => {
stripe.events.retrieve.restore();
logger.error.restore();
it('throws if the event can\'t be validated', async () => {
const err = new Error('fail');
constructEventStub.throws(err);
await expect(stripePayments.handleWebhooks({ body: event, headers }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: `Webhook Error: ${err.message}`,
});
expect(logger.error).to.have.been.calledOnce;
const calledWith = logger.error.getCall(0).args;
expect(calledWith[0].message).to.equal('Error verifying Stripe webhook');
expect(calledWith[1]).to.eql({ err });
});
it('logs an error if an unsupported webhook event is passed', async () => {
const error = new Error(`Missing handler for Stripe webhook ${eventType}`);
await stripePayments.handleWebhooks({ requestBody: event }, stripe);
expect(logger.error).to.have.been.calledOnce;
event.type = 'account.updated';
await expect(stripePayments.handleWebhooks({ body, headers }, stripe))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
name: 'BadRequest',
message: `Missing handler for Stripe webhook ${event.type}`,
});
expect(logger.error).to.have.been.calledOnce;
const calledWith = logger.error.getCall(0).args;
expect(calledWith[0].message).to.equal(error.message);
expect(calledWith[1].event).to.equal(eventRetrieved);
expect(calledWith[0].message).to.equal('Error handling Stripe webhook');
expect(calledWith[1].event).to.eql(event);
expect(calledWith[1].err.message).to.eql(`Missing handler for Stripe webhook ${event.type}`);
});
it('retrieves and validates the event from Stripe', async () => {
await stripePayments.handleWebhooks({ requestBody: event }, stripe);
expect(stripe.events.retrieve).to.have.been.calledOnce;
expect(stripe.events.retrieve).to.have.been.calledWith(event.id);
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(stripe.webhooks.constructEvent)
.to.have.been.calledWith(body, undefined, endpointSecret);
});
});
describe('customer.subscription.deleted', () => {
const eventType = 'customer.subscription.deleted';
let event;
let constructEventStub;
beforeEach(() => {
sinon.stub(stripe.customers, 'del').resolves({});
sinon.stub(payments, 'cancelSubscription').resolves({});
event = { type: eventType };
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
constructEventStub.returns(event);
});
afterEach(() => {
stripe.customers.del.restore();
payments.cancelSubscription.restore();
beforeEach(() => {
sandbox.stub(stripe.customers, 'del').resolves({});
sandbox.stub(payments, 'cancelSubscription').resolves({});
});
it('does not do anything if event.request is null (subscription cancelled manually)', async () => {
sinon.stub(stripe.events, 'retrieve').resolves({
it('does not do anything if event.request is not null (subscription cancelled manually)', async () => {
constructEventStub.returns({
id: 123,
type: eventType,
request: 123,
request: { id: 123 },
});
await stripePayments.handleWebhooks({ requestBody: {} }, stripe);
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.events.retrieve).to.have.been.calledOnce;
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(stripe.customers.del).to.not.have.been.called;
expect(payments.cancelSubscription).to.not.have.been.called;
stripe.events.retrieve.restore();
});
describe('user subscription', () => {
it('throws an error if the user is not found', async () => {
const customerId = 456;
sinon.stub(stripe.events, 'retrieve').resolves({
constructEventStub.returns({
id: 123,
type: eventType,
data: {
@@ -90,10 +116,10 @@ describe('Stripe - Webhooks', () => {
customer: customerId,
},
},
request: null,
request: { id: null },
});
await expect(stripePayments.handleWebhooks({ requestBody: {} }, stripe))
await expect(stripePayments.handleWebhooks({ body, headers }, stripe))
.to.eventually.be.rejectedWith({
message: i18n.t('userNotFound'),
httpCode: 404,
@@ -102,8 +128,6 @@ describe('Stripe - Webhooks', () => {
expect(stripe.customers.del).to.not.have.been.called;
expect(payments.cancelSubscription).to.not.have.been.called;
stripe.events.retrieve.restore();
});
it('deletes the customer on Stripe and calls payments.cancelSubscription', async () => {
@@ -114,7 +138,7 @@ describe('Stripe - Webhooks', () => {
subscriber.purchased.plan.paymentMethod = 'Stripe';
await subscriber.save();
sinon.stub(stripe.events, 'retrieve').resolves({
constructEventStub.returns({
id: 123,
type: eventType,
data: {
@@ -125,10 +149,10 @@ describe('Stripe - Webhooks', () => {
customer: customerId,
},
},
request: null,
request: { id: null },
});
await stripePayments.handleWebhooks({ requestBody: {} }, stripe);
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.customers.del).to.have.been.calledOnce;
expect(stripe.customers.del).to.have.been.calledWith(customerId);
@@ -139,15 +163,13 @@ describe('Stripe - Webhooks', () => {
expect(cancelSubscriptionOpts.paymentMethod).to.equal('Stripe');
expect(Math.round(moment(cancelSubscriptionOpts.nextBill).diff(new Date(), 'days', true))).to.equal(3);
expect(cancelSubscriptionOpts.groupId).to.be.undefined;
stripe.events.retrieve.restore();
});
});
describe('group plan subscription', () => {
it('throws an error if the group is not found', async () => {
const customerId = 456;
sinon.stub(stripe.events, 'retrieve').resolves({
constructEventStub.returns({
id: 123,
type: eventType,
data: {
@@ -158,10 +180,10 @@ describe('Stripe - Webhooks', () => {
customer: customerId,
},
},
request: null,
request: { id: null },
});
await expect(stripePayments.handleWebhooks({ requestBody: {} }, stripe))
await expect(stripePayments.handleWebhooks({ body, headers }, stripe))
.to.eventually.be.rejectedWith({
message: i18n.t('groupNotFound'),
httpCode: 404,
@@ -170,8 +192,6 @@ describe('Stripe - Webhooks', () => {
expect(stripe.customers.del).to.not.have.been.called;
expect(payments.cancelSubscription).to.not.have.been.called;
stripe.events.retrieve.restore();
});
it('throws an error if the group leader is not found', async () => {
@@ -187,7 +207,7 @@ describe('Stripe - Webhooks', () => {
subscriber.purchased.plan.paymentMethod = 'Stripe';
await subscriber.save();
sinon.stub(stripe.events, 'retrieve').resolves({
constructEventStub.returns({
id: 123,
type: eventType,
data: {
@@ -198,10 +218,10 @@ describe('Stripe - Webhooks', () => {
customer: customerId,
},
},
request: null,
request: { id: null },
});
await expect(stripePayments.handleWebhooks({ requestBody: {} }, stripe))
await expect(stripePayments.handleWebhooks({ body, headers }, stripe))
.to.eventually.be.rejectedWith({
message: i18n.t('userNotFound'),
httpCode: 404,
@@ -210,8 +230,6 @@ describe('Stripe - Webhooks', () => {
expect(stripe.customers.del).to.not.have.been.called;
expect(payments.cancelSubscription).to.not.have.been.called;
stripe.events.retrieve.restore();
});
it('deletes the customer on Stripe and calls payments.cancelSubscription', async () => {
@@ -230,7 +248,7 @@ describe('Stripe - Webhooks', () => {
subscriber.purchased.plan.paymentMethod = 'Stripe';
await subscriber.save();
sinon.stub(stripe.events, 'retrieve').resolves({
constructEventStub.returns({
id: 123,
type: eventType,
data: {
@@ -241,10 +259,10 @@ describe('Stripe - Webhooks', () => {
customer: customerId,
},
},
request: null,
request: { id: null },
});
await stripePayments.handleWebhooks({ requestBody: {} }, stripe);
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.customers.del).to.have.been.calledOnce;
expect(stripe.customers.del).to.have.been.calledWith(customerId);
@@ -255,9 +273,65 @@ describe('Stripe - Webhooks', () => {
expect(cancelSubscriptionOpts.paymentMethod).to.equal('Stripe');
expect(Math.round(moment(cancelSubscriptionOpts.nextBill).diff(new Date(), 'days', true))).to.equal(3);
expect(cancelSubscriptionOpts.groupId).to.equal(subscriber._id);
stripe.events.retrieve.restore();
});
});
});
describe('checkout.session.completed', () => {
const eventType = 'checkout.session.completed';
let event;
let constructEventStub;
const session = {};
beforeEach(() => {
session.metadata = {};
event = { type: eventType, data: { object: session } };
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
constructEventStub.returns(event);
sandbox.stub(oneTimePayments, 'applyGemPayment').resolves({});
sandbox.stub(subscriptions, 'applySubscription').resolves({});
sandbox.stub(subscriptions, 'handlePaymentMethodChange').resolves({});
});
it('handles changing an user sub', async () => {
session.metadata.type = 'edit-card-user';
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(subscriptions.handlePaymentMethodChange).to.have.been.calledOnce;
expect(subscriptions.handlePaymentMethodChange).to.have.been.calledWith(session);
});
it('handles changing a group sub', async () => {
session.metadata.type = 'edit-card-group';
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(subscriptions.handlePaymentMethodChange).to.have.been.calledOnce;
expect(subscriptions.handlePaymentMethodChange).to.have.been.calledWith(session);
});
it('applies a subscription', async () => {
session.metadata.type = 'subscription';
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(subscriptions.applySubscription).to.have.been.calledOnce;
expect(subscriptions.applySubscription).to.have.been.calledWith(session);
});
it('handles a one time payment', async () => {
session.metadata.type = 'something else';
await stripePayments.handleWebhooks({ body, headers }, stripe);
expect(stripe.webhooks.constructEvent).to.have.been.calledOnce;
expect(oneTimePayments.applyGemPayment).to.have.been.calledOnce;
expect(oneTimePayments.applyGemPayment).to.have.been.calledWith(session);
});
});
});

View File

@@ -0,0 +1,45 @@
import {
generateUser,
} from '../../../../../helpers/api-integration/v3';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
import common from '../../../../../../website/common';
describe('payments - stripe - #createCheckoutSession', () => {
const endpoint = '/stripe/checkout-session';
let user; const groupId = 'groupId';
const gift = {}; const subKey = 'basic_3mo';
const gemsBlock = '21gems'; const coupon = 'coupon';
let stripeCreateCheckoutSessionStub; const sessionId = 'sessionId';
beforeEach(async () => {
user = await generateUser();
stripeCreateCheckoutSessionStub = sinon
.stub(stripePayments, 'createCheckoutSession')
.resolves({ id: sessionId });
});
afterEach(() => {
stripePayments.createCheckoutSession.restore();
});
it('works', async () => {
const res = await user.post(endpoint, {
groupId,
gift,
sub: subKey,
gemsBlock,
coupon,
});
expect(res.sessionId).to.equal(sessionId);
expect(stripeCreateCheckoutSessionStub).to.be.calledOnce;
expect(stripeCreateCheckoutSessionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeCreateCheckoutSessionStub.args[0][0].groupId).to.eql(groupId);
expect(stripeCreateCheckoutSessionStub.args[0][0].gift).to.eql(gift);
expect(stripeCreateCheckoutSessionStub.args[0][0].sub)
.to.eql(common.content.subscriptionBlocks[subKey]);
expect(stripeCreateCheckoutSessionStub.args[0][0].gemsBlock).to.eql(gemsBlock);
expect(stripeCreateCheckoutSessionStub.args[0][0].coupon).to.eql(coupon);
});
});

View File

@@ -1,79 +0,0 @@
import {
generateUser,
generateGroup,
} from '../../../../../helpers/api-integration/v3';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
describe('payments - stripe - #checkout', () => {
const endpoint = '/stripe/checkout';
let user; let
group;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.post(
`${endpoint}?gemsBlock=4gems`,
{ id: 123 },
)).to.eventually.be.rejected.and.include({
code: 401,
error: 'Error',
// message: 'Invalid API Key provided: aaaabbbb********************1111',
});
});
describe('success', () => {
let stripeCheckoutSubscriptionStub;
beforeEach(async () => {
stripeCheckoutSubscriptionStub = sinon.stub(stripePayments, 'checkout').resolves({});
});
afterEach(() => {
stripePayments.checkout.restore();
});
it('creates a user subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
balance: 2,
});
await user.post(endpoint);
expect(stripeCheckoutSubscriptionStub).to.be.calledOnce;
expect(stripeCheckoutSubscriptionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeCheckoutSubscriptionStub.args[0][0].groupId).to.eql(undefined);
});
it('creates a group subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
balance: 2,
});
group = await generateGroup(user, {
name: 'test group',
type: 'guild',
privacy: 'public',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
});
await user.post(`${endpoint}?groupId=${group._id}`);
expect(stripeCheckoutSubscriptionStub).to.be.calledOnce;
expect(stripeCheckoutSubscriptionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeCheckoutSubscriptionStub.args[0][0].groupId).to.eql(group._id);
});
});
});

View File

@@ -1,79 +1,31 @@
import {
generateUser,
generateGroup,
translate as t,
} from '../../../../../helpers/api-integration/v3';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
describe('payments - stripe - #subscribeEdit', () => {
const endpoint = '/stripe/subscribe/edit';
let user; let
group;
let user; const groupId = 'groupId';
let stripeEditSubscriptionStub;
const sessionId = 'sessionId';
beforeEach(async () => {
user = await generateUser();
stripeEditSubscriptionStub = sinon
.stub(stripePayments, 'createEditCardCheckoutSession')
.resolves({ id: sessionId });
});
it('verifies credentials', async () => {
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingSubscription'),
});
afterEach(() => {
stripePayments.createEditCardCheckoutSession.restore();
});
describe('success', () => {
let stripeEditSubscriptionStub;
it('works', async () => {
const res = await user.post(endpoint, { groupId });
expect(res.sessionId).to.equal(sessionId);
beforeEach(async () => {
stripeEditSubscriptionStub = sinon.stub(stripePayments, 'editSubscription').resolves({});
});
afterEach(() => {
stripePayments.editSubscription.restore();
});
it('cancels a user subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
balance: 2,
});
await user.post(endpoint);
expect(stripeEditSubscriptionStub).to.be.calledOnce;
expect(stripeEditSubscriptionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeEditSubscriptionStub.args[0][0].groupId).to.eql(undefined);
});
it('cancels a group subscription', async () => {
user = await generateUser({
'profile.name': 'sender',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
balance: 2,
});
group = await generateGroup(user, {
name: 'test group',
type: 'guild',
privacy: 'public',
'purchased.plan.customerId': 'customer-id',
'purchased.plan.planId': 'basic_3mo',
'purchased.plan.lastBillingDate': new Date(),
});
await user.post(endpoint, {
groupId: group._id,
});
expect(stripeEditSubscriptionStub).to.be.calledOnce;
expect(stripeEditSubscriptionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeEditSubscriptionStub.args[0][0].groupId).to.eql(group._id);
});
expect(stripeEditSubscriptionStub).to.be.calledOnce;
expect(stripeEditSubscriptionStub.args[0][0].user._id).to.eql(user._id);
expect(stripeEditSubscriptionStub.args[0][0].groupId).to.eql(groupId);
});
});

View File

@@ -0,0 +1,30 @@
import {
generateUser,
} from '../../../../../helpers/api-integration/v3';
import stripePayments from '../../../../../../website/server/libs/payments/stripe';
describe('payments - stripe - #handleWebhooks', () => {
const endpoint = '/stripe/webhooks';
let user; const body = '{"key": "val"}';
let stripeHandleWebhooksStub;
beforeEach(async () => {
user = await generateUser();
stripeHandleWebhooksStub = sinon
.stub(stripePayments, 'handleWebhooks')
.resolves({});
});
afterEach(() => {
stripePayments.handleWebhooks.restore();
});
it('works', async () => {
const res = await user.post(endpoint, body);
expect(res).to.eql({});
expect(stripeHandleWebhooksStub).to.be.calledOnce;
expect(stripeHandleWebhooksStub.args[0][0].body).to.exist;
expect(stripeHandleWebhooksStub.args[0][0].headers).to.exist;
});
});

View File

@@ -8,9 +8,14 @@ import {
describe('POST /tasks/user', () => {
let user;
let tzoffset;
before(async () => {
tzoffset = new Date().getTimezoneOffset();
});
beforeEach(async () => {
user = await generateUser();
user = await generateUser({ 'preferences.timezoneOffset': tzoffset });
});
context('validates params', async () => {
@@ -220,6 +225,18 @@ describe('POST /tasks/user', () => {
});
});
it('errors if todo due date supplied is an invalid date', async () => {
await expect(user.post('/tasks/user', {
type: 'todo',
text: 'todo text',
date: 'invalid date',
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'todo validation failed',
});
});
context('sending task activity webhooks', () => {
before(async () => {
await server.start();
@@ -532,7 +549,7 @@ describe('POST /tasks/user', () => {
expect(task.everyX).to.eql(5);
expect(task.daysOfMonth).to.eql([15]);
expect(task.weeksOfMonth).to.eql([3]);
expect(new Date(task.startDate)).to.eql(now);
expect(new Date(task.startDate)).to.eql(new Date(now.setHours(0, 0, 0, 0)));
expect(task.isDue).to.be.true;
expect(task.nextDue.length).to.eql(6);
});

View File

@@ -10,9 +10,14 @@ import {
describe('PUT /tasks/:id', () => {
let user;
let tzoffset;
before(async () => {
tzoffset = (new Date()).getTimezoneOffset();
});
beforeEach(async () => {
user = await generateUser();
user = await generateUser({ 'preferences.timezoneOffset': tzoffset });
});
context('validates params', () => {
@@ -503,7 +508,8 @@ describe('PUT /tasks/:id', () => {
let monthly;
beforeEach(async () => {
const date1 = moment.utc('2020-07-01').toDate();
// using date literals is discouraged here, daylight savings will break everything
const date1 = moment().toDate();
monthly = await user.post('/tasks/user', {
text: 'test monthly',
type: 'daily',
@@ -514,7 +520,7 @@ describe('PUT /tasks/:id', () => {
});
it('updates days of month when start date updated', async () => {
const date2 = moment.utc('2020-07-01').toDate();
const date2 = moment().add(6, 'months').toDate();
const savedMonthly = await user.put(`/tasks/${monthly._id}`, {
startDate: date2,
});
@@ -523,18 +529,30 @@ describe('PUT /tasks/:id', () => {
});
it('updates next due when start date updated', async () => {
const date2 = moment.utc('2022-07-01').toDate();
const date2 = moment().add(6, 'months').toDate();
const savedMonthly = await user.put(`/tasks/${monthly._id}`, {
startDate: date2,
});
expect(savedMonthly.nextDue.length).to.eql(6);
expect(moment(savedMonthly.nextDue[0]).toDate()).to.eql(moment.utc('2022-08-01').toDate());
expect(moment(savedMonthly.nextDue[1]).toDate()).to.eql(moment.utc('2022-09-01').toDate());
expect(moment(savedMonthly.nextDue[2]).toDate()).to.eql(moment.utc('2022-10-01').toDate());
expect(moment(savedMonthly.nextDue[3]).toDate()).to.eql(moment.utc('2022-11-01').toDate());
expect(moment(savedMonthly.nextDue[4]).toDate()).to.eql(moment.utc('2022-12-01').toDate());
expect(moment(savedMonthly.nextDue[5]).toDate()).to.eql(moment.utc('2023-01-01').toDate());
expect(moment(savedMonthly.nextDue[0]).toDate()).to.eql(
moment(date2).add(1, 'months').startOf('day').toDate(),
);
expect(moment(savedMonthly.nextDue[1]).toDate()).to.eql(
moment(date2).add(2, 'months').startOf('day').toDate(),
);
expect(moment(savedMonthly.nextDue[2]).toDate()).to.eql(
moment(date2).add(3, 'months').startOf('day').toDate(),
);
expect(moment(savedMonthly.nextDue[3]).toDate()).to.eql(
moment(date2).add(4, 'months').startOf('day').toDate(),
);
expect(moment(savedMonthly.nextDue[4]).toDate()).to.eql(
moment(date2).add(5, 'months').startOf('day').toDate(),
);
expect(moment(savedMonthly.nextDue[5]).toDate()).to.eql(
moment(date2).add(6, 'months').startOf('day').toDate(),
);
});
});

View File

@@ -11,13 +11,18 @@ describe('POST /tasks/challenge/:challengeId', () => {
let user;
let guild;
let challenge;
let tzoffset;
function findUserChallengeTask (memberTask) {
return memberTask.challenge.id === challenge._id;
}
before(async () => {
tzoffset = new Date().getTimezoneOffset();
});
beforeEach(async () => {
user = await generateUser({ balance: 1 });
user = await generateUser({ balance: 1, 'preferences.timezoneOffset': tzoffset });
guild = await generateGroup(user);
challenge = await generateChallenge(user, guild);
await user.post(`/challenges/${challenge._id}/join`);
@@ -165,7 +170,7 @@ describe('POST /tasks/challenge/:challengeId', () => {
expect(task.type).to.eql('daily');
expect(task.frequency).to.eql('daily');
expect(task.everyX).to.eql(5);
expect(new Date(task.startDate)).to.eql(now);
expect(new Date(task.startDate)).to.eql(new Date(now.setHours(0, 0, 0, 0)));
expect(userChallengeTask.notes).to.eql(task.notes);
});

View File

@@ -12,7 +12,7 @@ describe('PUT /tasks/:id', () => {
let challenge;
before(async () => {
user = await generateUser();
user = await generateUser({ 'preferences.timezoneOffset': new Date().getTimezoneOffset() });
guild = await generateGroup(user);
challenge = await generateChallenge(user, guild);
await user.post(`/challenges/${challenge._id}/join`);

View File

@@ -8,12 +8,18 @@ import {
describe('POST /tasks/group/:groupid', () => {
let user; let guild; let
manager;
let tzoffset;
const groupName = 'Test Public Guild';
const groupType = 'guild';
before(async () => {
tzoffset = new Date().getTimezoneOffset();
});
beforeEach(async () => {
user = await generateUser({ balance: 1 });
// user = await generateUser({ balance: 1, 'preferences.timezoneOffset': tzoffset });
const { group, groupLeader, members } = await createAndPopulateGroup({
leaderDetails: { balance: 10, 'preferences.timezoneOffset': tzoffset },
groupDetails: {
name: groupName,
type: groupType,
@@ -128,7 +134,7 @@ describe('POST /tasks/group/:groupid', () => {
expect(task.type).to.eql('daily');
expect(task.frequency).to.eql('daily');
expect(task.everyX).to.eql(5);
expect(new Date(task.startDate)).to.eql(now);
expect(new Date(task.startDate)).to.eql(new Date(now.setHours(0, 0, 0, 0)));
});
it('allows a manager to add a group task', async () => {

View File

@@ -3,15 +3,15 @@ import {
} from '../../../../helpers/api-integration/v3';
import getOfficialPinnedItems from '../../../../../website/common/script/libs/getOfficialPinnedItems';
import content from '../../../../../website/common/script/content';
describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
let user;
let officialPinnedItems;
let officialPinnedItemPaths;
beforeEach(async () => {
user = await generateUser();
officialPinnedItems = getOfficialPinnedItems(user);
const officialPinnedItems = getOfficialPinnedItems(user);
officialPinnedItemPaths = [];
// officialPinnedItems are returned in { type: ..., path:... } format
@@ -83,7 +83,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
expect(res).to.eql(expectedResponse);
});
it('adjusts the order of pinned items with order mismatch', async () => {
it('adjusts the order of pinned items with order mismatch - existing item in order', async () => {
const testPinnedItems = [
{ type: 'card', path: 'cardTypes.thankyou' },
{ type: 'card', path: 'cardTypes.greeting' },
@@ -125,6 +125,95 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
expect(res).to.eql(expectedResponse);
});
it('adjusts the order of pinned items with order mismatch - not existing in order', async () => {
const testPinnedItems = [
{ type: 'card', path: 'cardTypes.thankyou' },
{ type: 'card', path: 'cardTypes.greeting' },
{ type: 'potion', path: 'potion' },
{ type: 'armoire', path: 'armoire' },
];
const testPinnedItemsOrder = [
'armoire',
'potion',
];
await user.update({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
await user.sync();
await user.post('/user/move-pinned-item/cardTypes.greeting/move/to/2');
await user.sync();
// The basic test
expect(user.pinnedItemsOrder[2]).to.equal('cardTypes.greeting');
// potion is now the last item because the 2 unacounted for cards show up
// at the beginning of the order
expect(user.pinnedItemsOrder[user.pinnedItemsOrder.length - 1]).to.equal('potion');
});
it('adjusts the order of official pinned items with order mismatch - not existing in order', async () => {
const testPinnedItems = [
{ type: 'card', path: 'cardTypes.thankyou' },
{ type: 'card', path: 'cardTypes.greeting' },
{ type: 'potion', path: 'potion' },
];
const testPinnedItemsOrder = [
'potion',
];
const { officialPinnedItems } = content;
// add item to pinned
officialPinnedItems.push({ type: 'armoire', path: 'armoire' });
await user.update({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
await user.sync();
await user.post('/user/move-pinned-item/armoire/move/to/2');
await user.sync();
// The basic test
expect(user.pinnedItemsOrder[2]).to.equal('armoire');
// potion is now the last item because the 2 unacounted for cards show up
// at the beginning of the order
expect(user.pinnedItemsOrder[user.pinnedItemsOrder.length - 1]).to.equal('potion');
});
it('adjusts the order of pinned items with order mismatch - not existing - out of length', async () => {
const testPinnedItems = [
{ type: 'card', path: 'cardTypes.thankyou' },
{ type: 'card', path: 'cardTypes.greeting' },
{ type: 'potion', path: 'potion' },
{ type: 'armoire', path: 'armoire' },
];
const testPinnedItemsOrder = [
'armoire',
'potion',
];
await user.update({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
await user.sync();
await user.post('/user/move-pinned-item/cardTypes.greeting/move/to/33');
await user.sync();
// since the target was out of bounce it added it to the last item
expect(user.pinnedItemsOrder[user.pinnedItemsOrder.length - 1]).to.equal('cardTypes.greeting');
});
it('cannot move pinned item that you do not have pinned', async () => {
const testPinnedItems = [
{ type: 'potion', path: 'potion' },

View File

@@ -169,7 +169,6 @@ describe('shared.ops.hatch', () => {
it('awards Back to Basics achievement', () => {
user.items.pets = {
'Wolf-Base': 5,
'TigerCub-Base': 5,
'PandaCub-Base': 10,
'LionCub-Base': 5,
@@ -180,14 +179,13 @@ describe('shared.ops.hatch', () => {
'BearCub-Base': 5,
};
user.items.eggs = { Wolf: 1 };
user.items.hatchingPotions = { Spooky: 1 };
hatch(user, { params: { egg: 'Wolf', hatchingPotion: 'Spooky' } });
user.items.hatchingPotions = { Base: 1 };
hatch(user, { params: { egg: 'Wolf', hatchingPotion: 'Base' } });
expect(user.achievements.backToBasics).to.eql(true);
});
it('awards Dust Devil achievement', () => {
user.items.pets = {
'Wolf-Desert': 5,
'TigerCub-Desert': 5,
'PandaCub-Desert': 10,
'LionCub-Desert': 5,
@@ -198,8 +196,8 @@ describe('shared.ops.hatch', () => {
'BearCub-Desert': 5,
};
user.items.eggs = { Wolf: 1 };
user.items.hatchingPotions = { Spooky: 1 };
hatch(user, { params: { egg: 'Wolf', hatchingPotion: 'Spooky' } });
user.items.hatchingPotions = { Desert: 1 };
hatch(user, { params: { egg: 'Wolf', hatchingPotion: 'Desert' } });
expect(user.achievements.dustDevil).to.eql(true);
});

File diff suppressed because it is too large Load Diff

View File

@@ -13,53 +13,53 @@
"storybook:serve": "vue-cli-service storybook:serve -p 6006 -c config/storybook"
},
"dependencies": {
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/addon-links": "^5.3.19",
"@storybook/addon-actions": "^6.1.15",
"@storybook/addon-knobs": "^6.1.15",
"@storybook/addon-links": "^6.1.15",
"@storybook/addon-notes": "^5.3.21",
"@storybook/vue": "^5.3.19",
"@vue/cli-plugin-babel": "^4.5.9",
"@vue/cli-plugin-eslint": "^4.5.9",
"@vue/cli-plugin-router": "^4.5.9",
"@vue/cli-plugin-unit-mocha": "^4.5.9",
"@vue/cli-service": "^4.5.9",
"@storybook/vue": "^6.1.15",
"@vue/cli-plugin-babel": "^4.5.11",
"@vue/cli-plugin-eslint": "^4.5.11",
"@vue/cli-plugin-router": "^4.5.11",
"@vue/cli-plugin-unit-mocha": "^4.5.11",
"@vue/cli-service": "^4.5.11",
"@vue/test-utils": "1.0.0-beta.29",
"amplitude-js": "^7.3.3",
"axios": "^0.21.0",
"amplitude-js": "^7.4.1",
"axios": "^0.21.1",
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.1.0",
"bootstrap": "^4.5.3",
"bootstrap-vue": "^2.19.0",
"bootstrap-vue": "^2.21.2",
"chai": "^4.1.2",
"core-js": "^3.8.0",
"core-js": "^3.8.3",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
"eslint-plugin-mocha": "^5.3.0",
"eslint-plugin-vue": "^6.2.2",
"habitica-markdown": "^3.0.0",
"hellojs": "^1.18.6",
"inspectpack": "^4.5.2",
"inspectpack": "^4.6.1",
"intro.js": "^2.9.3",
"jquery": "^3.5.1",
"lodash": "^4.17.20",
"moment": "^2.29.1",
"nconf": "^0.11.0",
"sass": "^1.29.0",
"nconf": "^0.11.1",
"sass": "^1.32.5",
"sass-loader": "^8.0.2",
"smartbanner.js": "^1.16.0",
"svg-inline-loader": "^0.8.2",
"svg-url-loader": "^6.0.0",
"svgo": "^1.3.2",
"svgo-loader": "^2.2.1",
"uuid": "^8.3.1",
"validator": "^13.1.17",
"uuid": "^8.3.2",
"validator": "^13.5.2",
"vue": "^2.6.12",
"vue-cli-plugin-storybook": "^0.6.1",
"vue-cli-plugin-storybook": "^2.0.0",
"vue-mugen-scroll": "^0.2.6",
"vue-router": "^3.4.9",
"vue-template-compiler": "^2.6.12",
"vuedraggable": "^2.24.3",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0",
"webpack": "^4.44.2"
"webpack": "^4.46.0"
}
}

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Some files were not shown because too many files have changed in this diff Show More