Compare commits

..

227 Commits

Author SHA1 Message Date
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
Sabe Jones 5daf96bbf5 4.173.0 2020-12-08 11:13:03 -06:00
Alys 62498ab646 remove links to Moderator Contact Form
This is a temporary measure until we can get the form working again.

This has NOT been approved by any of Habitica's staff.
It's just being proposed for consideration.

The changes are:

- remove link from Help menu
- replace link in Contacts page with mailto admin@habitica.com without changing the visible text of the link
- replace link in Tavern sidebar with mailto admin@habitica.com using the visible text from the Contacts page
2020-12-07 15:48:45 -06:00
Sabe Jones cf435ad007 chore(sprites): compile 2020-12-07 15:40:32 -06:00
Sabe Jones 55f4b8ae87 feat(content): Armoire items and backgrounds for Dec 2020 2020-12-07 15:40:24 -06:00
Sabe Jones 8434d727bd fix(Docker): use new Node base image 2020-12-04 13:18:45 -06:00
Sabe Jones c055d43895 4.172.1 2020-12-04 13:12:39 -06:00
Melior f0123a1571 Merge branch 'origin/develop' into Weblate. 2020-11-30 22:03:24 +01:00
Melior e4e200c32c Translated using Weblate (English (Pirate))
Currently translated at 100.0% (54 of 54 strings)

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

Translated using Weblate (English)

Currently translated at 14.4% (16 of 111 strings)

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

Translated using Weblate (English)

Currently translated at 20.4% (37 of 181 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 91.3% (95 of 104 strings)

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

Translated using Weblate (English)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Japanese)

Currently translated at 94.1% (2065 of 2193 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 (Russian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 75.8% (138 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% (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 90.6% (1988 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 80.3% (45 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 97.9% (709 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% (102 of 102 strings)

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

Translated using Weblate (Korean)

Currently translated at 15.8% (52 of 328 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 82.1% (46 of 56 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.7% (628 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.3% (2090 of 2193 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% (102 of 102 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.9% (2060 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 90.6% (1987 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.3% (705 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 93.2% (675 of 724 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.7% (2056 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 92.8% (672 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 95.0% (2084 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.6% (2053 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.3% (358 of 364 strings)

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

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 (Chinese (Simplified))

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Turkish)

Currently translated at 79.1% (452 of 571 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 83.9% (47 of 56 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 78.5% (44 of 56 strings)

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

Translated using Weblate (Galician)

Currently translated at 62.5% (35 of 56 strings)

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

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 (Vietnamese)

Currently translated at 92.8% (169 of 182 strings)

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

Translated using Weblate (Galician)

Currently translated at 64.8% (118 of 182 strings)

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

Translated using Weblate (Persian)

Currently translated at 64.8% (118 of 182 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 84.6% (11 of 13 strings)

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

Translated using Weblate (Croatian)

Currently translated at 84.6% (11 of 13 strings)

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

Translated using Weblate (Greek)

Currently translated at 84.6% (11 of 13 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Arabic)

Currently translated at 75.0% (6 of 8 strings)

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

Translated using Weblate (English)

Currently translated at 39.4% (41 of 104 strings)

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

Translated using Weblate (Latvian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Lingala)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Latin)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Hindi)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Hawaiian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Frisian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Filipino)

Currently translated at 94.5% (346 of 366 strings)

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

Translated using Weblate (Finnish)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Bosnian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Bengali)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Hindi)

Currently translated at 99.1% (122 of 123 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Klingon)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Tamil)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Malay)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Latin)

Currently translated at 93.3% (168 of 180 strings)

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

Translated using Weblate (Lojban)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Irish)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Slovak)

Currently translated at 90.9% (101 of 111 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 89.1% (99 of 111 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Swedish)

Currently translated at 75.0% (6 of 8 strings)

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

Translated using Weblate (Romanian)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Hebrew)

Currently translated at 87.4% (320 of 366 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 94.8% (347 of 366 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 97.7% (177 of 181 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 96.1% (174 of 181 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 91.0% (51 of 56 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 64.2% (36 of 56 strings)

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

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)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Dutch)

Currently translated at 85.7% (48 of 56 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Hebrew)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Danish)

Currently translated at 62.5% (35 of 56 strings)

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

Translated using Weblate (Czech)

Currently translated at 78.5% (44 of 56 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Czech)

Currently translated at 88.4% (92 of 104 strings)

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

Translated using Weblate (Macedonian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Kurdish)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Galician)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Irish)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Persian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Estonian)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Greek)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Catalan)

Currently translated at 89.6% (328 of 366 strings)

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

Translated using Weblate (Belarusian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 87.1% (319 of 366 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 87.1% (319 of 366 strings)

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

Translated using Weblate (Mongolian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Malayalam)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Korean)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Greek)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 86.0% (623 of 724 strings)

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

Translated using Weblate (Korean)

Currently translated at 86.0% (623 of 724 strings)

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

Translated using Weblate (Arabic)

Currently translated at 86.1% (624 of 724 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 89.8% (329 of 366 strings)

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

Translated using Weblate (Vietnamese)

Currently translated at 98.6% (361 of 366 strings)

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

Translated using Weblate (Urdu (Pakistan))

Currently translated at 92.0% (337 of 366 strings)

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

Translated using Weblate (Klingon)

Currently translated at 91.8% (336 of 366 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 89.6% (328 of 366 strings)

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

Translated using Weblate (Thai)

Currently translated at 89.6% (328 of 366 strings)

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

Translated using Weblate (Tamil)

Currently translated at 92.8% (340 of 366 strings)

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

Translated using Weblate (Swahili)

Currently translated at 92.3% (338 of 366 strings)

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

Translated using Weblate (Sundanese)

Currently translated at 92.3% (338 of 366 strings)

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

Translated using Weblate (Slovenian)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Sinhala)

Currently translated at 92.3% (338 of 366 strings)

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

Translated using Weblate (Scots)

Currently translated at 92.3% (338 of 366 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 99.4% (364 of 366 strings)

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

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Malay)

Currently translated at 92.0% (337 of 366 strings)

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

Translated using Weblate (Marathi)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Korean)

Currently translated at 90.7% (332 of 366 strings)

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

Translated using Weblate (Javanese)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Lojban)

Currently translated at 89.8% (329 of 366 strings)

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

Translated using Weblate (Esperanto)

Currently translated at 89.6% (328 of 366 strings)

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

Translated using Weblate (English)

Currently translated at 91.5% (335 of 366 strings)

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

Translated using Weblate (Arabic)

Currently translated at 91.8% (336 of 366 strings)

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

Translated using Weblate (Afrikaans)

Currently translated at 90.4% (331 of 366 strings)

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

Translated using Weblate (Acholi)

Currently translated at 90.1% (330 of 366 strings)

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

Translated using Weblate (Turkish)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 87.1% (319 of 366 strings)

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

Translated using Weblate (Turkish)

Currently translated at 92.0% (337 of 366 strings)

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

Translated using Weblate (Serbian)

Currently translated at 87.4% (320 of 366 strings)

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

Translated using Weblate (Slovak)

Currently translated at 87.4% (320 of 366 strings)

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

Translated using Weblate (Romanian)

Currently translated at 96.1% (352 of 366 strings)

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

Translated using Weblate (Dutch)

Currently translated at 95.0% (348 of 366 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 90.2% (1979 of 2193 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 64.2% (36 of 56 strings)

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

Translated using Weblate (Swedish)

Currently translated at 86.0% (623 of 724 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 84.6% (613 of 724 strings)

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

Translated using Weblate (Dutch)

Currently translated at 95.1% (689 of 724 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 78.5% (569 of 724 strings)

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

Translated using Weblate (Czech)

Currently translated at 83.9% (608 of 724 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 87.5% (7 of 8 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 89.1% (1955 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 88.6% (1944 of 2193 strings)

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

Translated using Weblate (Swahili)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Persian)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Afrikaans)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Icelandic)

Currently translated at 8.6% (9 of 104 strings)

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

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 (Korean)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Basque)

Currently translated at 6.5% (8 of 123 strings)

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

Translated using Weblate (Persian)

Currently translated at 91.6% (165 of 180 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 88.0% (118 of 134 strings)

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

Translated using Weblate (Swedish)

Currently translated at 79.6% (145 of 182 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 96.4% (54 of 56 strings)

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

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 (Turkish)

Currently translated at 78.1% (1714 of 2193 strings)

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

Translated using Weblate (Dutch)

Currently translated at 97.6% (2141 of 2193 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 77.7% (1704 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 87.9% (1929 of 2193 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 97.7% (177 of 181 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 98.8% (179 of 181 strings)

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

Translated using Weblate (Serbian)

Currently translated at 15.3% (16 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.0% (2084 of 2193 strings)

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

Translated using Weblate (Korean)

Currently translated at 69.2% (72 of 104 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.5% (2052 of 2193 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/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 (Turkish)

Currently translated at 78.1% (1714 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 86.6% (1901 of 2193 strings)

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

Translated using Weblate (Turkish)

Currently translated at 99.0% (101 of 102 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English)

Currently translated at 98.3% (359 of 365 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% (56 of 56 strings)

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

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 (English (Pirate))

Currently translated at 91.9% (666 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 99.1% (122 of 123 strings)

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

Translated using Weblate (English)

Currently translated at 98.3% (359 of 365 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.3% (2048 of 2193 strings)

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

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% (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 98.0% (357 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 84.4% (1851 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 91.2% (661 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% (187 of 187 strings)

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

Translated using Weblate (English)

Currently translated at 13.5% (15 of 111 strings)

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

Translated using Weblate (Latin)

Currently translated at 99.4% (186 of 187 strings)

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

Translated using Weblate (Catalan)

Currently translated at 97.0% (99 of 102 strings)

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

Translated using Weblate (Latvian)

Currently translated at 84.6% (11 of 13 strings)

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

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 (Latin)

Currently translated at 88.4% (92 of 104 strings)

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

Translated using Weblate (English)

Currently translated at 39.4% (41 of 104 strings)

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

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 (English)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Korean)

Currently translated at 94.0% (191 of 203 strings)

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

Translated using Weblate (Tagalog)

Currently translated at 77.5% (1701 of 2193 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 77.6% (1703 of 2193 strings)

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

Translated using Weblate (Lithuanian)

Currently translated at 77.5% (1701 of 2193 strings)

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

Translated using Weblate (Malay)

Currently translated at 83.8% (306 of 365 strings)

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

Translated using Weblate (English)

Currently translated at 98.3% (359 of 365 strings)

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

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 (Spanish (Latin America))

Currently translated at 86.0% (623 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% (2084 of 2193 strings)

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

Translated using Weblate (Czech)

Currently translated at 97.8% (182 of 186 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Swedish)

Currently translated at 81.9% (1797 of 2193 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 79.2% (1739 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 77.6% (1703 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.0% (1932 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 88.0% (1932 of 2193 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (187 of 187 strings)

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

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 (German)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Dutch)

Currently translated at 99.4% (179 of 180 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 83.9% (1840 of 2193 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% (104 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.9% (1928 of 2193 strings)

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

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/

Translated using Weblate (Spanish)

Currently translated at 97.1% (101 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 96.1% (100 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 95.1% (99 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 90.3% (94 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 89.4% (93 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 97.1% (101 of 104 strings)

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

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 (English (Pirate))

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

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1927 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 89.7% (167 of 186 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 89.7% (167 of 186 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% (571 of 571 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.0% (2084 of 2193 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% (104 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 96.8% (553 of 571 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.0% (103 of 104 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (13 of 13 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (56 of 56 strings)

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

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 (English (Pirate))

Currently translated at 83.7% (1836 of 2193 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English)

Currently translated at 0.5% (3 of 571 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 83.6% (1834 of 2193 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% (724 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.9% (185 of 187 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.0% (102 of 104 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (German)

Currently translated at 99.0% (103 of 104 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 70.1% (73 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 93.2% (125 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% (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 83.5% (1832 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 76.7% (43 of 56 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.5% (721 of 724 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (104 of 104 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 83.2% (1826 of 2193 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en@pirate/
2020-11-30 22:03:01 +01:00
Sabe Jones 637048af0b Merge branch 'release' into develop 2020-11-30 15:01:07 -06:00
Sabe Jones d6be92b346 4.172.0 2020-11-30 14:59:50 -06:00
Sabe Jones 2ed15f58e9 chore(sprites): compile 2020-11-30 14:59:36 -06:00
Sabe Jones 42de4397a1 feat(content): December Mystery Items 2020-11-30 14:59:30 -06:00
RaitheOfDureya 661c7b23a1 Removed duplicates I18N strings (related to issue #9210) (#12679)
* Removed duplicated string from `generic.json`

* Removed duplicated string from `npc.json`
2020-11-30 21:44:01 +01:00
jbusa22 f077e40c4c use or clause for display name and username search (#12820)
* use or clause for display name and username search

* update styling

* More style fix

* update comment and regex
2020-11-30 20:05:58 +01:00
Denys Dorokhov 3ce182d0dc Feature/enhance get memebers for a challenge fixes #12481 (#12716)
* refactor(api-members): separate handler for the GET /challenges/:challengeId/members route

* refactor(api-members): challenges-related code removed from _getMembersForItem handler function

* feat(api-members): added support to the new includeTasks query parameter for the GET /challenges/:challengeId/members route

* fix(api-members): adjustments to the GET /challenges/:challengeId/members route

* fix(api-members): merge of _getMembersTasksFromChallenge and additional check for a test suite

* refactor(api-members): includeAllMembers query parameter got removed from the GET /challenges/:challengeId/members route

* GET-challenges_challengeId_members.test.js: use _id

* members.js: use _id instead of id

* use id instead of _id

* _id instead of id

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-11-30 20:04:17 +01:00
Matteo Pagliazzi 6a658c45b5 Upgrade some deps: helmet, slack, amplitude and short-uuid (#12817)
* upgrade helmet to version 4

* deps(short-uuid): upgrade to version 4, closes #12573

* deps(slack): upgrade to version 4

* deps(slack): upgrade to version 5, closes #11442

* deps(amplitude): upgrade to latest version use api v2

* fix tests

* slack tests: return promise

* refactor slack setup for tests

* fix slack unit tests
2020-11-30 20:03:04 +01:00
Matteo Pagliazzi 7057797ed3 Node 14 (#12715)
* node 14

* restore package-lock.json from develop

* remove old heroku buildpack
2020-11-30 20:02:06 +01:00
negue d3eb9fe230 Apply Dropdown Styles to various parts (#12814)
* membersModal use the new select component instead of html select

* update dropdown styles on challengeDetail (add task) and on inventory unequip

* change the width to "min-width"
2020-11-30 20:01:22 +01:00
Matteo Pagliazzi 51b50bfa3c Upgrade APN module (#12818)
* switch apn module to up to date version @parse/apn

* remove old module

* fix unit tests
2020-11-30 20:00:57 +01:00
dependabot-preview[bot] 8c953ea8cb build(deps): bump core-js from 3.7.0 to 3.8.0 in /website/client (#12833)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.7.0 to 3.8.0.
- [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.7.0...v3.8.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-11-30 11:52:58 +01:00
dependabot-preview[bot] c5b644b892 build(deps): bump mongoose from 5.10.15 to 5.10.18 (#12826)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.15 to 5.10.18.
- [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.15...5.10.18)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-30 11:52:49 +01:00
dependabot-preview[bot] e65bd4164d build(deps): bump @babel/core from 7.12.7 to 7.12.9 (#12825)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.12.7 to 7.12.9.
- [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.9/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-11-30 11:52:39 +01:00
dependabot-preview[bot] c9ef21aa7e build(deps): bump nconf from 0.10.0 to 0.11.0 (#12821)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.10.0 to 0.11.0.
- [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/0.10.0...v0.11.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-11-30 11:52:15 +01:00
dependabot-preview[bot] f41eae3bf3 build(deps): bump nconf from 0.10.0 to 0.11.0 in /website/client (#12829)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.10.0 to 0.11.0.
- [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/0.10.0...v0.11.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-11-30 11:52:07 +01:00
dependabot-preview[bot] c984c04e46 build(deps-dev): bump run-rs from 0.6.2 to 0.7.3 (#12822)
Bumps [run-rs](https://github.com/vkarpov15/run-rs) from 0.6.2 to 0.7.3.
- [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.6.2...0.7.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-30 11:51:52 +01:00
Matteo Pagliazzi 4e9a2de527 fix(analytics): fix tests and add new ones for getServiceByEnvironment 2020-11-30 11:39:39 +01:00
Matteo Pagliazzi 7745a0e65a fix(analytics): always use mock service in development 2020-11-29 23:15:26 +01:00
Matteo Pagliazzi 6b3a6eb59f fix(analytics): allow tracking static pages events when the user is not authenticated 2020-11-29 20:15:12 +01:00
Matteo Pagliazzi 103b4cb8a8 docs(get user challenges): document all query parameters for the GET /challenges/user API route 2020-11-28 19:32:08 +01:00
Sabe Jones de5473c71e 4.171.1 2020-11-26 14:01:31 -06:00
Sabe Jones f31370d7ba chore(event): NPCs and auto award turkey 2020-11-26 14:01:23 -06:00
Sabe Jones 3b7bf5de75 chore(event): yearly harvest feasting 2020-11-26 13:39:07 -06:00
Melior 496950e97d Merge branch 'origin/develop' into Weblate. 2020-11-25 01:00:01 +01:00
Sabe Jones 281d7b4fe2 Merge branch 'release' into develop 2020-11-24 17:57:24 -06:00
Sabe Jones 8d2ecaffb0 4.171.0 2020-11-24 17:56:54 -06:00
Sabe Jones 00f66b3824 chore(sprites): compile 2020-11-24 17:53:23 -06:00
Sabe Jones c4f6644c3a feat(content): Red Pet Achievement 2020-11-24 17:53:15 -06:00
Melior 58b5af0d4c 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 76.7% (43 of 56 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.0% (623 of 724 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 69.6% (39 of 56 strings)

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

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 (Dutch)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 94.2% (2066 of 2193 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% (61 of 61 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.2% (2044 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1926 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 83.2% (1825 of 2193 strings)

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

Translated using Weblate (Dutch)

Currently translated at 85.7% (48 of 56 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 67.8% (38 of 56 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1926 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1926 of 2193 strings)

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

Translated using Weblate (Hindi)

Currently translated at 46.8% (52 of 111 strings)

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

Translated using Weblate (Malay)

Currently translated at 3.8% (7 of 181 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Hindi)

Currently translated at 97.5% (121 of 124 strings)

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

Translated using Weblate (Galician)

Currently translated at 85.9% (622 of 724 strings)

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

Translated using Weblate (Hindi)

Currently translated at 91.8% (90 of 98 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 92.5% (124 of 134 strings)

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

Translated using Weblate (Dutch)

Currently translated at 98.8% (84 of 85 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (Danish)

Currently translated at 87.4% (320 of 366 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 82.7% (1815 of 2193 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 67.8% (38 of 56 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 96.9% (702 of 724 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.4% (720 of 724 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Spanish)

Currently translated at 95.7% (693 of 724 strings)

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

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 (Chinese (Simplified))

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.9% (97 of 98 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 85.4% (619 of 724 strings)

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

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 94.1% (2065 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 94.7% (686 of 724 strings)

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

Translated using Weblate (Latin)

Currently translated at 99.4% (186 of 187 strings)

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

Translated using Weblate (Latin)

Currently translated at 93.8% (92 of 98 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 99.4% (364 of 366 strings)

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

Translated using Weblate (Danish)

Currently translated at 88.0% (118 of 134 strings)

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

Translated using Weblate (Dutch)

Currently translated at 90.3% (168 of 186 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Dutch)

Currently translated at 97.6% (2141 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 93.0% (2040 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.4% (1918 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Spanish)

Currently translated at 93.3% (676 of 724 strings)

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

Translated using Weblate (Korean)

Currently translated at 98.3% (184 of 187 strings)

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

Translated using Weblate (Russian)

Currently translated at 96.9% (702 of 724 strings)

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

Translated using Weblate (Russian)

Currently translated at 99.7% (364 of 365 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.8% (182 of 186 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (Spanish)

Currently translated at 93.2% (675 of 724 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (Russian)

Currently translated at 99.0% (101 of 102 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 81.6% (80 of 98 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 93.8% (2058 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.8% (2036 of 2193 strings)

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

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% (724 of 724 strings)

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

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 (Spanish (Latin America))

Currently translated at 93.7% (2056 of 2193 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 93.2% (2045 of 2193 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (723 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 99.8% (723 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 99.7% (722 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 99.5% (721 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 99.5% (721 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 99.4% (720 of 724 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (724 of 724 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.6% (2032 of 2193 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 92.6% (2032 of 2193 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 92.4% (2028 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.4% (2028 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.4% (2028 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.3% (2025 of 2193 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 48.9% (48 of 98 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (186 of 186 strings)

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

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 (German)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 92.4% (2028 of 2193 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% (186 of 186 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 92.3% (2025 of 2193 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 (Italian)

Currently translated at 99.8% (723 of 724 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (186 of 186 strings)

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

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 (Italian)

Currently translated at 100.0% (186 of 186 strings)

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

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 (Italian)

Currently translated at 99.4% (720 of 724 strings)

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

Translated using Weblate (German)

Currently translated at 99.4% (720 of 724 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.3% (719 of 724 strings)

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

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 (Dutch)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (186 of 186 strings)

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

Translated using Weblate (Dutch)

Currently translated at 83.9% (47 of 56 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (365 of 365 strings)

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

Translated using Weblate (French)

Currently translated at 99.7% (364 of 365 strings)

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

Translated using Weblate (Spanish (Latin America))

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

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/
2020-11-25 00:14:39 +01:00
Alys 9b76f9831e Miscellaneous lint fixes: move watch & mounted properties; apply automatic fixes (#12791)
* commit lint's automatic fixes

* move watch and mounted properties as advised in lint warnings
2020-11-23 22:14:14 +01:00
Lio 8bd2e09bde Bugfix in ko/front.json (#12790)
In weblate we have the allert:
Weblate could not parse the translation files while updating the translations.

The following occurrences were found:
Filename	Error
website/common/locales/ko/front.json	JSONDecodeError('Expecting property name enclosed in double quotes: line 19 column 1 (char 805)',)

I deleted the trailing comma (so that no further entry is expected).
2020-11-23 21:53:58 +01:00
dependabot-preview[bot] 670843c395 build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#12810)
Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.8 to 4.5.9.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.9/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.9/packages/@vue/cli-plugin-unit-mocha)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:31:20 +01:00
dependabot-preview[bot] a81e6932fb build(deps): bump @vue/cli-plugin-eslint in /website/client (#12806)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.8 to 4.5.9.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.9/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.9/packages/@vue/cli-plugin-eslint)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:31:00 +01:00
dependabot-preview[bot] 4219bcbffa build(deps): bump @babel/core from 7.12.3 to 7.12.7 (#12799)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.12.3 to 7.12.7.
- [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.7/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-11-23 11:28:01 +01:00
dependabot-preview[bot] e499666f64 build(deps): bump @vue/cli-plugin-router in /website/client (#12807)
Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.8 to 4.5.9.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.9/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.9/packages/@vue/cli-plugin-router)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:25:34 +01:00
dependabot-preview[bot] b5a25d74df build(deps): bump @vue/cli-plugin-babel in /website/client (#12811)
Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.8 to 4.5.9.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.9/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.9/packages/@vue/cli-plugin-babel)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:25:21 +01:00
dependabot-preview[bot] d5408b89b2 build(deps): bump @vue/cli-service in /website/client (#12805)
Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.8 to 4.5.9.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/v4.5.9/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.9/packages/@vue/cli-service)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:24:59 +01:00
dependabot-preview[bot] 4c69bf2090 build(deps): bump @babel/preset-env from 7.12.1 to 7.12.7 (#12804)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.12.1 to 7.12.7.
- [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.7/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-11-23 11:24:47 +01:00
dependabot-preview[bot] 54e2874990 build(deps): bump csv-stringify from 5.5.1 to 5.5.3 (#12801)
Bumps [csv-stringify](https://github.com/adaltas/node-csv-stringify) from 5.5.1 to 5.5.3.
- [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.1...v5.5.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:24:07 +01:00
dependabot-preview[bot] 278ed4d2df build(deps): bump mongoose from 5.10.14 to 5.10.15 (#12798)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.14 to 5.10.15.
- [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.14...5.10.15)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 11:23:50 +01:00
Matteo Pagliazzi f7b4d25657 update apidoc 2020-11-20 09:18:16 +01:00
Sabe Jones f44b331680 4.170.1 2020-11-19 16:19:24 -06:00
Matteo Pagliazzi 284cfde935 Mandatory pagination for GET /challenges/user (#12792)
* BREAKING: require pagination for GET /challenges/user

* fix tests

* remove unused test
2020-11-19 16:18:11 -06:00
Melior c19c39d72d Translated using Weblate (Spanish (Latin America))
Currently translated at 91.1% (1998 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.2% (2024 of 2193 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Dutch)

Currently translated at 99.4% (179 of 180 strings)

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

Translated using Weblate (Dutch)

Currently translated at 99.4% (179 of 180 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Japanese)

Currently translated at 92.1% (2021 of 2193 strings)

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

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 (Chinese (Traditional))

Currently translated at 99.2% (567 of 571 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (203 of 203 strings)

Translation: Habitica/Generic
Translate-URL: https://translate.habitica.com/projects/habitica/generic/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 (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 (German)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 97.9% (96 of 98 strings)

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

Translated using Weblate (Chinese (Traditional))

Currently translated at 99.4% (179 of 180 strings)

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

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 (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 (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 (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 (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 (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 (Japanese)

Currently translated at 92.1% (2020 of 2193 strings)

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

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 (Korean)

Currently translated at 98.1% (109 of 111 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 35.7% (35 of 98 strings)

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

Translated using Weblate (Korean)

Currently translated at 98.1% (109 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 98.1% (109 of 111 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 90.2% (1980 of 2193 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% (2193 of 2193 strings)

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

Translated using Weblate (Chinese (Simplified))

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

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

Translated using Weblate (Japanese)

Currently translated at 91.9% (2016 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 91.8% (2014 of 2193 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Japanese)

Currently translated at 91.7% (2012 of 2193 strings)

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

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 (Spanish (Latin America))

Currently translated at 88.6% (1944 of 2193 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% (102 of 102 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 88.6% (1944 of 2193 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% (102 of 102 strings)

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

Translated using Weblate (Japanese)

Currently translated at 91.5% (2008 of 2193 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 (Japanese)

Currently translated at 91.5% (2007 of 2193 strings)

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

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 (Italian)

Currently translated at 100.0% (102 of 102 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (102 of 102 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/
2020-11-18 21:11:25 +01:00
Sabe Jones 809398f607 Merge branch 'release' into develop 2020-11-18 13:53:50 -06:00
Sabe Jones 5791e87132 4.170.0 2020-11-18 13:53:30 -06:00
Sabe Jones 4a93201f50 chore(analytics): track Challenge prizes 2020-11-17 15:50:44 -06:00
Sabe Jones a8ac927030 chore(sprites): compile 2020-11-16 15:52:13 -06:00
Sabe Jones 5327827ef7 feat(content): Black Pearl Hatching Potions + quest 2020-11-16 15:52:06 -06:00
Matteo Pagliazzi df1e4af7fc fix(profile): correctly change page title when closing profile modal, fixes #12760, thanks @aevix 2020-11-16 11:30:06 +01:00
dependabot-preview[bot] d0c9c2917f build(deps): bump mongoose from 5.10.13 to 5.10.14 (#12786)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.13 to 5.10.14.
- [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.13...5.10.14)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-16 11:16:51 +01:00
dependabot-preview[bot] 50e009efff build(deps): bump amplitude-js from 7.3.2 to 7.3.3 in /website/client (#12789)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.3.2 to 7.3.3.
- [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.2...v7.3.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-16 11:16:05 +01:00
Shadow 8c98b7127e make guilds not display group plans as title section (#12761)
* make guilds not display group plans as title section

* fix for parties as well

* task board for group plans now says group plans

* fix party title

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-11-14 19:35:09 +01:00
Melior cb96ff84d1 Merge branch 'origin/develop' into Weblate. 2020-11-13 21:34:10 +01:00
Sabe Jones 705ae93292 4.169.2 2020-11-13 14:32:48 -06:00
Sabe Jones 1c089c33a0 Merge branch 'develop' into release 2020-11-13 14:31:50 -06:00
Melior 4481217b90 Translated using Weblate (Spanish (Latin America))
Currently translated at 87.5% (1920 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Japanese)

Currently translated at 91.4% (2006 of 2193 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.5% (1921 of 2193 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.5% (1921 of 2193 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Hindi)

Currently translated at 46.8% (52 of 111 strings)

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

Translated using Weblate (Latin)

Currently translated at 98.9% (185 of 187 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Irish)

Currently translated at 84.6% (11 of 13 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Hindi)

Currently translated at 91.8% (90 of 98 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.1% (55 of 61 strings)

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

Translated using Weblate (Hindi)

Currently translated at 96.0% (195 of 203 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 77.6% (1703 of 2193 strings)

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

Translated using Weblate (Irish)

Currently translated at 77.5% (1701 of 2193 strings)

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

Translated using Weblate (Norwegian Bokmål)

Currently translated at 92.4% (196 of 212 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.9% (1907 of 2193 strings)

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

Translated using Weblate (Dutch)

Currently translated at 97.6% (2141 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.4% (1918 of 2193 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.5% (1921 of 2193 strings)

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

Translated using Weblate (Romanian)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Portuguese (Brazil))

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

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

Translated using Weblate (Japanese)

Currently translated at 91.2% (2002 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.4% (1918 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 91.1% (1998 of 2193 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (15 of 15 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (98 of 98 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
2020-11-13 20:34:14 +01:00
Matteo Pagliazzi d3ba0346af Move more analytics to server (#12782)
* track events on the client by default, remove unused ones

* fix lint, remove some calls to updateUser

* remove dead code from guide.js
2020-11-13 15:42:46 +01:00
Matteo Pagliazzi 41de90e578 fix: make sure world state is not loaded every time a modal is opened, fix dev server caching on safari 2020-11-13 14:33:59 +01:00
Sabe Jones a863e79214 fix(teams): allow dismissal of approval requests, again 2020-11-10 15:25:12 -06:00
Sabe Jones 6ed1353e31 4.169.1 2020-11-10 14:49:14 -06:00
Sabe Jones c748477546 chore(shops): featured items update 2020-11-10 14:49:00 -06:00
Melior 365f9c0aa7 Merge branch 'origin/develop' into Weblate. 2020-11-10 21:12:30 +01:00
Melior 23e717353d Translated using Weblate (Spanish (Latin America))
Currently translated at 86.9% (1907 of 2193 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% (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% (8 of 8 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.9% (1994 of 2193 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.5% (1897 of 2193 strings)

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

Translated using Weblate (Swedish)

Currently translated at 98.3% (178 of 181 strings)

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

Translated using Weblate (Russian)

Currently translated at 85.7% (48 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.7% (1990 of 2193 strings)

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

Translated using Weblate (Czech)

Currently translated at 98.7% (564 of 571 strings)

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

Translated using Weblate (Czech)

Currently translated at 98.7% (564 of 571 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 26.5% (26 of 98 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 99.4% (361 of 363 strings)

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

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% (13 of 13 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.1% (1890 of 2193 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 96.5% (196 of 203 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 96.1% (349 of 363 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 78.5% (77 of 98 strings)

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

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 84.6% (1856 of 2193 strings)

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

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 (Spanish (Latin America))

Currently translated at 84.3% (1849 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.5% (1986 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.4% (1918 of 2193 strings)

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

Translated using Weblate (Swedish)

Currently translated at 71.4% (40 of 56 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 51.6% (48 of 93 strings)

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

Translated using Weblate (Swedish)

Currently translated at 70.4% (69 of 98 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 82.5% (1810 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.3% (1982 of 2193 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.2% (1979 of 2193 strings)

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

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 (Spanish)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (124 of 124 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (185 of 185 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.4% (1918 of 2193 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 (Spanish)

Currently translated at 93.1% (669 of 718 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.9% (2192 of 2193 strings)

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

Translated using Weblate (Russian)

Currently translated at 88.4% (161 of 182 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.8% (559 of 571 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.8% (559 of 571 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Russian)

Currently translated at 97.8% (181 of 185 strings)

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

Translated using Weblate (Russian)

Currently translated at 96.7% (354 of 366 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Russian)

Currently translated at 95.0% (58 of 61 strings)

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

Translated using Weblate (Russian)

Currently translated at 93.4% (57 of 61 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Swedish)

Currently translated at 100.0% (187 of 187 strings)

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

Translated using Weblate (Polish)

Currently translated at 94.8% (93 of 98 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.5% (1921 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.1% (1978 of 2193 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.2% (619 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/
2020-11-10 21:12:21 +01:00
Sabe Jones d5517ffc5f 4.169.0 2020-11-10 14:06:56 -06:00
Sabe Jones 7b6f63958a fix(pets): better marshmallow positioning
Fixes #12630
2020-11-10 14:06:47 -06:00
Matteo Pagliazzi b5d8bcc0fe fix(categories): correct z-index, fix #12777 2020-11-10 19:10:39 +01:00
Matteo Pagliazzi 181b33101e Challenge Won Notification improvements (#12762)
* challenge won notification: add more info

* update tests

* use new notification on web, fixes #7716

* wip design

* finalize design

* fix markdown rendering
2020-11-10 18:47:13 +01:00
negue 4319bd5ad1 Update sidebar styles (#12744)
* update sidebars to the filter-sidebar components

* update sidebars to the filter-sidebar components

* use object v-for instead of Object.keys
2020-11-09 23:00:57 +01:00
negue f2c6838e95 update dropdowns to use the updated / styled components (#12758)
* update dropdowns to use the updated / styled components

* update colors / behavior for colors

* remove class binding
2020-11-09 22:26:21 +01:00
Sabe Jones a2cd79f20e chore(sprites): compile 2020-11-09 15:07:05 -06:00
Sabe Jones 6a367d3697 feat(content): Autumn Leaf and Frost Hatching Potions 2020-11-09 15:06:56 -06:00
Sabe Jones ef0b19f17e fix(backgrounds): corrected icon 2020-11-09 14:35:30 -06:00
Matteo Pagliazzi 27129754cd gems-promo: comment unused code 2020-11-09 16:34:52 +01:00
jbusa22 983aae7f87 Fixes #12730 - Tag filter not always cleared correctly when deleting active tag (#12737)
* Update title for tabs not including challenges, guild and team

* add section titles to challenges, guilds, and groups

* Update dynamic title to use vuex action

* Remove duplicate key

* Actually remove duplicate key

* Fix section sub section in group

* Add note to implement setTitle when adding a page

* Add missing sections to dynamic title

* Features string not translated

* Use onGroupUpdate to update group titles

* Add watcher to challenges for dynamic title updates

* Small fixes

* Add register and login to title, remove duplicate keys

* Add home page dynamic title functionality

* Minor name changes

* Fix tag filtering on deletion

* Remove debuggers

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-11-09 12:25:22 +01:00
Matteo Pagliazzi 174ac6d7e3 Revert "Revert "fix(banned words): fix partial matching of words containing diacritic… (#12444)""
This reverts commit 5362058f35.
2020-11-09 11:34:28 +01:00
Matteo Pagliazzi 2e59260149 Revert "Revert "Analytics: track generic events through the server (#12735)""
This reverts commit 9d6fb2ca26.
2020-11-09 11:34:20 +01:00
Matteo Pagliazzi 997cc9f3c5 Merge branch 'release' into develop 2020-11-09 11:33:53 +01:00
dependabot-preview[bot] 8a7b4db5ee build(deps): bump amplitude-js from 7.3.1 to 7.3.2 in /website/client (#12771)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.3.1 to 7.3.2.
- [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.1...v7.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-11-09 10:50:39 +01:00
dependabot-preview[bot] 7adb33887e build(deps): bump bootstrap-vue from 2.18.1 to 2.19.0 in /website/client (#12772)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.18.1 to 2.19.0.
- [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.18.1...v2.19.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-11-09 10:50:30 +01:00
dependabot-preview[bot] 85d2e21510 build(deps): bump core-js from 3.6.5 to 3.7.0 in /website/client (#12770)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.6.5 to 3.7.0.
- [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.6.5...v3.7.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-11-09 10:50:11 +01:00
dependabot-preview[bot] 868a8a4e77 build(deps): bump sass from 1.28.0 to 1.29.0 in /website/client (#12769)
Bumps [sass](https://github.com/sass/dart-sass) from 1.28.0 to 1.29.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.28.0...1.29.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-11-09 10:50:05 +01:00
dependabot-preview[bot] b61425078a build(deps): bump mongoose from 5.10.11 to 5.10.13 (#12768)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.11 to 5.10.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.10.11...5.10.13)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-09 10:49:53 +01:00
dependabot-preview[bot] 03876b86bb build(deps): bump vue-router from 3.4.8 to 3.4.9 in /website/client (#12773)
Bumps [vue-router](https://github.com/vuejs/vue-router) from 3.4.8 to 3.4.9.
- [Release notes](https://github.com/vuejs/vue-router/releases)
- [Changelog](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-router/compare/v3.4.8...v3.4.9)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-09 10:45:58 +01:00
Melior 8ac48406e9 Translated using Weblate (Spanish (Latin America))
Currently translated at 86.2% (619 of 718 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.2% (619 of 718 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% (61 of 61 strings)

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

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 (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 (Portuguese (Brazil))

Currently translated at 100.0% (13 of 13 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 82.3% (1806 of 2193 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% (363 of 363 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.0% (1974 of 2193 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 (Spanish)

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.2% (567 of 571 strings)

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

Translated using Weblate (Hindi)

Currently translated at 99.1% (122 of 123 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (2187 of 2193 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 16.3% (16 of 98 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 15.3% (15 of 98 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.1% (566 of 571 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.2% (619 of 718 strings)

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

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 (Spanish (Latin America))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 96.9% (95 of 98 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 87.1% (319 of 366 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Japanese)

Currently translated at 89.9% (1972 of 2193 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2193 of 2193 strings)

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

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 100.0% (56 of 56 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.6% (569 of 571 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Hindi)

Currently translated at 97.5% (121 of 124 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (571 of 571 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (2193 of 2193 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (571 of 571 strings)

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

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 (French)

Currently translated at 100.0% (185 of 185 strings)

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

Translated using Weblate (French)

Currently translated at 99.7% (365 of 366 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (100 of 100 strings)

Translation: Habitica/Challenge
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/
2020-11-05 22:49:10 +01:00
Sabe Jones a6e96f7ad9 4.168.3 2020-11-05 15:45:54 -06:00
Sabe Jones 43b8368f42 Merge branch 'develop' into release 2020-11-05 15:45:44 -06:00
Sabe Jones 5362058f35 Revert "fix(banned words): fix partial matching of words containing diacritic… (#12444)"
This reverts commit f2bcdd21de.
2020-11-05 15:44:59 -06:00
Sabe Jones 9d6fb2ca26 Revert "Analytics: track generic events through the server (#12735)"
This reverts commit 48dbe547c0.
2020-11-05 15:44:30 -06:00
jbusa22 9213ee92de Group title on route fix (#12743)
* Update title for tabs not including challenges, guild and team

* add section titles to challenges, guilds, and groups

* Update dynamic title to use vuex action

* Remove duplicate key

* Actually remove duplicate key

* Fix section sub section in group

* Add note to implement setTitle when adding a page

* Add missing sections to dynamic title

* Features string not translated

* Use onGroupUpdate to update group titles

* Add watcher to challenges for dynamic title updates

* Small fixes

* Add register and login to title, remove duplicate keys

* Add home page dynamic title functionality

* Minor name changes

* remove wrong i18n strings from front.js

* refactor router note

* 4.166.1

* build(deps): bump got from 11.7.0 to 11.8.0

Bumps [got](https://github.com/sindresorhus/got) from 11.7.0 to 11.8.0.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.7.0...v11.8.0)

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

* build(deps): bump rate-limiter-flexible from 2.1.10 to 2.1.13 (#12709)

Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.10 to 2.1.13.
- [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>

* build(deps): bump image-size from 0.9.1 to 0.9.2 (#12711)

Bumps [image-size](https://github.com/image-size/image-size) from 0.9.1 to 0.9.2.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](https://github.com/image-size/image-size/compare/v0.9.1...v0.9.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump mongoose from 5.10.9 to 5.10.10 (#12706)

Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.9 to 5.10.10.
- [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.9...5.10.10)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps-dev): bump axios from 0.19.2 to 0.21.0 (#12708)

Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.21.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.21.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump axios from 0.19.2 to 0.21.0 in /website/client (#12712)

Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.21.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.21.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump jwks-rsa from 1.10.1 to 1.11.0 (#12707)

Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.10.1 to 1.11.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)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Prevent the removal of a quest owner from a group, take 2 (#12695)

* add cannotRemoveQuestLeader string

* throw error when member is quest leader

* add the new apidoc error

* change i18n key name

* fix apidoc formatting and change key in throw()

* add test for preventing removing quest owner

* patch(groups): change error codes

* Merge #12654
Fixes #12417
Squashed commit of the following:

commit 1f074175c480a638cf61e2c72ca57cdc6f8699b6
Author: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Date:   Mon Oct 26 10:57:23 2020 +0100

    fix(i18n): remove unused string questLevelTooHigh

commit 12cc74002ec87c14cc000b008454f34475fd3636
Merge: 4fc260e552 ad9b551de3
Author: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Date:   Mon Oct 26 10:50:39 2020 +0100

    Merge branch 'feature/level-locked-quests-should-be-used-at-any-level' of https://github.com/hamboomger/habitica into hamboomger-feature/level-locked-quests-should-be-used-at-any-level

commit ad9b551de3
Author: hamboomger <hamboomger@gmail.com>
Date:   Thu Oct 8 13:34:19 2020 +0300

    fix(quests): Quests that are level-locked for purchase can now be used at any level

* fix(banned words): fix partial matching of words containing diacritic… (#12444)

* fix(banned words): fix partial matching of words containing diacritics against banned words list (#12309)

* lint: remove whitespace to fix error

* test: add test to prevent partial matching of words containing diacritics against banned words list (#12309)

* doc: add link to Unicode table of diacritical marks (#12309)

* fix Arabic punctuation & alignment (#12655)

* fix Arabic punctuation & alignment

* fix Arabic punctuation & alignment - 2

* add rtl support for all rtl languages

* add auto direction to chat cards

* fix alignment: use automatic alignment based on dir attribute

* restore package-lock.json

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>

* Fix keyboard inaccessible accordion in guild/party page fixes #12653 (#12656)

* fix: replace clickable div with button

improve accessibility for keyboard users

* refactor: extract sidebar button to own component

* refactor: button to div

* fix: lint, update sidebarSection test

* build(deps): bump vuedraggable from 2.24.2 to 2.24.3 in /website/client (#12727)

Bumps [vuedraggable](https://github.com/SortableJS/Vue.Draggable) from 2.24.2 to 2.24.3.
- [Release notes](https://github.com/SortableJS/Vue.Draggable/releases)
- [Commits](https://github.com/SortableJS/Vue.Draggable/compare/v2.24.2...v2.24.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump @vue/cli-plugin-eslint in /website/client (#12719)

Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.7 to 4.5.8.
- [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.8/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>

* build(deps): bump bootstrap-vue from 2.18.0 to 2.18.1 in /website/client (#12725)

Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.18.0 to 2.18.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.18.0...v2.18.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#12721)

Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.7 to 4.5.8.
- [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.8/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>

* build(deps): bump vue-router from 3.4.7 to 3.4.8 in /website/client (#12720)

Bumps [vue-router](https://github.com/vuejs/vue-router) from 3.4.7 to 3.4.8.
- [Release notes](https://github.com/vuejs/vue-router/releases)
- [Changelog](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-router/compare/v3.4.7...v3.4.8)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* build(deps): bump @vue/cli-plugin-router in /website/client (#12718)

Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.7 to 4.5.8.
- [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.8/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>

* build(deps): bump @vue/cli-plugin-babel in /website/client (#12717)

Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.7 to 4.5.8.
- [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.8/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>

* build(deps): bump @vue/cli-service in /website/client (#12726)

Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.7 to 4.5.8.
- [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.8/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>

* feat(content): Mystery Items and Habitoween pet

* fix(content): shield not weapon

* fix(event): goodies for newbies

* Loggly-only user support events (#12676)

* feat(analytics): Loggly-only user support events

* fix(analytics): clean up more Unknowns

* 4.166.2

* Analytics: track generic events through the server (#12735)

* Loggly-only user support events (#12676)

* feat(analytics): Loggly-only user support events

* fix(analytics): clean up more Unknowns

* wip: allow tracking events from the server

* analytics: allow tracking generic events on the server

* remove console.logs

* remove console.log (client)

* add integration test

Co-authored-by: Sabe Jones <sabrecat@gmail.com>

* 4.166.3

* fix erranous upgrade

* 4.166.2

* 4.167.0

* Translated using Weblate (Korean)

Currently translated at 98.1% (109 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 98.3% (121 of 123 strings)

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

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 89.0% (1944 of 2183 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% (564 of 564 strings)

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

Translated using Weblate (Korean)

Currently translated at 65.7% (73 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 77.4% (72 of 93 strings)

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

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 88.9% (1941 of 2183 strings)

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

Translated using Weblate (Korean)

Currently translated at 73.1% (68 of 93 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.8% (356 of 364 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.8% (1940 of 2183 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.7% (1938 of 2183 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 45.1% (42 of 93 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 45.1% (42 of 93 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.7% (1937 of 2183 strings)

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

Translated using Weblate (Basque)

Currently translated at 100.0% (1 of 1 strings)

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

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 100.0% (8 of 8 strings)

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

Translated using Weblate (Basque)

Currently translated at 6.5% (8 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (564 of 564 strings)

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

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 97.2% (354 of 364 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/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 (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 (Spanish)

Currently translated at 99.8% (563 of 564 strings)

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

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% (124 of 124 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1917 of 2183 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 (Spanish)

Currently translated at 95.3% (538 of 564 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.6% (1935 of 2183 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (184 of 184 strings)

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

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% (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% (718 of 718 strings)

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

Translated using Weblate (Chinese (Simplified))

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

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 81.4% (1779 of 2183 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% (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% (2183 of 2183 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% (718 of 718 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% (718 of 718 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% (2183 of 2183 strings)

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

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 (Czech)

Currently translated at 98.9% (182 of 184 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.5% (1933 of 2183 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (564 of 564 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.4% (1931 of 2183 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 89.2% (50 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.7% (177 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Polish)

Currently translated at 98.2% (55 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 87.5% (49 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Polish)

Currently translated at 89.2% (50 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.0% (58 of 61 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (183 of 184 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 85.3% (613 of 718 strings)

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

* fix(event): Habitoween NPC sprites

* Fix Tasks styles (#12700)

* re-add previous markdown h3/h4 styles - remove double transition properties

* fix more heading styles

* fix markdown h3 / tasktitle h3

* Add title update to fetchguilds to catch router.push page changes

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Shadow <william.shadow@outlook.com>
Co-authored-by: Carlton McFarlane <carlton@ilicmcfarlane.io>
Co-authored-by: Mario Yonan <62141485+mario130@users.noreply.github.com>
Co-authored-by: J Sanderson <julia@parentscheme.com>
Co-authored-by: Melior <admin@habitica.com>
Co-authored-by: negue <negue@users.noreply.github.com>
2020-11-03 23:28:27 +01:00
Melior 3a80875505 Merge branch 'origin/develop' into Weblate. 2020-11-03 22:39:06 +01:00
Melior 2d6802ae87 Translated using Weblate (French)
Currently translated at 100.0% (98 of 98 strings)

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

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Spanish (Latin America))

Currently translated at 85.3% (613 of 718 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 81.3% (1779 of 2187 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.8% (1921 of 2187 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (185 of 185 strings)

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

Translated using Weblate (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 (Czech)

Currently translated at 87.8% (1921 of 2187 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.8% (1921 of 2187 strings)

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

Translated using Weblate (Czech)

Currently translated at 87.8% (1921 of 2187 strings)

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

Translated using Weblate (Hindi)

Currently translated at 16.5% (30 of 181 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (100 of 100 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/Inventory
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/hi/

Translated using Weblate (Hindi)

Currently translated at 98.3% (121 of 123 strings)

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

Translated using Weblate (Japanese)

Currently translated at 90.0% (1970 of 2187 strings)

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

Translated using Weblate (Dutch)

Currently translated at 95.9% (689 of 718 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.4% (364 of 366 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 77.5% (76 of 98 strings)

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

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 (Japanese)

Currently translated at 89.8% (1966 of 2187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Chinese (Hong Kong))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (181 of 182 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 97.7% (702 of 718 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (564 of 564 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 93.4% (527 of 564 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 93.4% (527 of 564 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.9% (97 of 98 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% (180 of 180 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% (180 of 180 strings)

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

Translated using Weblate (Japanese)

Currently translated at 89.7% (1962 of 2187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Japanese)

Currently translated at 89.3% (1955 of 2187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.5% (715 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.5% (715 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.5% (715 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Japanese)

Currently translated at 98.0% (704 of 718 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 99.1% (559 of 564 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% (182 of 182 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (English (United Kingdom))

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

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (2187 of 2187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.3% (692 of 718 strings)

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

Translated using Weblate (English (United Kingdom))

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

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

Translated using Weblate (English (United Kingdom))

Currently translated at 95.0% (173 of 182 strings)

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

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (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 (German)

Currently translated at 100.0% (185 of 185 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (2187 of 2187 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.9% (185 of 187 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 98.9% (185 of 187 strings)

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

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% (185 of 185 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.7% (365 of 366 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (366 of 366 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (2187 of 2187 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.9% (689 of 718 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.9% (95 of 98 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (98 of 98 strings)

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

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 (Chinese (Simplified))

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

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2187 of 2187 strings)

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

Translated using Weblate (Swedish)

Currently translated at 67.8% (38 of 56 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (100 of 100 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (98 of 98 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 85.3% (613 of 718 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% (134 of 134 strings)

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

Translated using Weblate (Spanish (Latin America))

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

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 81.3% (1779 of 2187 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 96.9% (95 of 98 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (185 of 185 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.7% (365 of 366 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (100 of 100 strings)

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

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/
2020-11-03 22:39:00 +01:00
Sabe Jones 497c023995 Merge branch 'release' into develop 2020-11-03 15:20:20 -06:00
Sabe Jones b97d514c68 4.168.2 2020-11-03 15:20:01 -06:00
Sabe Jones 142fdfe743 fix(events): handle new spacer 2020-11-03 15:19:54 -06:00
Sabe Jones ee5a2b0e36 Merge branch 'release' into develop 2020-11-03 15:14:42 -06:00
Sabe Jones 9455f996ef 4.168.1 2020-11-03 15:14:23 -06:00
Sabe Jones 5cc3f6e8aa fix(mobile): empty event in world state 2020-11-03 15:14:17 -06:00
Sabe Jones 8bad3d1184 Merge branch 'release' into develop 2020-11-03 14:57:00 -06:00
Sabe Jones 3f65353974 4.168.0 2020-11-03 14:56:16 -06:00
Sabe Jones ab7c4015a2 chore(sprites): compile 2020-11-03 14:55:59 -06:00
Sabe Jones 6d509ae1f8 feat(content): Armoire and Backgrounds 2020-11-03 14:55:51 -06:00
Matteo Pagliazzi 6375bc1d59 drop cap ab test: add migration to enroll all web users 2020-11-03 21:30:50 +01:00
Matteo Pagliazzi 14714f9e1c Drop Cap A/B Tests: v2 (#12759)
* drop cap ab test: enroll all web users, 50/50

* update tests

* fix lint
2020-11-03 14:19:09 -06:00
Sara Olson 60b3f2b860 Update faq.json (#12757)
Changed android faq to properly explain where user can choose their class after opting out
2020-11-02 18:12:21 +01:00
Matteo Pagliazzi 965df326ed fix(hall): correctly set page title 2020-11-02 17:33:10 +01:00
agarwalvaibhav0211 3c49db9bfe Nested Spans Withing li tags (#12732) 2020-11-02 17:28:23 +01:00
Matteo Pagliazzi 72bd104567 migration: add migration to fix items.pets.JackOLantern-Base for new users 2020-11-02 13:31:40 +01:00
Matteo Pagliazzi 2cbd376cf6 fix(new users): use correct numeric value for JackOLantern-Base pet 2020-11-02 13:20:20 +01:00
Sabe Jones a7477e137e fix(teams): preserve original subscription start date (#12742) 2020-11-02 11:42:09 +01:00
dependabot-preview[bot] f6cb57c22f build(deps): bump image-size from 0.9.2 to 0.9.3 (#12747)
Bumps [image-size](https://github.com/image-size/image-size) from 0.9.2 to 0.9.3.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](https://github.com/image-size/image-size/compare/v0.9.2...v0.9.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-02 10:57:47 +01:00
dependabot-preview[bot] 76fa4dfd7f build(deps-dev): bump sinon from 9.2.0 to 9.2.1 (#12745)
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.2.0 to 9.2.1.
- [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)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-02 10:57:37 +01:00
dependabot-preview[bot] aceaeacbf0 build(deps): bump amplitude-js from 7.3.0 to 7.3.1 in /website/client (#12752)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/amplitude/amplitude-javascript/releases)
- [Changelog](https://github.com/amplitude/Amplitude-JavaScript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/amplitude/amplitude-javascript/compare/v7.3.0...v7.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-11-02 10:57:30 +01:00
dependabot-preview[bot] b2cb5f83de build(deps): bump mongoose from 5.10.10 to 5.10.11 (#12749)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.10 to 5.10.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.10.10...5.10.11)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-02 10:57:07 +01:00
dependabot-preview[bot] d09dea5185 build(deps): bump sass from 1.27.0 to 1.28.0 in /website/client (#12753)
Bumps [sass](https://github.com/sass/dart-sass) from 1.27.0 to 1.28.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.27.0...1.28.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-11-02 10:52:50 +01:00
Sabe Jones 6fa7fbce3f Merge branch 'release' into develop 2020-11-01 22:03:42 -06:00
Sabe Jones b17c9a33a5 4.167.2 2020-11-01 22:02:49 -06:00
Sabe Jones 31d0cb5a91 chore(event): conclude
and fix rotten potatoe
2020-11-01 22:02:39 -06:00
negue d678eb920f Fix Tasks styles (#12700)
* re-add previous markdown h3/h4 styles - remove double transition properties

* fix more heading styles

* fix markdown h3 / tasktitle h3
2020-10-29 23:50:29 +01:00
Sabe Jones 163eb55dbb 4.167.1 2020-10-29 12:31:30 -05:00
Sabe Jones 8661716c23 fix(event): Habitoween NPC sprites 2020-10-29 12:31:26 -05:00
Sabe Jones ea11e302c6 fix(event): Habitoween NPC sprites 2020-10-29 11:58:31 -05:00
Melior afdd5af7a9 Merge branch 'origin/develop' into Weblate. 2020-10-29 16:36:52 +01:00
Melior a09e56048e Translated using Weblate (Korean)
Currently translated at 98.1% (109 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 98.3% (121 of 123 strings)

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

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 89.0% (1944 of 2183 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% (564 of 564 strings)

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

Translated using Weblate (Korean)

Currently translated at 65.7% (73 of 111 strings)

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

Translated using Weblate (Korean)

Currently translated at 77.4% (72 of 93 strings)

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

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 88.9% (1941 of 2183 strings)

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

Translated using Weblate (Korean)

Currently translated at 73.1% (68 of 93 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 97.8% (356 of 364 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.8% (1940 of 2183 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (134 of 134 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.7% (1938 of 2183 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 45.1% (42 of 93 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 45.1% (42 of 93 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 92.2% (166 of 180 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.7% (1937 of 2183 strings)

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

Translated using Weblate (Basque)

Currently translated at 100.0% (1 of 1 strings)

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

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 100.0% (8 of 8 strings)

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

Translated using Weblate (Basque)

Currently translated at 6.5% (8 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (564 of 564 strings)

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

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 97.2% (354 of 364 strings)

Translation: Habitica/Groups
Translate-URL: https://translate.habitica.com/projects/habitica/groups/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 (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 (Spanish)

Currently translated at 99.8% (563 of 564 strings)

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

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% (124 of 124 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (23 of 23 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish)

Currently translated at 87.8% (1917 of 2183 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 (Spanish)

Currently translated at 95.3% (538 of 564 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (180 of 180 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.6% (1935 of 2183 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (184 of 184 strings)

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

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% (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% (718 of 718 strings)

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

Translated using Weblate (Chinese (Simplified))

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

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 81.4% (1779 of 2183 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% (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% (2183 of 2183 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% (718 of 718 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% (718 of 718 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% (2183 of 2183 strings)

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

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 (Czech)

Currently translated at 98.9% (182 of 184 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.5% (1933 of 2183 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (564 of 564 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.4% (1931 of 2183 strings)

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

Translated using Weblate (Japanese)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 89.2% (50 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 97.7% (177 of 181 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Polish)

Currently translated at 98.2% (55 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 87.5% (49 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 96.4% (54 of 56 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Polish)

Currently translated at 89.2% (50 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 95.0% (58 of 61 strings)

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

Translated using Weblate (Japanese)

Currently translated at 99.4% (183 of 184 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 85.3% (613 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/
2020-10-29 16:36:33 +01:00
Sabe Jones fd37ee90da 4.167.0 2020-10-29 10:25:35 -05:00
Sabe Jones a4cfb97dbf Merge branch 'sabrecat/prebuild-202010' into develop 2020-10-29 10:25:06 -05:00
Matteo Pagliazzi ea766251c2 Merge branch 'release' into develop 2020-10-28 23:24:42 +01:00
Matteo Pagliazzi f196ff2e24 4.166.2 2020-10-28 22:43:39 +01:00
Matteo Pagliazzi cc901fe085 fix erranous upgrade 2020-10-28 22:43:32 +01:00
Matteo Pagliazzi f257488b39 4.166.3 2020-10-28 22:39:55 +01:00
Matteo Pagliazzi 48dbe547c0 Analytics: track generic events through the server (#12735)
* Loggly-only user support events (#12676)

* feat(analytics): Loggly-only user support events

* fix(analytics): clean up more Unknowns

* wip: allow tracking events from the server

* analytics: allow tracking generic events on the server

* remove console.logs

* remove console.log (client)

* add integration test

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2020-10-28 22:39:19 +01:00
Matteo Pagliazzi b15462596b 4.166.2 2020-10-28 22:38:59 +01:00
Sabe Jones 2a98b5b7bf Loggly-only user support events (#12676)
* feat(analytics): Loggly-only user support events

* fix(analytics): clean up more Unknowns
2020-10-28 17:05:54 +01:00
Sabe Jones f7667fcf79 fix(event): goodies for newbies 2020-10-27 16:39:38 -05:00
Sabe Jones 05aaad8743 fix(content): shield not weapon 2020-10-27 16:33:45 -05:00
Sabe Jones 5e1f2c16f8 feat(content): Mystery Items and Habitoween pet 2020-10-27 16:19:36 -05:00
dependabot-preview[bot] 82b6a14d5b build(deps): bump @vue/cli-service in /website/client (#12726)
Bumps [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service) from 4.5.7 to 4.5.8.
- [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.8/packages/@vue/cli-service)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:36:02 +01:00
dependabot-preview[bot] f9cfd9fb5e build(deps): bump @vue/cli-plugin-babel in /website/client (#12717)
Bumps [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel) from 4.5.7 to 4.5.8.
- [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.8/packages/@vue/cli-plugin-babel)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:35:25 +01:00
dependabot-preview[bot] 60bef56577 build(deps): bump @vue/cli-plugin-router in /website/client (#12718)
Bumps [@vue/cli-plugin-router](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-router) from 4.5.7 to 4.5.8.
- [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.8/packages/@vue/cli-plugin-router)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:34:53 +01:00
dependabot-preview[bot] af87185bfa build(deps): bump vue-router from 3.4.7 to 3.4.8 in /website/client (#12720)
Bumps [vue-router](https://github.com/vuejs/vue-router) from 3.4.7 to 3.4.8.
- [Release notes](https://github.com/vuejs/vue-router/releases)
- [Changelog](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-router/compare/v3.4.7...v3.4.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-10-27 11:31:00 +01:00
dependabot-preview[bot] f8c8be4f4c build(deps): bump @vue/cli-plugin-unit-mocha in /website/client (#12721)
Bumps [@vue/cli-plugin-unit-mocha](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-unit-mocha) from 4.5.7 to 4.5.8.
- [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.8/packages/@vue/cli-plugin-unit-mocha)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:30:54 +01:00
dependabot-preview[bot] 5d220544e0 build(deps): bump bootstrap-vue from 2.18.0 to 2.18.1 in /website/client (#12725)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.18.0 to 2.18.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.18.0...v2.18.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-10-27 11:30:46 +01:00
dependabot-preview[bot] c4fd9daa90 build(deps): bump @vue/cli-plugin-eslint in /website/client (#12719)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.7 to 4.5.8.
- [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.8/packages/@vue/cli-plugin-eslint)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:30:33 +01:00
dependabot-preview[bot] fc8f9cbaa0 build(deps): bump vuedraggable from 2.24.2 to 2.24.3 in /website/client (#12727)
Bumps [vuedraggable](https://github.com/SortableJS/Vue.Draggable) from 2.24.2 to 2.24.3.
- [Release notes](https://github.com/SortableJS/Vue.Draggable/releases)
- [Commits](https://github.com/SortableJS/Vue.Draggable/compare/v2.24.2...v2.24.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-27 11:30:14 +01:00
J Sanderson e39d3e52e2 Fix keyboard inaccessible accordion in guild/party page fixes #12653 (#12656)
* fix: replace clickable div with button

improve accessibility for keyboard users

* refactor: extract sidebar button to own component

* refactor: button to div

* fix: lint, update sidebarSection test
2020-10-26 15:41:40 +01:00
Mario Yonan 625b4a4ad7 fix Arabic punctuation & alignment (#12655)
* fix Arabic punctuation & alignment

* fix Arabic punctuation & alignment - 2

* add rtl support for all rtl languages

* add auto direction to chat cards

* fix alignment: use automatic alignment based on dir attribute

* restore package-lock.json

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-10-26 15:32:07 +01:00
Carlton McFarlane f2bcdd21de fix(banned words): fix partial matching of words containing diacritic… (#12444)
* fix(banned words): fix partial matching of words containing diacritics against banned words list (#12309)

* lint: remove whitespace to fix error

* test: add test to prevent partial matching of words containing diacritics against banned words list (#12309)

* doc: add link to Unicode table of diacritical marks (#12309)
2020-10-26 12:14:04 +01:00
jbusa22 ad51675ac6 Fixes Issue #12421 - Change page title based on the site section being viewed (#12627)
* Update title for tabs not including challenges, guild and team

* add section titles to challenges, guilds, and groups

* Update dynamic title to use vuex action

* Remove duplicate key

* Actually remove duplicate key

* Fix section sub section in group

* Add note to implement setTitle when adding a page

* Add missing sections to dynamic title

* Features string not translated

* Use onGroupUpdate to update group titles

* Add watcher to challenges for dynamic title updates

* Small fixes

* Add register and login to title, remove duplicate keys

* Add home page dynamic title functionality

* Minor name changes

* remove wrong i18n strings from front.js

* refactor router note

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-10-26 11:22:46 +01:00
Matteo Pagliazzi 869d2df4fa Merge #12654
Fixes #12417
Squashed commit of the following:

commit 1f074175c480a638cf61e2c72ca57cdc6f8699b6
Author: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Date:   Mon Oct 26 10:57:23 2020 +0100

    fix(i18n): remove unused string questLevelTooHigh

commit 12cc74002ec87c14cc000b008454f34475fd3636
Merge: 4fc260e552 ad9b551de3
Author: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Date:   Mon Oct 26 10:50:39 2020 +0100

    Merge branch 'feature/level-locked-quests-should-be-used-at-any-level' of https://github.com/hamboomger/habitica into hamboomger-feature/level-locked-quests-should-be-used-at-any-level

commit ad9b551de3
Author: hamboomger <hamboomger@gmail.com>
Date:   Thu Oct 8 13:34:19 2020 +0300

    fix(quests): Quests that are level-locked for purchase can now be used at any level
2020-10-26 10:58:50 +01:00
Shadow 734e997345 Prevent the removal of a quest owner from a group, take 2 (#12695)
* add cannotRemoveQuestLeader string

* throw error when member is quest leader

* add the new apidoc error

* change i18n key name

* fix apidoc formatting and change key in throw()

* add test for preventing removing quest owner

* patch(groups): change error codes
2020-10-26 10:46:43 +01:00
dependabot-preview[bot] 4fc260e552 build(deps): bump jwks-rsa from 1.10.1 to 1.11.0 (#12707)
Bumps [jwks-rsa](https://github.com/auth0/node-jwks-rsa) from 1.10.1 to 1.11.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)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-26 10:43:16 +01:00
dependabot-preview[bot] fa22a47b7a build(deps): bump axios from 0.19.2 to 0.21.0 in /website/client (#12712)
Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.21.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.21.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-10-26 10:33:19 +01:00
dependabot-preview[bot] 0366245fab build(deps-dev): bump axios from 0.19.2 to 0.21.0 (#12708)
Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.21.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.21.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-10-26 10:28:16 +01:00
dependabot-preview[bot] f342eff70b build(deps): bump mongoose from 5.10.9 to 5.10.10 (#12706)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.10.9 to 5.10.10.
- [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.9...5.10.10)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-26 10:20:46 +01:00
dependabot-preview[bot] 84eb39fde2 build(deps): bump image-size from 0.9.1 to 0.9.2 (#12711)
Bumps [image-size](https://github.com/image-size/image-size) from 0.9.1 to 0.9.2.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](https://github.com/image-size/image-size/compare/v0.9.1...v0.9.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-10-26 10:20:06 +01:00
Matteo Pagliazzi d6fe2c76e2 build(deps): bump got from 11.7.0 to 11.8.0 (#12710)
Bumps [got](https://github.com/sindresorhus/got) from 11.7.0 to 11.8.0.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.7.0...v11.8.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-10-26 10:19:47 +01:00
dependabot-preview[bot] f19e9dd57e build(deps): bump rate-limiter-flexible from 2.1.10 to 2.1.13 (#12709)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.1.10 to 2.1.13.
- [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-10-26 10:19:33 +01:00
dependabot-preview[bot] 13566e8a39 build(deps): bump got from 11.7.0 to 11.8.0
Bumps [got](https://github.com/sindresorhus/got) from 11.7.0 to 11.8.0.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.7.0...v11.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-26 07:27:39 +00:00
Melior 7d3dd9f157 Translated using Weblate (Spanish (Latin America))
Currently translated at 85.3% (613 of 718 strings)

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

Translated using Weblate (Portuguese (Brazil))

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

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

Translated using Weblate (Czech)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Hindi)

Currently translated at 46.8% (52 of 111 strings)

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

Translated using Weblate (Polish)

Currently translated at 97.0% (130 of 134 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Hindi)

Currently translated at 40.5% (45 of 111 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (203 of 203 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (230 of 230 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (61 of 61 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (181 of 181 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.3% (60 of 61 strings)

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

Translated using Weblate (German)

Currently translated at 96.7% (59 of 61 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (English (Pirate))

Currently translated at 81.9% (1788 of 2183 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/en@pirate/
2020-10-22 20:50:10 +02:00
Sabe Jones 92f283f6a2 4.166.1 2020-10-22 13:42:55 -05:00
Melior 5d24d584d4 Merge branch 'develop' of github.com:HabitRPG/habitica into develop 2020-10-20 21:28:02 +02:00
Sabe Jones 0320827f7e Merge branch 'release' into develop 2020-10-20 14:13:00 -05:00
Yowi faa49b1412 Translated using Weblate (Spanish (Latin America))
Currently translated at 85.3% (613 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/
2020-10-20 15:42:19 +02:00
Atticus c3decc3951 Translated using Weblate (Swedish)
Currently translated at 81.8% (144 of 176 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/sv/
2020-10-20 15:42:16 +02:00
blacksheep47 084adf8b0d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (13 of 13 strings)

Translation: Habitica/Rebirth
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hans/
2020-10-20 15:42:16 +02:00
Atticus 04574dad69 Translated using Weblate (Swedish)
Currently translated at 91.8% (518 of 564 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/sv/
2020-10-20 15:42:15 +02:00
Atticus 6526a6317e Translated using Weblate (Swedish)
Currently translated at 93.3% (168 of 180 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/sv/
2020-10-20 15:42:14 +02:00
Andrew Webb c778e5e84e 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/
2020-10-20 03:22:16 +02:00
Quartz Fox b5dacdf9ea Translated using Weblate (English (Pirate))
Currently translated at 100.0% (8 of 8 strings)

Translation: Habitica/Overview
Translate-URL: https://translate.habitica.com/projects/habitica/overview/en@pirate/
2020-10-20 03:22:15 +02:00
Lio Zam e05d1dae43 Translated using Weblate (German)
Currently translated at 100.0% (2183 of 2183 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
2020-10-20 03:22:15 +02:00
Quartz Fox 864db644e3 Translated using Weblate (English (Pirate))
Currently translated at 97.8% (91 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@pirate/
2020-10-20 03:22:11 +02:00
Andrew Webb 5ddd4ec564 Translated using Weblate (English (Pirate))
Currently translated at 97.8% (91 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@pirate/
2020-10-20 03:22:11 +02:00
Anonymous 2d7d4af2b8 Translated using Weblate (English (Pirate))
Currently translated at 97.8% (91 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@pirate/
2020-10-20 03:22:11 +02:00
negue bad3f82dfb Inventory: fixes / layout (#11948)
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2020-10-19 23:54:51 +02:00
Atticus 8595641d12 Translated using Weblate (Swedish)
Currently translated at 78.9% (139 of 176 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/sv/
2020-10-19 23:20:45 +02:00
Lio Zam 9bb3e17995 Translated using Weblate (Swedish)
Currently translated at 98.3% (121 of 123 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/sv/
2020-10-19 23:20:44 +02:00
Atticus 1d7e02428b Translated using Weblate (Swedish)
Currently translated at 78.9% (139 of 176 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/sv/
2020-10-19 21:35:14 +02:00
Atticus eee04255f8 Translated using Weblate (Swedish)
Currently translated at 85.8% (158 of 184 strings)

Translation: Habitica/Limited
Translate-URL: https://translate.habitica.com/projects/habitica/limited/sv/
2020-10-19 21:35:13 +02:00
Atticus 7f30385c09 Translated using Weblate (Swedish)
Currently translated at 78.9% (139 of 176 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/sv/
2020-10-19 20:21:27 +02:00
Atticus 5b6eeef290 Translated using Weblate (Swedish)
Currently translated at 91.1% (113 of 124 strings)

Translation: Habitica/Npc
Translate-URL: https://translate.habitica.com/projects/habitica/npc/sv/
2020-10-19 20:21:27 +02:00
Atticus 9953c9346d Translated using Weblate (Swedish)
Currently translated at 73.1% (68 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sv/
2020-10-19 20:21:26 +02:00
Matteo Pagliazzi d62930b9da Merge branch 'release' into develop 2020-10-19 16:54:35 +02:00
Atticus 093bcbb715 Translated using Weblate (Swedish)
Currently translated at 78.4% (138 of 176 strings)

Translation: Habitica/Subscriber
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/sv/
2020-10-19 16:38:44 +02:00
Atticus 1f5992ccc5 Translated using Weblate (Swedish)
Currently translated at 67.9% (125 of 184 strings)

Translation: Habitica/Limited
Translate-URL: https://translate.habitica.com/projects/habitica/limited/sv/
2020-10-19 16:38:44 +02:00
Atticus 2d598c9933 Translated using Weblate (Swedish)
Currently translated at 82.2% (1796 of 2183 strings)

Translation: Habitica/Gear
Translate-URL: https://translate.habitica.com/projects/habitica/gear/sv/
2020-10-19 16:38:43 +02:00
Atticus b4be8286e2 Translated using Weblate (Swedish)
Currently translated at 91.1% (514 of 564 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/sv/
2020-10-19 16:38:40 +02:00
Yowi 96b985a191 Translated using Weblate (Spanish (Latin America))
Currently translated at 85.3% (613 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es_419/
2020-10-19 13:51:18 +02:00
sou osu a196a0cae2 Translated using Weblate (Japanese)
Currently translated at 95.9% (689 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
2020-10-19 13:51:17 +02:00
Tereza F 8f9043e4f1 Translated using Weblate (Czech)
Currently translated at 100.0% (564 of 564 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/cs/
2020-10-19 13:51:12 +02:00
Matteo Pagliazzi 1cace198a1 Merge branch 'release' into develop 2020-10-19 12:30:52 +02:00
Matteo Pagliazzi 0275636f46 new users: do not show bailey news (#12693) 2020-10-19 12:13:31 +02:00
dependabot-preview[bot] ea7ae4bb2f build(deps): bump bootstrap-vue from 2.17.3 to 2.18.0 in /website/client (#12691)
Bumps [bootstrap-vue](https://github.com/bootstrap-vue/bootstrap-vue) from 2.17.3 to 2.18.0.
- [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.17.3...v2.18.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-10-19 12:09:48 +02:00
dependabot-preview[bot] 9f32a879e3 build(deps): bump @babel/preset-env from 7.11.5 to 7.12.1 (#12684)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.11.5 to 7.12.1.
- [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.1/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-10-19 12:07:46 +02:00
dependabot-preview[bot] 665200b49d build(deps): bump vue-router from 3.4.6 to 3.4.7 in /website/client (#12692)
Bumps [vue-router](https://github.com/vuejs/vue-router) from 3.4.6 to 3.4.7.
- [Release notes](https://github.com/vuejs/vue-router/releases)
- [Changelog](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-router/compare/v3.4.6...v3.4.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-10-19 12:06:45 +02:00
dependabot-preview[bot] c63e92c8f2 build(deps): bump bootstrap from 4.5.2 to 4.5.3 in /website/client (#12689)
Bumps [bootstrap](https://github.com/twbs/bootstrap) from 4.5.2 to 4.5.3.
- [Release notes](https://github.com/twbs/bootstrap/releases)
- [Commits](https://github.com/twbs/bootstrap/compare/v4.5.2...v4.5.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-19 12:06:11 +02:00
dependabot-preview[bot] ba5b79855f build(deps): bump vuedraggable from 2.24.1 to 2.24.2 in /website/client (#12686)
Bumps [vuedraggable](https://github.com/SortableJS/Vue.Draggable) from 2.24.1 to 2.24.2.
- [Release notes](https://github.com/SortableJS/Vue.Draggable/releases)
- [Commits](https://github.com/SortableJS/Vue.Draggable/commits/v2.24.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-10-19 12:05:51 +02:00
dependabot-preview[bot] 97051bb3ae build(deps): bump amplitude-js from 7.2.2 to 7.3.0 in /website/client (#12687)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 7.2.2 to 7.3.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.2.2...v7.3.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-10-19 12:04:59 +02:00
dependabot-preview[bot] 29e3cae0a6 build(deps): bump @babel/register from 7.11.5 to 7.12.1 (#12683)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.11.5 to 7.12.1.
- [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.1/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-10-19 12:04:44 +02:00
dependabot-preview[bot] 274c582af8 build(deps): bump @babel/core from 7.11.6 to 7.12.3 (#12681)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.11.6 to 7.12.3.
- [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.3/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-10-19 12:04:33 +02:00
sou osu 4a7f40ea37 Translated using Weblate (Japanese)
Currently translated at 95.6% (687 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
2020-10-19 11:09:21 +02:00
Lio Zam 97ad0fae26 Translated using Weblate (German)
Currently translated at 100.0% (718 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/
2020-10-19 11:09:19 +02:00
Tereza F b7b91caef1 Translated using Weblate (Czech)
Currently translated at 100.0% (564 of 564 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/cs/
2020-10-19 11:09:16 +02:00
Matteo Pagliazzi daa3458760 Merge branch 'release' into develop 2020-10-19 01:30:00 +02:00
Matteo Pagliazzi 2cfc765e39 Merge branch 'release' into develop 2020-10-18 19:16:25 +02:00
sou osu 7cd9f800cc Translated using Weblate (Japanese)
Currently translated at 95.4% (685 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
2020-10-18 14:19:17 +02:00
Lio Zam 9a1cadd49f Translated using Weblate (German)
Currently translated at 100.0% (564 of 564 strings)

Translation: Habitica/Backgrounds
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
2020-10-18 14:19:14 +02:00
Melior b3285db5b0 Translated using Weblate (Spanish (Latin America))
Currently translated at 100.0% (364 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 86.8% (1896 of 2183 strings)

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

Translated using Weblate (Spanish)

Currently translated at 93.1% (669 of 718 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.6% (359 of 364 strings)

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

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% (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% (56 of 56 strings)

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

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 100.0% (176 of 176 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (86 of 86 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (111 of 111 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (124 of 124 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (8 of 8 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (184 of 184 strings)

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

Translated using Weblate (Japanese)

Currently translated at 88.3% (1929 of 2183 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (298 of 298 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (328 of 328 strings)

Translation: Habitica/Front
Translate-URL: https://translate.habitica.com/projects/habitica/front/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 (German)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Spanish)

Currently translated at 93.0% (668 of 718 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (123 of 123 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (47 of 47 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (363 of 363 strings)

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

Translated using Weblate (Czech)

Currently translated at 97.1% (548 of 564 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (93 of 93 strings)

Translation: Habitica/Achievements
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
2020-10-18 00:26:47 +02:00
Alys 8b1c009990 fix "push to bottom" for user tasks in API (#12659)
Also:
- Fix the test for this which has been equally broken.
- Simplify apidoc position info and make consistent in similar routes.
- Replace non-ascii characters in apidoc comment.
2020-10-17 17:58:48 +02:00
RaitheOfDureya 9061a59fc2 Removed unused I18N strings from the challenges.json files (related to issue #9957) (#12639)
* Removed unused I18N strings from the `challenges.json` file (locales\en)

* Removed unused I18N `challenge.json` strings from all other languages

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-10-17 17:40:57 +02:00
RaitheOfDureya cbfed9c0d3 Removed unused I18N strings from the character.json files (related to issue #9957) (#12635)
* Removed unused I18N strings from the `character.json` file (locales\en)

* Removed unused I18N `character.json` strings from the other languages

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-10-17 17:40:24 +02:00
RaitheOfDureya 77447f7096 Removed unused I18N strings from the achievements.json files (related to issue #9957) (#12658)
* Removed unused I18N string from the `achievements.json` file (locales\en)

* Removed unused I18N `achievements.json` strings from the other languages
2020-10-17 17:39:33 +02:00
RaitheOfDureya 361bb92b3b Removed unused I18N front.json strings from all the languages (#12604) 2020-10-17 17:39:13 +02:00
RaitheOfDureya e50d5f514c Removed unused I18N strings from the generic.json files (related to issue #9957) (#12590)
* Removed unused I18N strings from the `generic.json` file (locales\en)

* Removed unused I18N `generic.json` strings from all the other languages

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
2020-10-17 17:38:21 +02:00
Matteo Pagliazzi a7ac4633a8 Merge branch 'release' into develop 2020-10-16 19:58:24 +02:00
Matteo Pagliazzi 31b53fd6ed Merge branch 'release' into develop 2020-10-16 19:51:54 +02:00
Melior 3e31223812 Translated using Weblate (Spanish)
Currently translated at 98.2% (55 of 56 strings)

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

Translated using Weblate (Spanish)

Currently translated at 99.4% (179 of 180 strings)

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

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Spanish)

Currently translated at 99.4% (175 of 176 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.6% (359 of 364 strings)

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

Translated using Weblate (Spanish)

Currently translated at 85.7% (151 of 176 strings)

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

Translated using Weblate (Spanish)

Currently translated at 95.3% (538 of 564 strings)

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

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.6% (359 of 364 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (718 of 718 strings)

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

Translated using Weblate (Czech)

Currently translated at 100.0% (56 of 56 strings)

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

Translated using Weblate (Japanese)

Currently translated at 100.0% (175 of 175 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/it/

Translated using Weblate (Italian)

Currently translated at 100.0% (718 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/it/

Translated using Weblate (Czech)

Currently translated at 100.0% (180 of 180 strings)

Translation: Habitica/Settings
Translate-URL: https://translate.habitica.com/projects/habitica/settings/cs/

Translated using Weblate (Basque)

Currently translated at 100.0% (2 of 2 strings)

Translation: Habitica/Noscript
Translate-URL: https://translate.habitica.com/projects/habitica/noscript/eu/

Translated using Weblate (Basque)

Currently translated at 6.5% (8 of 123 strings)

Translation: Habitica/Communityguidelines
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/eu/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/zh_Hans/

Translated using Weblate (Japanese)

Currently translated at 100.0% (56 of 56 strings)

Translation: Habitica/Messages
Translate-URL: https://translate.habitica.com/projects/habitica/messages/ja/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (718 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (718 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (717 of 718 strings)

Translation: Habitica/Questscontent
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/
2020-10-15 22:29:31 +02:00
1151 changed files with 42948 additions and 54777 deletions
+1 -2
View File
@@ -1,2 +1 @@
https://github.com/heroku/heroku-buildpack-nodejs.git
https://github.com/stomita/heroku-buildpack-phantomjs.git
https://github.com/heroku/heroku-buildpack-nodejs.git
+9 -9
View File
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
@@ -49,7 +49,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
@@ -71,7 +71,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
@@ -92,7 +92,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
@@ -114,7 +114,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
mongodb-version: [4.2]
steps:
- uses: actions/checkout@v1
@@ -143,7 +143,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
mongodb-version: [4.2]
steps:
- uses: actions/checkout@v1
@@ -172,7 +172,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
mongodb-version: [4.2]
steps:
- uses: actions/checkout@v1
@@ -202,7 +202,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v1
with:
+1 -1
View File
@@ -1 +1 @@
12
14
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:12
FROM node:14
ENV ADMIN_EMAIL admin@habitica.com
ENV EMAILS_COMMUNITY_MANAGER_EMAIL admin@habitica.com
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:12
FROM node:14
# Install global packages
RUN npm install -g gulp-cli mocha
+1
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",
@@ -0,0 +1,84 @@
/*
* Award Habitoween ladder items to participants in this month's Habitoween festivities
*/
/* eslint-disable no-console */
const MIGRATION_NAME = '20201029_habitoween_ladder'; // Update when running in future years
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {};
const inc = {
'items.food.Candy_Skeleton': 1,
'items.food.Candy_Base': 1,
'items.food.Candy_CottonCandyBlue': 1,
'items.food.Candy_CottonCandyPink': 1,
'items.food.Candy_Shade': 1,
'items.food.Candy_White': 1,
'items.food.Candy_Golden': 1,
'items.food.Candy_Zombie': 1,
'items.food.Candy_Desert': 1,
'items.food.Candy_Red': 1,
};
set.migration = MIGRATION_NAME;
if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Glow']) {
set['items.pets.JackOLantern-RoyalPurple'] = 5;
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Glow']) {
set['items.mounts.JackOLantern-Glow'] = true;
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Ghost']) {
set['items.pets.JackOLantern-Glow'] = 5;
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Ghost']) {
set['items.mounts.JackOLantern-Ghost'] = true;
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Base']) {
set['items.pets.JackOLantern-Ghost'] = 5;
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Base']) {
set['items.mounts.JackOLantern-Base'] = true;
} else {
set['items.pets.JackOLantern-Base'] = 5;
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set}).exec();
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2020-10-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
}
};
@@ -0,0 +1,58 @@
/*
* Fix JackOLantern-Base for users that signed up recently
*/
/* eslint-disable no-console */
const MIGRATION_NAME = '20201102_fix_habitoween'; // Update when running in future years
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {};
set.migration = MIGRATION_NAME;
set['items.pets.JackOLantern-Base'] = 5;
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set}).exec();
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.created': {$gt: new Date('2020-10-26')},
'items.pets.JackOLantern-Base': true,
};
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
}
};
@@ -0,0 +1,62 @@
/*
* All web users should be enrolled in the Drop Cap AB Test
*/
/* eslint-disable no-console */
const MIGRATION_NAME = '20201103_drop_cap_ab_tweaks';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {};
set.migration = MIGRATION_NAME;
const testGroup = Math.random();
// Enroll 100% of users, splitting them 50/50
const value = testGroup <= 0.50 ? 'drop-cap-notif-enabled' : 'drop-cap-notif-disabled';
set['_ABtests.dropCapNotif'] = value;
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$set: set}).exec();
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2020-10-10')},
'_ABtests.dropCapNotif': 'drop-cap-notif-not-enrolled',
};
const fields = {
_id: 1,
_ABtests: 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
}
};
@@ -0,0 +1,82 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20201124_pet_color_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['Wolf-Red'] > 0
&& pets['TigerCub-Red'] > 0
&& pets['PandaCub-Red'] > 0
&& pets['LionCub-Red'] > 0
&& pets['Fox-Red'] > 0
&& pets['FlyingPig-Red'] > 0
&& pets['Dragon-Red'] > 0
&& pets['Cactus-Red'] > 0
&& pets['BearCub-Red'] > 0) {
set['achievements.seeingRed'] = true;
}
}
if (user && user.items && user.items.mounts) {
const mounts = user.items.mounts;
if (mounts['Wolf-Red']
&& mounts['TigerCub-Red']
&& mounts['PandaCub-Red']
&& mounts['LionCub-Red']
&& mounts['Fox-Red']
&& mounts['FlyingPig-Red']
&& mounts['Dragon-Red']
&& mounts['Cactus-Red']
&& mounts['BearCub-Red'] ) {
set['achievements.redLetterDay'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
module.exports = async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2020-11-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
}
};
@@ -0,0 +1,126 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20201126_harvest_feast';
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 set = {};
let inc;
let push;
set.migration = MIGRATION_NAME;
if (typeof user.items.gear.owned.head_special_turkeyHelmGilded !== 'undefined') {
inc = {
'items.food.Pie_Base': 1,
'items.food.Pie_CottonCandyBlue': 1,
'items.food.Pie_CottonCandyPink': 1,
'items.food.Pie_Desert': 1,
'items.food.Pie_Golden': 1,
'items.food.Pie_Red': 1,
'items.food.Pie_Shade': 1,
'items.food.Pie_Skeleton': 1,
'items.food.Pie_Zombie': 1,
'items.food.Pie_White': 1,
}
} else if (typeof user.items.gear.owned.armor_special_turkeyArmorBase !== 'undefined') {
set['items.gear.owned.head_special_turkeyHelmGilded'] = false;
set['items.gear.owned.armor_special_turkeyArmorGilded'] = false;
set['items.gear.owned.back_special_turkeyTailGilded'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_turkeyHelmGilded',
_id: uuid(),
},
{
type: 'marketGear',
path: 'gear.flat.armor_special_turkeyArmorGilded',
_id: uuid(),
},
{
type: 'marketGear',
path: 'gear.flat.back_special_turkeyTailGilded',
_id: uuid(),
},
];
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Gilded']) {
set['items.gear.owned.head_special_turkeyHelmBase'] = false;
set['items.gear.owned.armor_special_turkeyArmorBase'] = false;
set['items.gear.owned.back_special_turkeyTailBase'] = false;
push = [
{
type: 'marketGear',
path: 'gear.flat.head_special_turkeyHelmBase',
_id: uuid(),
},
{
type: 'marketGear',
path: 'gear.flat.armor_special_turkeyArmorBase',
_id: uuid(),
},
{
type: 'marketGear',
path: 'gear.flat.back_special_turkeyTailBase',
_id: uuid(),
},
];
} else if (user.items && user.items.pets && user.items.pets['Turkey-Gilded']) {
set['items.mounts.Turkey-Gilded'] = true;
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Base']) {
set['items.pets.Turkey-Gilded'] = 5;
} else if (user.items && user.items.pets && user.items.pets['Turkey-Base']) {
set['items.mounts.Turkey-Base'] = true;
} else {
set['items.pets.Turkey-Base'] = 5;
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
if (inc) {
return await User.update({_id: user._id}, {$inc: inc, $set: set}).exec();
} else if (push) {
return await User.update({_id: user._id}, {$set: set, $push: {pinnedItems: {$each: push}}}).exec();
} else {
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('2019-11-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
}
};
+809 -957
View File
File diff suppressed because it is too large Load Diff
+21 -21
View File
@@ -1,26 +1,26 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.166.0",
"version": "4.174.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@babel/register": "^7.11.5",
"@babel/core": "^7.12.9",
"@babel/preset-env": "^7.12.7",
"@babel/register": "^7.12.1",
"@google-cloud/trace-agent": "^5.1.1",
"@slack/client": "^4.12.0",
"@slack/webhook": "^5.0.3",
"@parse/node-apn": "^4.0.0",
"accepts": "^1.3.5",
"amazon-payments": "^0.2.8",
"amplitude": "^3.5.0",
"amplitude": "^5.1.4",
"apidoc": "^0.25.0",
"apn": "^2.2.0",
"apple-auth": "^1.0.6",
"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.1",
"csv-stringify": "^5.5.3",
"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.7.0",
"got": "^11.8.0",
"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": "^3.23.3",
"image-size": "^0.9.1",
"helmet": "^4.2.0",
"image-size": "^0.9.3",
"in-app-purchase": "^1.11.3",
"js2xmlparser": "^4.0.1",
"jsonwebtoken": "^8.5.1",
"jwks-rsa": "^1.10.1",
"jwks-rsa": "^1.11.0",
"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.9",
"mongoose": "^5.10.18",
"morgan": "^1.10.0",
"nconf": "^0.10.0",
"nconf": "^0.11.0",
"node-gcm": "^1.0.3",
"on-headers": "^1.0.2",
"passport": "^0.4.1",
@@ -60,13 +60,13 @@
"paypal-rest-sdk": "^1.8.1",
"pp-ipn": "^1.1.0",
"ps-tree": "^1.0.0",
"rate-limiter-flexible": "^2.1.10",
"rate-limiter-flexible": "^2.1.13",
"redis": "^3.0.2",
"regenerator-runtime": "^0.13.7",
"remove-markdown": "^0.3.0",
"rimraf": "^3.0.2",
"short-uuid": "^3.0.0",
"stripe": "^7.15.0",
"short-uuid": "^4.1.0",
"stripe": "^8.121.0",
"superagent": "^6.1.0",
"universal-analytics": "^0.4.23",
"useragent": "^2.1.9",
@@ -79,7 +79,7 @@
},
"private": true,
"engines": {
"node": "^12",
"node": "^14",
"npm": "^6"
},
"scripts": {
@@ -109,7 +109,7 @@
"apidoc": "gulp apidoc"
},
"devDependencies": {
"axios": "^0.19.2",
"axios": "^0.21.0",
"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.6.2",
"sinon": "^9.2.0",
"run-rs": "^0.7.3",
"sinon": "^9.2.1",
"sinon-chai": "^3.5.0",
"sinon-stub-promise": "^4.0.0"
},
@@ -1,4 +1,5 @@
/* eslint-disable camelcase */
import nconf from 'nconf';
import Amplitude from 'amplitude';
import { Visitor } from 'universal-analytics';
import * as analyticsService from '../../../../website/server/libs/analyticsService';
@@ -15,6 +16,22 @@ describe('analyticsService', () => {
sandbox.restore();
});
describe('#getServiceByEnvironment', () => {
it('returns mock methods when not in production', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(false);
expect(analyticsService.getAnalyticsServiceByEnvironment())
.to.equal(analyticsService.mockAnalyticsService);
});
it('returns real methods when in production', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
expect(analyticsService.getAnalyticsServiceByEnvironment().track)
.to.equal(analyticsService.track);
expect(analyticsService.getAnalyticsServiceByEnvironment().trackPurchase)
.to.equal(analyticsService.trackPurchase);
});
});
describe('#track', () => {
let eventType; let
data;
@@ -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);
+8 -1
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,
+53 -1
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;
});
});
});
+9 -1
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, {
@@ -22,7 +22,9 @@ describe('Purchasing a group plan for group', () => {
let plan; let group; let user; let
data;
const stripe = stripeModule('test');
const stripe = stripeModule('test', {
apiVersion: '2020-08-27',
});
const groupLeaderName = 'sender';
const groupName = 'test group';
+6 -6
View File
@@ -32,8 +32,8 @@ describe('payments/index', () => {
sandbox.stub(sender, 'sendTxn');
sandbox.stub(user, 'sendMessage');
sandbox.stub(analytics, 'trackPurchase');
sandbox.stub(analytics, 'track');
sandbox.stub(analytics.mockAnalyticsService, 'trackPurchase');
sandbox.stub(analytics.mockAnalyticsService, 'track');
sandbox.stub(notifications, 'sendNotification');
data = {
@@ -237,8 +237,8 @@ describe('payments/index', () => {
it('tracks subscription purchase as gift', async () => {
await api.createSubscription(data);
expect(analytics.trackPurchase).to.be.calledOnce;
expect(analytics.trackPurchase).to.be.calledWith({
expect(analytics.mockAnalyticsService.trackPurchase).to.be.calledOnce;
expect(analytics.mockAnalyticsService.trackPurchase).to.be.calledWith({
uuid: user._id,
groupId: undefined,
itemPurchased: 'Subscription',
@@ -335,8 +335,8 @@ describe('payments/index', () => {
it('tracks subscription purchase', async () => {
await api.createSubscription(data);
expect(analytics.trackPurchase).to.be.calledOnce;
expect(analytics.trackPurchase).to.be.calledWith({
expect(analytics.mockAnalyticsService.trackPurchase).to.be.calledOnce;
expect(analytics.mockAnalyticsService.trackPurchase).to.be.calledWith({
uuid: user._id,
groupId: undefined,
itemPurchased: 'Subscription',
@@ -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'));
@@ -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,
});
});
});
});
@@ -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,
});
});
});
@@ -1,235 +1,484 @@
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';
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];
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();
token = 'test-token';
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({});
describe('Stripe - Checkout', () => {
const stripe = stripeModule('test', {
apiVersion: '2020-08-27',
});
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`,
};
afterEach(() => {
stripe.charges.create.restore();
payments.buyGems.restore();
payments.createSubscription.restore();
});
describe('createCheckoutSession', () => {
let user;
const sessionId = 'session-id';
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',
beforeEach(() => {
user = new User();
sandbox.stub(stripe.checkout.sessions, 'create').returns(sessionId);
sandbox.stub(gems, 'validateGiftMessage');
});
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,
});
});
});
});
});
@@ -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 },
);
});
});
});
@@ -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,
});
});
});
});
});
@@ -0,0 +1,442 @@
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', {
apiVersion: '2020-08-27',
});
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', {
apiVersion: '2020-08-27',
});
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', {
apiVersion: '2020-08-27',
});
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,
});
});
});
});
});
@@ -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);
});
});
@@ -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,104 @@ 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 stripe = stripeModule('test', {
apiVersion: '2020-08-27',
});
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({
constructEventStub.returns({
id: 123,
type: eventType,
request: 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: {
@@ -93,7 +121,7 @@ describe('Stripe - Webhooks', () => {
request: 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 +130,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 +140,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: {
@@ -128,7 +154,7 @@ describe('Stripe - Webhooks', () => {
request: 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 +165,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: {
@@ -161,7 +185,7 @@ describe('Stripe - Webhooks', () => {
request: 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 +194,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 +209,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: {
@@ -201,7 +223,7 @@ describe('Stripe - Webhooks', () => {
request: 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 +232,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 +250,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: {
@@ -244,7 +264,7 @@ describe('Stripe - Webhooks', () => {
request: 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 +275,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);
});
});
});
+1 -1
View File
@@ -1,4 +1,4 @@
import apn from 'apn/mock';
import apn from '@parse/node-apn/mock';
import _ from 'lodash';
import nconf from 'nconf';
import gcmLib from 'node-gcm'; // works with FCM notifications too
+3 -2
View File
@@ -1,5 +1,5 @@
/* eslint-disable camelcase */
import { IncomingWebhook } from '@slack/client';
import { IncomingWebhook } from '@slack/webhook';
import requireAgain from 'require-again';
import nconf from 'nconf';
import moment from 'moment';
@@ -12,7 +12,7 @@ describe('slack', () => {
let data;
beforeEach(() => {
sandbox.stub(IncomingWebhook.prototype, 'send');
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
data = {
authorEmail: 'author@example.com',
flagger: {
@@ -112,6 +112,7 @@ describe('slack', () => {
it('noops if no flagging url is provided', () => {
sandbox.stub(nconf, 'get').withArgs('SLACK_FLAGGING_URL').returns('');
nconf.get.withArgs('IS_TEST').returns(true);
sandbox.stub(logger, 'error');
const reRequiredSlack = requireAgain('../../../../website/server/libs/slack');
+5
View File
@@ -8,5 +8,10 @@ describe('stringUtils', () => {
const matches = getMatchesByWordArray(message, bannedWords);
expect(matches.length).to.equal(bannedWords.length);
});
it('doesn\'t flag names with accented characters', () => {
const name = 'TESTPLACEHOLDERSWEARWORDHEREé';
const matches = getMatchesByWordArray(name, bannedWords);
expect(matches.length).to.equal(0);
});
});
});
+4 -21
View File
@@ -311,25 +311,8 @@ describe('cron middleware', () => {
});
});
it('does not enroll 50% of users', async () => {
sandbox.stub(Math, 'random').returns(0.6);
user.lastCron = moment(new Date()).subtract({ days: 2 });
await user.save();
req.headers['x-client'] = 'habitica-web';
await new Promise((resolve, reject) => {
cronMiddleware(req, res, async err => {
if (err) return reject(err);
user = await User.findById(user._id).exec();
expect(user._ABtests.dropCapNotif).to.be.equal('drop-cap-notif-not-enrolled');
return resolve();
});
});
});
it('enables the new notification for 25% of users', async () => {
sandbox.stub(Math, 'random').returns(0.25);
it('enables the new notification for 50% of users', async () => {
sandbox.stub(Math, 'random').returns(0.5);
user.lastCron = moment(new Date()).subtract({ days: 2 });
await user.save();
req.headers['x-client'] = 'habitica-web';
@@ -345,8 +328,8 @@ describe('cron middleware', () => {
});
});
it('disables the new notification for 25% of users', async () => {
sandbox.stub(Math, 'random').returns(0.5);
it('disables the new notification for 50% of users', async () => {
sandbox.stub(Math, 'random').returns(0.51);
user.lastCron = moment(new Date()).subtract({ days: 2 });
await user.save();
req.headers['x-client'] = 'habitica-web';
@@ -0,0 +1,19 @@
import {
generateUser,
requester,
} from '../../../../helpers/api-integration/v3';
import { mockAnalyticsService as analytics } from '../../../../../website/server/libs/analyticsService';
describe('POST /analytics/track/:eventName', () => {
it('calls res.analytics', async () => {
const user = await generateUser();
sandbox.spy(analytics, 'track');
const requestWithHeaders = requester(user, { 'x-client': 'habitica-web' });
await requestWithHeaders.post('/analytics/track/eventName', { data: 'example' }, { 'x-client': 'habitica-web' });
expect(analytics.track).to.be.calledOnce;
expect(analytics.track).to.be.calledWith('eventName', sandbox.match({ data: 'example' }));
sandbox.restore();
});
});
@@ -117,26 +117,7 @@ describe('GET /challenges/:challengeId/members', () => {
expect(res[0].profile).to.have.all.keys(['name']);
});
it('returns only first 30 members if req.query.includeAllMembers is not true and req.query.limit is undefined', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
const usersToGenerate = [];
for (let i = 0; i < 31; i += 1) {
usersToGenerate.push(generateUser({ challenges: [challenge._id] }));
}
await Promise.all(usersToGenerate);
const res = await user.get(`/challenges/${challenge._id}/members?includeAllMembers=not-true`);
expect(res.length).to.equal(30);
res.forEach(member => {
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
expect(member.profile).to.have.all.keys(['name']);
});
});
it('returns only first 30 members if req.query.includeAllMembers is not defined and req.query.limit is undefined', async () => {
it('returns only first 30 members if req.query.limit is undefined', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
@@ -217,25 +198,6 @@ describe('GET /challenges/:challengeId/members', () => {
});
}).timeout(30000);
it('returns all members if req.query.includeAllMembers is true', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
const usersToGenerate = [];
for (let i = 0; i < 31; i += 1) {
usersToGenerate.push(generateUser({ challenges: [challenge._id] }));
}
await Promise.all(usersToGenerate);
const res = await user.get(`/challenges/${challenge._id}/members?includeAllMembers=true`);
expect(res.length).to.equal(32);
res.forEach(member => {
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
expect(member.profile).to.have.all.keys(['name']);
});
});
it('supports using req.query.lastId to get more members', async function test () {
this.timeout(30000); // @TODO: times out after 8 seconds
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
@@ -259,6 +221,34 @@ describe('GET /challenges/:challengeId/members', () => {
expect(resIds).to.eql(expectedIds.sort());
});
it('supports using req.query.includeTasks in order to add challenge-related tasks of all members', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
const usersToGenerate = [];
for (let i = 0; i < 8; i += 1) {
usersToGenerate.push(generateUser({ challenges: [challenge._id] }));
}
await Promise.all(usersToGenerate);
await user.post(`/tasks/challenge/${challenge._id}`, [{ type: 'habit', text: 'Some task' }]);
await user.post(`/tasks/challenge/${challenge._id}`, [{ type: 'daily', text: 'Some different task' }]);
const res = await user.get(`/challenges/${challenge._id}/members?includeTasks=true`);
expect(res.length).to.equal(9);
res.forEach(member => {
expect(member).to.have.property('tasks');
expect(member.tasks).to.be.an('array');
expect(member.tasks).to.have.lengthOf(2);
member.tasks.forEach(task => {
expect(task).to.include.all.keys(['type', 'value', 'priority', 'text', '_id', 'userId']);
expect(task).to.not.have.any.keys(['tags', 'checklist']);
expect(task.challenge.id).to.be.equal(challenge._id);
expect(task.userId).to.be.equal(member._id);
});
});
});
it('supports using req.query.search to get search members', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);
@@ -116,7 +116,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
}]);
const memberProgress = await user.get(`/challenges/${challenge._id}/members/${user._id}`);
expect(memberProgress.tasks[0]).not.to.have.key('tags');
expect(memberProgress.tasks[0].checklist).to.eql([]);
expect(memberProgress.tasks[0]).to.not.have.any.keys(['tags', 'checklist']);
});
});
@@ -56,7 +56,7 @@ describe('GET challenges/user', () => {
});
context('all challenges', () => {
it('should return challenges user has joined', async () => {
const challenges = await nonMember.get('/challenges/user');
const challenges = await nonMember.get('/challenges/user?page=0');
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.exist;
@@ -65,14 +65,14 @@ describe('GET challenges/user', () => {
});
it('should not return challenges a non-member has not joined', async () => {
const challenges = await nonMember.get('/challenges/user');
const challenges = await nonMember.get('/challenges/user?page=0');
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.not.exist;
});
it('should return challenges user has created', async () => {
const challenges = await user.get('/challenges/user');
const challenges = await user.get('/challenges/user?page=0');
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
@@ -85,7 +85,7 @@ describe('GET challenges/user', () => {
});
it('should return challenges in user\'s group', async () => {
const challenges = await member.get('/challenges/user');
const challenges = await member.get('/challenges/user?page=0');
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
@@ -98,7 +98,7 @@ describe('GET challenges/user', () => {
});
it('should return newest challenges first', async () => {
let challenges = await user.get('/challenges/user');
let challenges = await user.get('/challenges/user?page=0');
let foundChallengeIndex = _.findIndex(challenges, { _id: challenge2._id });
expect(foundChallengeIndex).to.eql(0);
@@ -106,7 +106,7 @@ describe('GET challenges/user', () => {
const newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user');
challenges = await user.get('/challenges/user?page=0');
foundChallengeIndex = _.findIndex(challenges, { _id: newChallenge._id });
expect(foundChallengeIndex).to.eql(0);
@@ -125,7 +125,7 @@ describe('GET challenges/user', () => {
const privateChallenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
const challenges = await nonMember.get('/challenges/user');
const challenges = await nonMember.get('/challenges/user?page=0');
const foundChallenge = _.find(challenges, { _id: privateChallenge._id });
expect(foundChallenge).to.not.exist;
@@ -149,7 +149,7 @@ describe('GET challenges/user', () => {
});
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
const challenges = await nonMember.get('/challenges/user?categories=academics&owned=not_owned');
const challenges = await nonMember.get('/challenges/user?page=0&categories=academics&owned=not_owned');
const foundChallenge = _.find(challenges, { _id: privateChallenge._id });
expect(foundChallenge).to.not.exist;
@@ -158,7 +158,7 @@ describe('GET challenges/user', () => {
context('my challenges', () => {
it('should return challenges user has joined', async () => {
const challenges = await nonMember.get(`/challenges/user?member=${true}`);
const challenges = await nonMember.get(`/challenges/user?page=0&member=${true}`);
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.exist;
@@ -167,7 +167,7 @@ describe('GET challenges/user', () => {
});
it('should return challenges user has created', async () => {
const challenges = await user.get(`/challenges/user?member=${true}`);
const challenges = await user.get(`/challenges/user?page=0&member=${true}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
@@ -180,7 +180,7 @@ describe('GET challenges/user', () => {
});
it('should return challenges user has created if filter by owned', async () => {
const challenges = await user.get(`/challenges/user?member=${true}&owned=owned`);
const challenges = await user.get(`/challenges/user?member=${true}&owned=owned&page=0`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
@@ -193,7 +193,7 @@ describe('GET challenges/user', () => {
});
it('should not return challenges user has created if filter by not owned', async () => {
const challenges = await user.get(`/challenges/user?owned=not_owned&member=${true}`);
const challenges = await user.get(`/challenges/user?page=0&owned=not_owned&member=${true}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.not.exist;
@@ -202,7 +202,7 @@ describe('GET challenges/user', () => {
});
it('should not return challenges in user groups', async () => {
const challenges = await member.get(`/challenges/user?member=${true}`);
const challenges = await member.get(`/challenges/user?page=0&member=${true}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.not.exist;
@@ -253,7 +253,7 @@ describe('GET challenges/user', () => {
});
it('should return official challenges first', async () => {
const challenges = await user.get('/challenges/user');
const challenges = await user.get('/challenges/user?page=0');
const foundChallengeIndex = _.findIndex(challenges, { _id: officialChallenge._id });
expect(foundChallengeIndex).to.eql(0);
@@ -274,7 +274,7 @@ describe('GET challenges/user', () => {
const newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user');
challenges = await user.get('/challenges/user?page=0');
const foundChallengeIndex = _.findIndex(challenges, { _id: newChallenge._id });
expect(foundChallengeIndex).to.eql(1);
@@ -314,18 +314,12 @@ describe('GET challenges/user', () => {
it('returns public guilds filtered by category', async () => {
const categoryChallenge = await generateChallenge(user, guild, { categories });
await user.post(`/challenges/${categoryChallenge._id}/join`);
const challenges = await user.get(`/challenges/user?categories=${categories[0].slug}`);
const challenges = await user.get(`/challenges/user?page=0&categories=${categories[0].slug}`);
expect(challenges[0]._id).to.eql(categoryChallenge._id);
expect(challenges.length).to.eql(1);
});
it('does not page challenges if page parameter is absent', async () => {
const challenges = await user.get('/challenges/user');
expect(challenges.length).to.be.above(11);
});
it('paginates challenges', async () => {
const challenges = await user.get('/challenges/user?page=0');
const challengesPaged = await user.get('/challenges/user?page=1&owned=owned');
@@ -335,7 +329,7 @@ describe('GET challenges/user', () => {
});
it('filters by owned', async () => {
const challenges = await member.get('/challenges/user?owned=owned');
const challenges = await member.get('/challenges/user?page=0&owned=owned');
expect(challenges.length).to.eql(0);
});
@@ -103,7 +103,15 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
await expect(winningUser.sync()).to.eventually.have.nested.property('achievements.challenges').to.include(challenge.name);
// 2 because winningUser just joined the challenge, which now awards an achievement
expect(winningUser.notifications.length).to.equal(2);
expect(winningUser.notifications[1].type).to.equal('WON_CHALLENGE');
const notif = winningUser.notifications[1];
expect(notif.type).to.equal('WON_CHALLENGE');
expect(notif.data).to.eql({
id: challenge._id,
name: challenge.name,
prize: challenge.prize,
leader: challenge.leader,
});
});
it('gives winner gems as reward', async () => {
@@ -1,7 +1,7 @@
import { find } from 'lodash';
import moment from 'moment';
import nconf from 'nconf';
import { IncomingWebhook } from '@slack/client';
import { IncomingWebhook } from '@slack/webhook';
import {
generateUser,
translate as t,
@@ -20,7 +20,7 @@ describe('POST /chat/:chatId/flag', () => {
admin = await generateUser({ balance: 1, 'contributor.admin': true });
anotherUser = await generateUser({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
newUser = await generateUser({ 'auth.timestamps.created': moment().subtract(1, 'days').toDate() });
sandbox.stub(IncomingWebhook.prototype, 'send');
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
group = await user.post('/groups', {
name: 'Test Guild',
@@ -1,4 +1,4 @@
import { IncomingWebhook } from '@slack/client';
import { IncomingWebhook } from '@slack/webhook';
import nconf from 'nconf';
import { v4 as generateUUID } from 'uuid';
import {
@@ -133,7 +133,7 @@ describe('POST /chat', () => {
describe('shadow-mute user', () => {
beforeEach(() => {
sandbox.spy(email, 'sendTxn');
sandbox.stub(IncomingWebhook.prototype, 'send');
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
});
afterEach(() => {
@@ -355,7 +355,7 @@ describe('POST /chat', () => {
context('banned slur', () => {
beforeEach(() => {
sandbox.spy(email, 'sendTxn');
sandbox.stub(IncomingWebhook.prototype, 'send');
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
});
afterEach(() => {
@@ -251,6 +251,29 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
expect(party.quest.members[partyMember._id]).to.not.exist;
});
it('prevents user from being removed if they are the quest owner', async () => {
const petQuest = 'whale';
await partyMember.update({
[`items.quests.${petQuest}`]: 1,
});
await partyMember.post(`/groups/${party._id}/quests/invite/${petQuest}`);
await partyLeader.post(`/groups/${party._id}/quests/accept`);
await party.sync();
expect(party.quest.members[partyLeader._id]).to.be.true;
expect(party.quest.members[partyMember._id]).to.be.true;
await party.sync();
expect(leader.post(`/groups/${party._id}/removeMember/${partyMember._id}`))
.to.eventually.be.rejected.and.eql({
code: 401,
text: t('cannotRemoveQuestOwner'),
});
});
it('sends email to user with rescinded invite', async () => {
await partyLeader.post(`/groups/${party._id}/removeMember/${partyInvitedUser._id}`);
@@ -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);
});
});
@@ -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);
});
});
});
@@ -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);
});
});
@@ -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;
});
});
@@ -83,22 +83,6 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
});
});
it('does not issue invites if the user is of insufficient Level', async () => {
const LEVELED_QUEST = 'atom1';
const LEVELED_QUEST_REQ = questScrolls[LEVELED_QUEST].lvl;
const leaderUpdate = {};
leaderUpdate[`items.quests.${LEVELED_QUEST}`] = 1;
leaderUpdate['stats.lvl'] = LEVELED_QUEST_REQ - 1;
await leader.update(leaderUpdate);
await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${LEVELED_QUEST}`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('questLevelTooHigh', { level: LEVELED_QUEST_REQ }),
});
});
it('does not issue invites if a quest is already underway', async () => {
const QUEST_IN_PROGRESS = 'atom1';
const leaderUpdate = {};
@@ -212,6 +196,18 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
expect(returnedGroup.chat[0]._meta).to.be.undefined;
});
it('successfully issues a quest invitation when quest level is higher than user level', async () => {
const LEVELED_QUEST = 'atom1';
const LEVELED_QUEST_REQ = questScrolls[LEVELED_QUEST].lvl;
const leaderUpdate = {};
leaderUpdate[`items.quests.${LEVELED_QUEST}`] = 1;
leaderUpdate['stats.lvl'] = LEVELED_QUEST_REQ - 1;
await leader.update(leaderUpdate);
await leader.post(`/groups/${questingGroup._id}/quests/invite/${LEVELED_QUEST}`);
});
context('sending quest activity webhooks', () => {
before(async () => {
await server.start();
@@ -91,7 +91,9 @@ describe('POST /tasks/:taskId/move/to/:position', () => {
const taskToMove = tasks[1];
expect(taskToMove.text).to.equal('habit 2');
const newOrder = await user.post(`/tasks/${tasks[1]._id}/move/to/-1`);
await user.post(`/tasks/${tasks[1]._id}/move/to/-1`);
await user.sync();
const newOrder = user.tasksOrder.habits;
expect(newOrder[4]).to.equal(taskToMove._id);
expect(newOrder.length).to.equal(5);
});
@@ -0,0 +1,52 @@
import {
generateUser,
} from '../../../helpers/api-integration/v4';
import { UNEQUIP_EQUIPPED } from '../../../../website/common/script/ops/unequip';
describe('POST /user/unequip', () => {
let user;
beforeEach(async () => {
user = await generateUser({
preferences: {
background: 'violet',
},
items: {
currentMount: 'BearCub-Base',
currentPet: 'BearCub-Base',
gear: {
owned: {
weapon_warrior_0: true,
weapon_warrior_1: true,
weapon_warrior_2: true,
weapon_wizard_1: true,
weapon_wizard_2: true,
shield_base_0: true,
shield_warrior_1: true,
},
equipped: {
weapon: 'weapon_warrior_2',
shield: 'shield_warrior_1',
},
costume: {
weapon: 'weapon_warrior_2',
shield: 'shield_warrior_1',
},
},
},
stats: { gp: 200 },
});
});
// More tests in common code unit tests
context('Gear', () => {
it('should unequip all battle gear items', async () => {
await user.post(`/user/unequip/${UNEQUIP_EQUIPPED}`);
await user.sync();
expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0');
expect(user.items.gear.equipped.shield).to.eq('shield_base_0');
});
});
});
+100
View File
@@ -0,0 +1,100 @@
/* eslint-disable camelcase */
import {
generateUser,
} from '../../helpers/common.helper';
import {
UNEQUIP_ALL,
UNEQUIP_BACKGROUND,
UNEQUIP_COSTUME,
UNEQUIP_EQUIPPED,
UNEQUIP_PET_MOUNT,
unEquipByType,
} from '../../../website/common/script/ops/unequip';
describe('shared.ops.unequip', () => {
let user;
beforeEach(() => {
user = generateUser({
preferences: {
background: 'violet',
},
items: {
currentMount: 'BearCub-Base',
currentPet: 'BearCub-Base',
gear: {
owned: {
weapon_warrior_0: true,
weapon_warrior_1: true,
weapon_warrior_2: true,
weapon_wizard_1: true,
weapon_wizard_2: true,
shield_base_0: true,
shield_warrior_1: true,
},
equipped: {
weapon: 'weapon_warrior_2',
shield: 'shield_warrior_1',
},
costume: {
weapon: 'weapon_warrior_2',
shield: 'shield_warrior_1',
},
},
},
stats: { gp: 200 },
});
});
context('Gear', () => {
it('should unequip all battle gear items', () => {
unEquipByType(user, { params: { type: UNEQUIP_EQUIPPED } });
expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0');
expect(user.items.gear.equipped.shield).to.eq('shield_base_0');
});
});
context('Costume', () => {
it('should unequip all costume items', () => {
unEquipByType(user, { params: { type: UNEQUIP_COSTUME } });
expect(user.items.gear.costume.weapon).to.eq('weapon_base_0');
expect(user.items.gear.costume.shield).to.eq('shield_base_0');
});
});
context('Pet and Mount', () => {
it('should unequip Pet and Mount', () => {
unEquipByType(user, { params: { type: UNEQUIP_PET_MOUNT } });
expect(user.items.currentMount).to.eq('');
expect(user.items.currentPet).to.eq('');
});
});
context('Background', () => {
it('should unequip Background', () => {
unEquipByType(user, { params: { type: UNEQUIP_BACKGROUND } });
expect(user.preferences.background).to.eq('');
});
});
context('All Items', () => {
it('should unequip all Items', () => {
unEquipByType(user, { params: { type: UNEQUIP_ALL } });
expect(user.items.gear.equipped.weapon).to.eq('weapon_base_0');
expect(user.items.gear.equipped.shield).to.eq('shield_base_0');
expect(user.items.gear.costume.weapon).to.eq('weapon_base_0');
expect(user.items.gear.costume.shield).to.eq('shield_base_0');
expect(user.items.currentMount).to.eq('');
expect(user.items.currentPet).to.eq('');
expect(user.preferences.background).to.eq('');
});
});
});
@@ -41,6 +41,7 @@ function _requestMaker (user, method, additionalSets = {}) {
|| route.indexOf('/amazon') === 0
|| route.indexOf('/stripe') === 0
|| route.indexOf('/qr-code') === 0
|| route.indexOf('/analytics') === 0
) {
url += `${route}`;
} else {
@@ -50,4 +50,5 @@ function loadStories () {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
+1015 -1016
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -18,20 +18,20 @@
"@storybook/addon-links": "^5.3.19",
"@storybook/addon-notes": "^5.3.21",
"@storybook/vue": "^5.3.19",
"@vue/cli-plugin-babel": "^4.5.7",
"@vue/cli-plugin-eslint": "^4.5.7",
"@vue/cli-plugin-router": "^4.5.7",
"@vue/cli-plugin-unit-mocha": "^4.5.7",
"@vue/cli-service": "^4.5.7",
"@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",
"@vue/test-utils": "1.0.0-beta.29",
"amplitude-js": "^7.2.2",
"axios": "^0.19.2",
"amplitude-js": "^7.3.3",
"axios": "^0.21.0",
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.1.0",
"bootstrap": "^4.5.2",
"bootstrap-vue": "^2.17.3",
"bootstrap": "^4.5.3",
"bootstrap-vue": "^2.19.0",
"chai": "^4.1.2",
"core-js": "^3.6.5",
"core-js": "^3.8.0",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
"eslint-plugin-mocha": "^5.3.0",
@@ -43,8 +43,8 @@
"jquery": "^3.5.1",
"lodash": "^4.17.20",
"moment": "^2.29.1",
"nconf": "^0.10.0",
"sass": "^1.27.0",
"nconf": "^0.11.0",
"sass": "^1.29.0",
"sass-loader": "^8.0.2",
"smartbanner.js": "^1.16.0",
"svg-inline-loader": "^0.8.2",
@@ -56,9 +56,9 @@
"vue": "^2.6.12",
"vue-cli-plugin-storybook": "^0.6.1",
"vue-mugen-scroll": "^0.2.6",
"vue-router": "^3.4.6",
"vue-router": "^3.4.9",
"vue-template-compiler": "^2.6.12",
"vuedraggable": "^2.24.1",
"vuedraggable": "^2.24.3",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0",
"webpack": "^4.44.2"
}
+4 -3
View File
@@ -38,7 +38,7 @@
<template v-else>
<template v-if="isUserLoaded">
<damage-paused-banner />
<gems-promo-banner />
<!-- <gems-promo-banner /> -->
<notifications-display />
<app-menu />
<div
@@ -153,7 +153,7 @@ import { loadProgressBar } from 'axios-progress-bar';
import AppMenu from './components/header/menu';
import AppHeader from './components/header/index';
import DamagePausedBanner from './components/header/banners/damagePaused';
import GemsPromoBanner from './components/header/banners/gemsPromo';
// import GemsPromoBanner from './components/header/banners/gemsPromo';
import AppFooter from './components/appFooter';
import notificationsDisplay from './components/notifications';
import snackbars from './components/snackbars/notifications';
@@ -184,7 +184,7 @@ export default {
AppHeader,
AppFooter,
DamagePausedBanner,
GemsPromoBanner,
// GemsPromoBanner,
notificationsDisplay,
snackbars,
BuyModal,
@@ -540,5 +540,6 @@ export default {
<style src="@/assets/css/sprites/spritesmith-main-26.css"></style>
<style src="@/assets/css/sprites/spritesmith-main-27.css"></style>
<style src="@/assets/css/sprites/spritesmith-main-28.css"></style>
<style src="@/assets/css/sprites/spritesmith-main-29.css"></style>
<style src="@/assets/css/sprites.css"></style>
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
@@ -1,486 +1,498 @@
.achievement-alien {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1568px -1628px;
background-position: -1659px -1480px;
width: 24px;
height: 26px;
}
.achievement-alien2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -622px -1549px;
background-position: -480px -1549px;
width: 48px;
height: 52px;
}
.achievement-allThatGlitters2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -954px -1480px;
background-position: -812px -1480px;
width: 64px;
height: 56px;
}
.achievement-allYourBase2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1019px -1480px;
background-position: -877px -1480px;
width: 64px;
height: 56px;
}
.achievement-alpha2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -671px -1549px;
background-position: -529px -1549px;
width: 48px;
height: 52px;
}
.achievement-aridAuthority2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1084px -1480px;
background-position: -942px -1480px;
width: 64px;
height: 56px;
}
.achievement-armor2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -720px -1549px;
background-position: -578px -1549px;
width: 48px;
height: 52px;
}
.achievement-backToBasics2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1344px -1480px;
background-position: -1267px -1480px;
width: 48px;
height: 56px;
}
.achievement-bareNecessities2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1480px;
background-position: -284px -1480px;
width: 68px;
height: 68px;
}
.achievement-bewilder2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -769px -1549px;
background-position: -627px -1549px;
width: 48px;
height: 52px;
}
.achievement-birthday2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -818px -1549px;
background-position: -676px -1549px;
width: 48px;
height: 52px;
}
.achievement-boneCollector2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1393px -1480px;
background-position: -1316px -1480px;
width: 48px;
height: 56px;
}
.achievement-boot2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -867px -1549px;
background-position: -725px -1549px;
width: 48px;
height: 52px;
}
.achievement-bow2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -916px -1549px;
background-position: -774px -1549px;
width: 48px;
height: 52px;
}
.achievement-bugBonanza2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -771px -1480px;
background-position: -629px -1480px;
width: 60px;
height: 64px;
}
.achievement-burnout2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -965px -1549px;
background-position: -823px -1549px;
width: 48px;
height: 52px;
}
.achievement-cactus2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1014px -1549px;
background-position: -872px -1549px;
width: 48px;
height: 52px;
}
.achievement-cake2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1063px -1549px;
background-position: -921px -1549px;
width: 48px;
height: 52px;
}
.achievement-cave2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1112px -1549px;
background-position: -970px -1549px;
width: 48px;
height: 52px;
}
.achievement-challenge2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1161px -1549px;
background-position: -1019px -1549px;
width: 48px;
height: 52px;
}
.achievement-comment2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1210px -1549px;
background-position: -1068px -1549px;
width: 48px;
height: 52px;
}
.achievement-completedTask2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1442px -1480px;
background-position: -1365px -1480px;
width: 48px;
height: 56px;
}
.achievement-congrats2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1259px -1549px;
background-position: -1117px -1549px;
width: 48px;
height: 52px;
}
.achievement-costumeContest2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1308px -1549px;
background-position: -1166px -1549px;
width: 48px;
height: 52px;
}
.achievement-createdTask2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1491px -1480px;
background-position: -1414px -1480px;
width: 48px;
height: 56px;
}
.achievement-dilatory2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1357px -1549px;
background-position: -1215px -1549px;
width: 48px;
height: 52px;
}
.achievement-dustDevil2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1540px -1480px;
background-position: -1463px -1480px;
width: 48px;
height: 56px;
}
.achievement-dysheartener2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1406px -1549px;
background-position: -1264px -1549px;
width: 48px;
height: 52px;
}
.achievement-fedPet2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1589px -1480px;
background-position: -1512px -1480px;
width: 48px;
height: 56px;
}
.achievement-freshwaterFriends2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -495px -1480px;
background-position: -353px -1480px;
width: 68px;
height: 68px;
}
.achievement-friends2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1455px -1549px;
background-position: -1313px -1549px;
width: 48px;
height: 52px;
}
.achievement-getwell2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1504px -1549px;
background-position: -1362px -1549px;
width: 48px;
height: 52px;
}
.achievement-goodAsGold2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1638px -1480px;
background-position: -1561px -1480px;
width: 48px;
height: 56px;
}
.achievement-goodluck2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1553px -1549px;
background-position: -1411px -1549px;
width: 48px;
height: 52px;
}
.achievement-greeting2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1602px -1549px;
background-position: -1460px -1549px;
width: 48px;
height: 52px;
}
.achievement-guild2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1651px -1549px;
background-position: -1509px -1549px;
width: 48px;
height: 52px;
}
.achievement-habitBirthday2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1628px;
background-position: -1558px -1549px;
width: 48px;
height: 52px;
}
.achievement-habiticaDay2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -49px -1628px;
background-position: -1607px -1549px;
width: 48px;
height: 52px;
}
.achievement-hatchedPet2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1549px;
background-position: -1610px -1480px;
width: 48px;
height: 56px;
}
.achievement-heart2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -98px -1628px;
background-position: 0px -1628px;
width: 48px;
height: 52px;
}
.achievement-justAddWater2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -832px -1480px;
background-position: -690px -1480px;
width: 60px;
height: 64px;
}
.achievement-karaoke-2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -147px -1628px;
background-position: -49px -1628px;
width: 48px;
height: 52px;
}
.achievement-karaoke {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1593px -1628px;
background-position: -1659px -1507px;
width: 24px;
height: 26px;
}
.achievement-kickstarter20192x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -564px -1480px;
background-position: -422px -1480px;
width: 68px;
height: 68px;
}
.achievement-lostMasterclasser2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -196px -1628px;
background-position: -98px -1628px;
width: 48px;
height: 52px;
}
.achievement-mindOverMatter2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -893px -1480px;
background-position: -751px -1480px;
width: 60px;
height: 64px;
}
.achievement-monsterMagus2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -475px -1549px;
background-position: -284px -1549px;
width: 48px;
height: 56px;
}
.achievement-ninja2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -245px -1628px;
background-position: -147px -1628px;
width: 48px;
height: 52px;
}
.achievement-npc2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -294px -1628px;
background-position: -196px -1628px;
width: 48px;
height: 52px;
}
.achievement-nye2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -343px -1628px;
background-position: -245px -1628px;
width: 48px;
height: 52px;
}
.achievement-partyOn2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -392px -1628px;
background-position: -294px -1628px;
width: 48px;
height: 52px;
}
.achievement-partyUp2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -441px -1628px;
background-position: -343px -1628px;
width: 48px;
height: 52px;
}
.achievement-pearlyPro2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1149px -1480px;
background-position: -1007px -1480px;
width: 64px;
height: 56px;
}
.achievement-perfect2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -490px -1628px;
background-position: -392px -1628px;
width: 48px;
height: 52px;
}
.achievement-primedForPainting2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -524px -1549px;
background-position: -333px -1549px;
width: 48px;
height: 56px;
}
.achievement-purchasedEquipment2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -573px -1549px;
background-position: -382px -1549px;
width: 48px;
height: 56px;
}
.achievement-rat2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -539px -1628px;
background-position: -441px -1628px;
width: 48px;
height: 52px;
}
.achievement-redLetterDay2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1072px -1480px;
width: 64px;
height: 56px;
}
.achievement-rosyOutlook2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -633px -1480px;
background-position: -491px -1480px;
width: 68px;
height: 68px;
}
.achievement-royally-loyal2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -588px -1628px;
background-position: -490px -1628px;
width: 48px;
height: 52px;
}
.achievement-seafoam2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -637px -1628px;
background-position: -539px -1628px;
width: 48px;
height: 52px;
}
.achievement-seeingRed2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -431px -1549px;
width: 48px;
height: 56px;
}
.achievement-shield2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -686px -1628px;
background-position: -588px -1628px;
width: 48px;
height: 52px;
}
.achievement-shinySeed2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -735px -1628px;
background-position: -637px -1628px;
width: 48px;
height: 52px;
}
.achievement-skeletonCrew2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1214px -1480px;
background-position: -1137px -1480px;
width: 64px;
height: 56px;
}
.achievement-snowball2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -784px -1628px;
background-position: -686px -1628px;
width: 48px;
height: 52px;
}
.achievement-spookySparkles2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -833px -1628px;
background-position: -735px -1628px;
width: 48px;
height: 52px;
}
.achievement-stoikalm2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -882px -1628px;
background-position: -784px -1628px;
width: 48px;
height: 52px;
}
.achievement-sun2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -931px -1628px;
background-position: -833px -1628px;
width: 48px;
height: 52px;
}
.achievement-sword2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -980px -1628px;
background-position: -882px -1628px;
width: 48px;
height: 52px;
}
.achievement-thankyou2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1029px -1628px;
background-position: -931px -1628px;
width: 48px;
height: 52px;
}
.achievement-thermometer2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1078px -1628px;
background-position: -980px -1628px;
width: 48px;
height: 52px;
}
.achievement-tickledPink2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -702px -1480px;
background-position: -560px -1480px;
width: 68px;
height: 68px;
}
.achievement-tree2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1127px -1628px;
background-position: -1029px -1628px;
width: 48px;
height: 52px;
}
.achievement-triadbingo2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1176px -1628px;
background-position: -1078px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-healer2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1225px -1628px;
background-position: -1127px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-mage2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1274px -1628px;
background-position: -1176px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-rogue2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1323px -1628px;
background-position: -1225px -1628px;
width: 48px;
height: 52px;
}
.achievement-ultimate-warrior2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1372px -1628px;
background-position: -1274px -1628px;
width: 48px;
height: 52px;
}
.achievement-undeadUndertaker2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1279px -1480px;
background-position: -1202px -1480px;
width: 64px;
height: 56px;
}
.achievement-unearned2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1421px -1628px;
background-position: -1323px -1628px;
width: 48px;
height: 52px;
}
.achievement-valentine2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1470px -1628px;
background-position: -1372px -1628px;
width: 48px;
height: 52px;
}
.achievement-wolf2x {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1519px -1628px;
background-position: -1421px -1628px;
width: 48px;
height: 52px;
}
@@ -1084,165 +1096,159 @@
width: 141px;
height: 147px;
}
.background_glowing_mushroom_cave {
.background_gingerbread_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -888px;
width: 141px;
height: 147px;
}
.background_gorgeous_greenhouse {
.background_glowing_mushroom_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1036px;
width: 141px;
height: 147px;
}
.background_grand_staircase {
.background_gorgeous_greenhouse {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1184px;
width: 141px;
height: 147px;
}
.background_graveyard {
.background_grand_staircase {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1332px;
width: 141px;
height: 147px;
}
.background_green {
.background_graveyard {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -142px -1332px;
width: 141px;
height: 147px;
}
.background_guardian_statues {
.background_green {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -284px -1332px;
width: 141px;
height: 147px;
}
.background_gumdrop_land {
.background_guardian_statues {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -426px -1332px;
width: 141px;
height: 147px;
}
.background_habit_city_rooftops {
.background_gumdrop_land {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -568px -1332px;
width: 141px;
height: 147px;
}
.background_habit_city_streets {
.background_habit_city_rooftops {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -710px -1332px;
width: 141px;
height: 147px;
}
.background_halflings_house {
.background_habit_city_streets {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -852px -1332px;
width: 141px;
height: 147px;
}
.background_hall_of_heroes {
.background_halflings_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -994px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_feast {
.background_hall_of_heroes {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1136px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_fields {
.background_harvest_feast {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1278px -1332px;
width: 141px;
height: 147px;
}
.background_harvest_moon {
.background_harvest_fields {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1420px -1332px;
width: 141px;
height: 147px;
}
.background_haunted_forest {
.background_harvest_moon {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px 0px;
width: 141px;
height: 147px;
}
.background_haunted_house {
.background_haunted_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -148px;
width: 141px;
height: 147px;
}
.background_heather_field {
.background_haunted_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -296px;
width: 141px;
height: 147px;
}
.background_herding_sheep_in_autumn {
.background_heather_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -444px;
width: 141px;
height: 147px;
}
.background_holiday_market {
.background_herding_sheep_in_autumn {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -592px;
width: 141px;
height: 147px;
}
.background_holiday_wreath {
.background_holiday_hearth {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -740px;
width: 141px;
height: 147px;
}
.background_hot_air_balloon {
.background_holiday_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -888px;
width: 141px;
height: 147px;
}
.background_ice_cave {
.background_holiday_wreath {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1036px;
width: 141px;
height: 147px;
}
.background_iceberg {
.background_hot_air_balloon {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1184px;
width: 141px;
height: 147px;
}
.background_idyllic_cabin {
.background_ice_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -1562px -1332px;
width: 141px;
height: 147px;
}
.background_in_a_classroom {
.background_iceberg {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: 0px -1480px;
width: 141px;
height: 147px;
}
.background_in_an_ancient_tomb {
.background_idyllic_cabin {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -142px -1480px;
width: 141px;
height: 147px;
}
.background_island_waterfalls {
background-image: url('~@/assets/images/sprites/spritesmith-main-0.png');
background-position: -284px -1480px;
width: 141px;
height: 147px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,738 @@
.Pet-Velociraptor-CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px 0px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Desert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px 0px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Golden {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px 0px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Red {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -100px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Shade {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -100px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Skeleton {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -100px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-White {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px 0px;
width: 81px;
height: 99px;
}
.Pet-Velociraptor-Zombie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -100px;
width: 81px;
height: 99px;
}
.Pet-Whale-Base {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -200px;
width: 81px;
height: 99px;
}
.Pet-Whale-CottonCandyBlue {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -200px;
width: 81px;
height: 99px;
}
.Pet-Whale-CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -200px;
width: 81px;
height: 99px;
}
.Pet-Whale-Desert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -200px;
width: 81px;
height: 99px;
}
.Pet-Whale-Golden {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px 0px;
width: 81px;
height: 99px;
}
.Pet-Whale-Red {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -100px;
width: 81px;
height: 99px;
}
.Pet-Whale-Shade {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -200px;
width: 81px;
height: 99px;
}
.Pet-Whale-Skeleton {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -300px;
width: 81px;
height: 99px;
}
.Pet-Whale-White {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -300px;
width: 81px;
height: 99px;
}
.Pet-Whale-Zombie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Amber {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Aquatic {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Aurora {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px 0px;
width: 81px;
height: 99px;
}
.Pet-Wolf-AutumnLeaf {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -100px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Base {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -200px;
width: 81px;
height: 99px;
}
.Pet-Wolf-BirchBark {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-BlackPearl {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px 0px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Bronze {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -100px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Celestial {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -200px;
width: 81px;
height: 99px;
}
.Pet-Wolf-CottonCandyBlue {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Cupid {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Desert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Dessert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Ember {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Fairy {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Floral {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Fluorite {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px 0px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Frost {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -100px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Ghost {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -200px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Glass {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Glow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Golden {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Holly {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-IcySnow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Peppermint {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Rainbow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Red {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-RoseQuartz {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-RoyalPurple {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Ruby {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px 0px;
width: 81px;
height: 99px;
}
.Pet-Wolf-SandSculpture {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -100px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Shade {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -200px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Shadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -300px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Shimmer {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -400px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Silver {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -500px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Skeleton {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Spooky {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-StarryNight {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Sunshine {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Thunderstorm {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Turquoise {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Vampire {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Veggie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Veteran {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -656px -600px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Watery {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px 0px;
width: 81px;
height: 99px;
}
.Pet-Wolf-White {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -100px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Windup {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -200px;
width: 81px;
height: 99px;
}
.Pet-Wolf-Zombie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -300px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Base {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -400px;
width: 81px;
height: 99px;
}
.Pet-Yarn-CottonCandyBlue {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -500px;
width: 81px;
height: 99px;
}
.Pet-Yarn-CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -738px -600px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Desert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Golden {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -82px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Red {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -164px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Shade {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -246px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Skeleton {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -328px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-White {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -410px -700px;
width: 81px;
height: 99px;
}
.Pet-Yarn-Zombie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -492px -700px;
width: 81px;
height: 99px;
}
.Pet_HatchingPotion_Amber {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -574px -700px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Aquatic {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -643px -700px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Aurora {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -712px -700px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_AutumnLeaf {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px 0px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Base {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -69px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_BirchBark {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -138px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_BlackPearl {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -207px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Bronze {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -276px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Celestial {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -345px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_CottonCandyBlue {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -414px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_CottonCandyPink {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -483px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Cupid {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -552px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Desert {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -621px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Ember {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -820px -690px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Fairy {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Floral {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -69px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Fluorite {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -138px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Frost {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -207px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Ghost {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -276px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Glass {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -345px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Glow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -414px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Golden {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -483px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Holly {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -552px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_IcySnow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -621px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Peppermint {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -690px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Purple {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -759px -800px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Rainbow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px 0px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Red {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -69px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_RoseQuartz {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -138px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_RoyalPurple {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -207px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Ruby {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -276px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_SandSculpture {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -345px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Shade {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -414px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Shadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -483px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Shimmer {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -552px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Silver {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -621px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Skeleton {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -690px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Spooky {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -889px -759px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_StarryNight {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: 0px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Sunshine {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -69px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Thunderstorm {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -138px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Turquoise {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -207px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Vampire {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -276px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Watery {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -345px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_White {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -414px -869px;
width: 68px;
height: 68px;
}
.Pet_HatchingPotion_Zombie {
background-image: url('~@/assets/images/sprites/spritesmith-main-29.png');
background-position: -483px -869px;
width: 68px;
height: 68px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 KiB

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 KiB

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Some files were not shown because too many files have changed in this diff Show More