Compare commits

...

542 Commits

Author SHA1 Message Date
Sabe Jones
1a3c2f64e4 5.18.0 2024-02-08 14:50:11 -06:00
Sabe Jones
2f42422d35 Squashed commit of the following:
commit 44b1c8c7ba8b45cb682973fb89b70445d0f5c478
Merge: 489c15b7fd 4dadb64af0
Author: Sabe Jones <sabe@habitica.com>
Date:   Thu Feb 8 14:49:05 2024 -0600

    Merge branch 'release' into phillip/panel_profile

commit 489c15b7fd
Author: Phillip Thelen <phillip@habitica.com>
Date:   Wed Dec 14 13:29:32 2022 +0100

    allow profiles to be edited in admin panel

commit 1afaaf4089
Author: Phillip Thelen <phillip@habitica.com>
Date:   Wed Dec 14 12:50:47 2022 +0100

    include month for next hourglass date in admin panel
2024-02-08 14:49:37 -06:00
Phillip Thelen
4dadb64af0 Add Customizations and Achievements to admin panel (#15114)
* allow owned customizations to be edited in admin panel

* Allow subscription termination date to be edited more flexibly

* begin adding achievements to admin panel page

* better display for customizations in admin panel

* allow achievements to be modified in admin panel

* fix lint

* fix errors

* Improve how achievements, customizations and items are listed in admin panel

* fix naming

* fix lint error

* Fix issues with achievements in admin panel and add some tests

* handle some edgecases better

* Fix lint

* Fix sort/search on member selection modal (#15066)

* fix(birthday): correct birthday robe ownership check

* feat(content): add February items (#15090)

* update(content): add February 2024 items

* feat(content): add October content

* feat(content):update February Content

* feat(content): finish up February content

* fix(backgrounds): tweak consistency

* fix(strings): remove extra whitespace

* fix(event): add missing Valentine features

---------

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

* 5.17.0

* Translated using Weblate (Ukrainian)

Currently translated at 63.6% (1918 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Spanish)

Currently translated at 88.5% (2668 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Bulgarian)

Currently translated at 15.3% (21 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 88.0% (96 of 109 strings)

Translated using Weblate (Bulgarian)

Currently translated at 98.9% (187 of 189 strings)

Translated using Weblate (Bulgarian)

Currently translated at 59.8% (503 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.6% (282 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 87.7% (2643 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 87.7% (2643 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.3% (235 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 48.1% (66 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.8% (822 of 840 strings)

Deleted translation using Weblate (Chinese (Simplified) (zh_HK))

Deleted translation using Weblate (Chinese (Simplified) (zh_HK))

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Spanish)

Currently translated at 94.2% (215 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.5% (279 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 91.3% (390 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Italian)

Currently translated at 94.5% (226 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 37.9% (52 of 137 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 38.6% (53 of 137 strings)

Translated using Weblate (Italian)

Currently translated at 1.4% (2 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 56.0% (51 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Japanese)

Currently translated at 98.5% (2970 of 3013 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (424 of 427 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 63.0% (1900 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.7% (821 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2847 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 62.9% (1897 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.0% (108 of 109 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.8% (223 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2845 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 37.9% (52 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.8% (223 of 228 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.9% (148 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2845 of 3013 strings)

Translated using Weblate (Korean)

Currently translated at 2.1% (3 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1 of 1 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 60.4% (55 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Italian)

Currently translated at 98.6% (225 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Russian)

Currently translated at 18.9% (26 of 137 strings)

Translated using Weblate (Italian)

Currently translated at 93.9% (789 of 840 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Russian)

Currently translated at 75.7% (194 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.3% (147 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 59.3% (54 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Italian)

Currently translated at 98.1% (158 of 161 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Spanish)

Currently translated at 92.1% (210 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.5% (279 of 283 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.0% (2835 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 62.8% (1894 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 21.1% (29 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Spanish)

Currently translated at 78.1% (200 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.1% (816 of 840 strings)

Co-authored-by: Alberto Pesquera <dashmilel@gmail.com>
Co-authored-by: Alcatraz Huo <alrcatraz@gmail.com>
Co-authored-by: Alessandro Losi <pipipe550@hotmail.com>
Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Dimitar Kraev <dimkraeff@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Ike Osenberg <ike.osenberg@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Jerry Chen <minecjraft@qq.com>
Co-authored-by: Kedr <sergeysamori.ua@gmail.com>
Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com>
Co-authored-by: Omar Bertolla <scaram@icloud.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Roberto Tramontano <roberto.tramontano1@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Vinicius Rodrigues <suburbanizar@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: nelly <nellychopyuk@gmail.com>
Co-authored-by: tony <duzhe163908@gmail.com>
Co-authored-by: 이수진 <govl09876@naver.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/it/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/es/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/es/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/death/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/front/es/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/es/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/it/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/es/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/merch/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/es/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/noscript/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/es/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/it/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/es/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Death
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Inventory
Translation: Habitica/Limited
Translation: Habitica/Loginincentives
Translation: Habitica/Merch
Translation: Habitica/Messages
Translation: Habitica/Noscript
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks

* fix(content): fix February background release date

* 5.17.1

* chore(repo): remove duplicate file

* chore(migrations): move various files to archive
and remove erroneous comment bars

* Translated using Weblate (Portuguese)

Currently translated at 96.4% (109 of 113 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.1% (816 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (2982 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (2982 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.8% (2978 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.2% (2961 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Korean)

Currently translated at 58.0% (1748 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 92.1% (2777 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 73.7% (101 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (French)

Currently translated at 98.8% (2978 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.9% (2741 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.2% (2871 of 3013 strings)

Translated using Weblate (French)

Currently translated at 98.5% (2969 of 3013 strings)

Translated using Weblate (French)

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Spanish)

Currently translated at 32.8% (45 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (French)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2989 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.5% (2729 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.5% (2729 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.0% (2983 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.7% (2703 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.4% (2695 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.2% (2959 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.1% (2685 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Spanish)

Currently translated at 93.9% (266 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.9% (148 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 99.4% (182 of 183 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.3% (2932 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 88.0% (96 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 73.2% (189 of 258 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (837 of 840 strings)

Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Icaro <icaro.mascarenhas@outlook.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Quim Martínez Lara <quimml60@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 김경은 <kekim.lang@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/es/
Translate-URL: https://translate.habitica.com/projects/habitica/front/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks

---------

Co-authored-by: Leonardo Chappuis <40621126+leonardochappuis@users.noreply.github.com>
Co-authored-by: Sabe Jones <sabe@habitica.com>
Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Alberto Pesquera <dashmilel@gmail.com>
Co-authored-by: Alcatraz Huo <alrcatraz@gmail.com>
Co-authored-by: Alessandro Losi <pipipe550@hotmail.com>
Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Dimitar Kraev <dimkraeff@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Ike Osenberg <ike.osenberg@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Jerry Chen <minecjraft@qq.com>
Co-authored-by: Kedr <sergeysamori.ua@gmail.com>
Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com>
Co-authored-by: Omar Bertolla <scaram@icloud.com>
Co-authored-by: Roberto Tramontano <roberto.tramontano1@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Vinicius Rodrigues <suburbanizar@gmail.com>
Co-authored-by: nelly <nellychopyuk@gmail.com>
Co-authored-by: tony <duzhe163908@gmail.com>
Co-authored-by: 이수진 <govl09876@naver.com>
Co-authored-by: CuriousMagpie <eilatan@gmail.com>
Co-authored-by: Icaro <icaro.mascarenhas@outlook.com>
Co-authored-by: Quim Martínez Lara <quimml60@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: 김경은 <kekim.lang@gmail.com>
2024-02-08 14:45:07 -06:00
Sabe Jones
88611aeb80 Merge branch 'sabrecat/gmail-oneclick' into release 2024-02-08 14:33:36 -06:00
Sabe Jones
29f555ac5c Merge branch 'develop' into release 2024-02-08 14:31:06 -06:00
Weblate
49082714d7 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (3023 of 3023 strings)

Translated using Weblate (Russian)

Currently translated at 96.3% (2912 of 3023 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Russian)

Currently translated at 19.7% (27 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (377 of 377 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (377 of 377 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Russian)

Currently translated at 77.1% (199 of 258 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (3023 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.1% (2997 of 3023 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 91.4% (236 of 258 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.1% (2997 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.0% (2993 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.0% (2993 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (2991 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (229 of 229 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (282 of 282 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.7% (2986 of 3023 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (377 of 377 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (847 of 847 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Spanish)

Currently translated at 92.8% (2797 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 82.9% (214 of 258 strings)

Translated using Weblate (Spanish)

Currently translated at 92.8% (2797 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 92.8% (2797 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 92.6% (2792 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 92.3% (2784 of 3013 strings)

Co-authored-by: Alcatraz Huo <alrcatraz@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Ike Osenberg <ike.osenberg@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Valeria <dbrvvk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Loginincentives
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-02-08 21:27:44 +01:00
CuriousMagpie
5be019864f chore(git): update .gitignore 2024-02-07 17:31:58 -05:00
Sabe Jones
91795875b5 feat(email): allow unsub via POST request 2024-02-07 16:09:23 -06:00
Phillip Thelen
67a6e6f8ac Add Content Release notification type (#15101) 2024-02-06 14:06:44 -06:00
Sabe Jones
e95f1cf003 5.17.2 2024-02-06 13:58:08 -06:00
Sabe Jones
90bd743816 Merge branch 'develop' into release 2024-02-06 13:58:01 -06:00
Weblate
76e5e8c069 Translated using Weblate (Portuguese)
Currently translated at 96.4% (109 of 113 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.1% (816 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (2982 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.9% (2982 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.8% (2978 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.2% (2961 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Korean)

Currently translated at 58.0% (1748 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 92.1% (2777 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 73.7% (101 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (2951 of 3013 strings)

Translated using Weblate (French)

Currently translated at 98.8% (2978 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.9% (2741 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.2% (2871 of 3013 strings)

Translated using Weblate (French)

Currently translated at 98.5% (2969 of 3013 strings)

Translated using Weblate (French)

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Spanish)

Currently translated at 32.8% (45 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (French)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.2% (2989 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.5% (2729 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 90.5% (2729 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.0% (2983 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.7% (2703 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.4% (2695 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.2% (2959 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 89.1% (2685 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Spanish)

Currently translated at 93.9% (266 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.9% (148 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 99.4% (182 of 183 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.3% (2932 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (749 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (183 of 183 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 88.0% (96 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (258 of 258 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 73.2% (189 of 258 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (837 of 840 strings)

Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Icaro <icaro.mascarenhas@outlook.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Quim Martínez Lara <quimml60@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 김경은 <kekim.lang@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/es/
Translate-URL: https://translate.habitica.com/projects/habitica/front/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-02-06 20:57:18 +01:00
Sabe Jones
12c75b7488 Merge branch 'develop' into release 2024-02-06 11:50:47 -06:00
Sabe Jones
eed7c9aabc fix(test): no longer expect keepAlive 2024-02-05 17:27:37 -06:00
Sabe Jones
f74160c16a chore(deprecations): clean out some warnings 2024-02-05 16:50:06 -06:00
Sabe Jones
2ba74f1645 chore(migrations): move various files to archive
and remove erroneous comment bars
2024-02-05 15:34:53 -06:00
Sabe Jones
200af2cf16 chore(migrations): move various files to archive
and remove erroneous comment bars
2024-02-05 15:34:43 -06:00
negue
8b373b9283 allow liking their own message (#15117) 2024-02-05 14:55:46 -06:00
SabreCat
2fa26db93f chore(repo): remove duplicate file 2024-02-02 14:50:02 -06:00
Sabe Jones
bd5c669374 5.17.1 2024-02-01 15:34:35 -06:00
CuriousMagpie
5626991074 fix(content): fix February background release date 2024-02-01 15:43:11 -05:00
Sabe Jones
a3fd55d56e Merge branch 'develop' into release 2024-01-26 16:44:36 -06:00
Weblate
27eedaf347 Merge branch 'origin/develop' into Weblate. 2024-01-26 23:42:51 +01:00
Sabe Jones
11baeda71e 5.17.0 2024-01-26 16:35:55 -06:00
Natalie
0b5ce61555 feat(content): add February items (#15090)
* update(content): add February 2024 items

* feat(content): add October content

* feat(content):update February Content

* feat(content): finish up February content

* fix(backgrounds): tweak consistency

* fix(strings): remove extra whitespace

* fix(event): add missing Valentine features

---------

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: Sabe Jones <sabe@habitica.com>
2024-01-26 16:35:02 -06:00
Weblate
1c617d90aa Translated using Weblate (Ukrainian)
Currently translated at 63.6% (1918 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Spanish)

Currently translated at 88.5% (2668 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Bulgarian)

Currently translated at 15.3% (21 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 88.0% (96 of 109 strings)

Translated using Weblate (Bulgarian)

Currently translated at 98.9% (187 of 189 strings)

Translated using Weblate (Bulgarian)

Currently translated at 59.8% (503 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.6% (282 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 87.7% (2643 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 87.7% (2643 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.3% (235 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 48.1% (66 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.8% (822 of 840 strings)

Deleted translation using Weblate (Chinese (Simplified) (zh_HK))

Deleted translation using Weblate (Chinese (Simplified) (zh_HK))

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Spanish)

Currently translated at 94.2% (215 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.5% (279 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 91.3% (390 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Italian)

Currently translated at 94.5% (226 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 37.9% (52 of 137 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 38.6% (53 of 137 strings)

Translated using Weblate (Italian)

Currently translated at 1.4% (2 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 56.0% (51 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Japanese)

Currently translated at 98.5% (2970 of 3013 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (424 of 427 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.1% (2867 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 63.0% (1900 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.7% (821 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (283 of 283 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2847 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 62.9% (1897 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.0% (108 of 109 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.8% (223 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2845 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 37.9% (52 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.8% (223 of 228 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.9% (148 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.4% (2845 of 3013 strings)

Translated using Weblate (Korean)

Currently translated at 2.1% (3 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1 of 1 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 60.4% (55 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Italian)

Currently translated at 98.6% (225 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Russian)

Currently translated at 18.9% (26 of 137 strings)

Translated using Weblate (Italian)

Currently translated at 93.9% (789 of 840 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Russian)

Currently translated at 75.7% (194 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.3% (147 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 59.3% (54 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Italian)

Currently translated at 98.1% (158 of 161 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.2% (2841 of 3013 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.9% (748 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Spanish)

Currently translated at 92.1% (210 of 228 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.5% (279 of 283 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (427 of 427 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.0% (2835 of 3013 strings)

Translated using Weblate (Ukrainian)

Currently translated at 62.8% (1894 of 3013 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 21.1% (29 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (109 of 109 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (840 of 840 strings)

Translated using Weblate (Spanish)

Currently translated at 78.1% (200 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.1% (816 of 840 strings)

Co-authored-by: Alberto Pesquera <dashmilel@gmail.com>
Co-authored-by: Alcatraz Huo <alrcatraz@gmail.com>
Co-authored-by: Alessandro Losi <pipipe550@hotmail.com>
Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Dimitar Kraev <dimkraeff@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Ike Osenberg <ike.osenberg@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Jerry Chen <minecjraft@qq.com>
Co-authored-by: Kedr <sergeysamori.ua@gmail.com>
Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com>
Co-authored-by: Omar Bertolla <scaram@icloud.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Roberto Tramontano <roberto.tramontano1@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Vinicius Rodrigues <suburbanizar@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: nelly <nellychopyuk@gmail.com>
Co-authored-by: tony <duzhe163908@gmail.com>
Co-authored-by: 이수진 <govl09876@naver.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/it/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/es/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/content/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/es/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/death/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/front/es/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/es/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/it/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/es/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/merch/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/es/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/noscript/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/es/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/it/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/es/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Death
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Inventory
Translation: Habitica/Limited
Translation: Habitica/Loginincentives
Translation: Habitica/Merch
Translation: Habitica/Messages
Translation: Habitica/Noscript
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-01-26 21:46:26 +01:00
Sabe Jones
724c710636 fix(birthday): correct birthday robe ownership check 2024-01-23 15:08:20 -06:00
Leonardo Chappuis
6d62ecdf17 Fix sort/search on member selection modal (#15066) 2024-01-23 15:06:54 -06:00
Sabe Jones
bfe7c263cb 5.16.1 2024-01-18 15:52:21 -06:00
Sabe Jones
987b6949c9 fix(hall): mark items modified 2024-01-18 15:52:18 -06:00
Phillip Thelen
1ade4c6b3e Fix resetting account for social accounts (#15087)
* Fix resetting account for social accounts

* added integration tests

* chore(packages): reinstall modules

* only enable reset button if user typed RESET

* fix enabling reset button

---------

Co-authored-by: negue <eugen.bolz@gmail.com>
Co-authored-by: Sabe Jones <sabe@habitica.com>
2024-01-18 15:51:36 -06:00
Sabe Jones
67069b1adc 5.16.0 2024-01-16 15:40:53 -06:00
Weblate
29e4a62ba7 Merge branch 'origin/develop' into Weblate. 2024-01-16 22:34:32 +01:00
Weblate
87eb067fb5 Translated using Weblate (Spanish)
Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 89.4% (144 of 161 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 89.4% (144 of 161 strings)

Translated using Weblate (Spanish)

Currently translated at 91.0% (254 of 279 strings)

Translated using Weblate (Spanish)

Currently translated at 88.4% (2627 of 2969 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Spanish)

Currently translated at 92.3% (769 of 833 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.3% (110 of 113 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.3% (2832 of 2969 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.8% (229 of 239 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 96.9% (808 of 833 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Spanish)

Currently translated at 87.4% (2597 of 2969 strings)

Translated using Weblate (Spanish)

Currently translated at 31.3% (43 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 99.3% (160 of 161 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 13.1% (18 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 99.3% (160 of 161 strings)

Translated using Weblate (Spanish)

Currently translated at 99.3% (160 of 161 strings)

Translated using Weblate (Portuguese)

Currently translated at 20.4% (28 of 137 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (German)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (French)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (French)

Currently translated at 99.9% (2968 of 2969 strings)

Translated using Weblate (Korean)

Currently translated at 75.1% (121 of 161 strings)

Translated using Weblate (Korean)

Currently translated at 73.9% (119 of 161 strings)

Translated using Weblate (Korean)

Currently translated at 73.9% (119 of 161 strings)

Translated using Weblate (Korean)

Currently translated at 73.2% (118 of 161 strings)

Translated using Weblate (Korean)

Currently translated at 73.2% (118 of 161 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Ukrainian)

Currently translated at 58.1% (1727 of 2969 strings)

Translated using Weblate (Russian)

Currently translated at 14.5% (20 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 58.0% (1723 of 2969 strings)

Translated using Weblate (Ukrainian)

Currently translated at 57.9% (1722 of 2969 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (833 of 833 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.2% (827 of 833 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Dutch)

Currently translated at 97.3% (184 of 189 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (227 of 227 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (279 of 279 strings)

Translated using Weblate (French)

Currently translated at 100.0% (227 of 227 strings)

Translated using Weblate (French)

Currently translated at 99.9% (2968 of 2969 strings)

Translated using Weblate (French)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (2969 of 2969 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Japanese)

Currently translated at 70.8% (97 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 22.6% (31 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 67.1% (92 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (833 of 833 strings)

Translated using Weblate (Japanese)

Currently translated at 33.5% (46 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Spanish)

Currently translated at 21.1% (29 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 30.6% (42 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (French)

Currently translated at 100.0% (833 of 833 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (279 of 279 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (139 of 140 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Japanese)

Currently translated at 85.1% (218 of 256 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Japanese)

Currently translated at 98.3% (2921 of 2969 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 21.8% (30 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 18.2% (25 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 15.3% (21 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 57.4% (1707 of 2969 strings)

Translated using Weblate (Spanish)

Currently translated at 6.5% (9 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 5.1% (7 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 99.5% (225 of 226 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 2.9% (4 of 137 strings)

Translated using Weblate (French)

Currently translated at 86.8% (119 of 137 strings)

Translated using Weblate (Spanish)

Currently translated at 2.1% (3 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 7.2% (10 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 96.2% (104 of 108 strings)

Translated using Weblate (Ukrainian)

Currently translated at 57.4% (1707 of 2969 strings)

Translated using Weblate (Ukrainian)

Currently translated at 56.3% (1673 of 2969 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (French)

Currently translated at 84.6% (116 of 137 strings)

Translated using Weblate (Russian)

Currently translated at 98.3% (2911 of 2961 strings)

Translated using Weblate (French)

Currently translated at 75.9% (104 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (254 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.4% (252 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Ukrainian)

Currently translated at 55.7% (1650 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (French)

Currently translated at 74.4% (102 of 137 strings)

Translated using Weblate (French)

Currently translated at 51.8% (71 of 137 strings)

Translated using Weblate (French)

Currently translated at 48.9% (67 of 137 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 5.8% (8 of 137 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Japanese)

Currently translated at 99.5% (238 of 239 strings)

Translated using Weblate (French)

Currently translated at 43.0% (59 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 54.1% (1603 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.2% (136 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 84.6% (116 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 81.2% (2406 of 2961 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 95.5% (108 of 113 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 80.8% (2394 of 2961 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 0.7% (1 of 137 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 89.8% (97 of 108 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 62.8% (161 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (Ukrainian)

Currently translated at 83.9% (115 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (826 of 826 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.3% (110 of 113 strings)

Translated using Weblate (French)

Currently translated at 99.9% (2960 of 2961 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 4.3% (6 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Korean)

Currently translated at 48.3% (88 of 182 strings)

Translated using Weblate (Korean)

Currently translated at 75.5% (624 of 826 strings)

Translated using Weblate (Korean)

Currently translated at 53.7% (150 of 279 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Korean)

Currently translated at 65.6% (168 of 256 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.3% (157 of 158 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 87.5% (224 of 256 strings)

Translated using Weblate (French)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (French)

Currently translated at 98.7% (2923 of 2961 strings)

Translated using Weblate (French)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (French)

Currently translated at 100.0% (826 of 826 strings)

Translated using Weblate (French)

Currently translated at 100.0% (161 of 161 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.4% (154 of 158 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.8% (137 of 140 strings)

Translated using Weblate (Portuguese)

Currently translated at 7.2% (10 of 137 strings)

Translated using Weblate (German)

Currently translated at 98.5% (135 of 137 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (819 of 819 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (German)

Currently translated at 4.3% (6 of 137 strings)

Translated using Weblate (German)

Currently translated at 99.3% (157 of 158 strings)

Deleted translation using Weblate (tl_PH (generated) (tl_PH))

Deleted translation using Weblate (tl_PH (generated) (tl_PH))

Deleted translation using Weblate (no (generated) (no))

Deleted translation using Weblate (no (generated) (no))

Deleted translation using Weblate (hi (generated))

Deleted translation using Weblate (hi (generated))

Deleted translation using Weblate (fa (generated))

Deleted translation using Weblate (fa (generated))

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (158 of 158 strings)

Co-authored-by: AGM <yoartgm@gmail.com>
Co-authored-by: Alberto Pesquera <dashmilel@gmail.com>
Co-authored-by: Alcatraz Huo <alrcatraz@gmail.com>
Co-authored-by: Artem StolyROV <stolyarov11303@gmail.com>
Co-authored-by: Bruno Marvin <itsbruno42@gmail.com>
Co-authored-by: Delta S <deseji93@gmail.com>
Co-authored-by: Finrod <963505255@qq.com>
Co-authored-by: Gean Ribeiro <geanribeirok@gmail.com>
Co-authored-by: Henrique Lavezzo <hlavezzo@hey.com>
Co-authored-by: Icaro Alves Pinto <fly-too-high@hotmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Jan met de Pet <stijn.koppers@gmail.com>
Co-authored-by: Juan Esteban Marín <juanmarin690@gmail.com>
Co-authored-by: Lapin <sirocuro01@gmail.com>
Co-authored-by: Lauren Chiang <laurenrenc@gmail.com>
Co-authored-by: Lorea <loreamartinez@yahoo.es>
Co-authored-by: LucilleL <lecointrefreelancing@gmail.com>
Co-authored-by: Luã Fhelyp Pacheco Guimarães <fhelypg@gmail.com>
Co-authored-by: Maria Otonuo <mariaotonio@gmail.com>
Co-authored-by: Marius <mariusschmid11@gmail.com>
Co-authored-by: Martim Pinto Paiva <pintopaivam@gmail.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Nathan Monteiro <nathanspeeds1@outlook.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Oli Chag <sifto11@hotmail.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Rodrigo Gonçalves Braga <rgbraga@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: SunshineRain <suusykraft@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yan <1223889952@qq.com>
Co-authored-by: Yan <ariamao0802@gmail.com>
Co-authored-by: doyo <doyochoi@kaist.ac.kr>
Co-authored-by: endriw cisersa batistela correa <endriwbatistela@gmail.com>
Co-authored-by: fred4real <1487463579@qq.com>
Co-authored-by: theBlinking <lingocommonwealth@schneekatze.nl>
Co-authored-by: 張鈞崴 <qoo94230@gmail.com>
Co-authored-by: 박동훈 <creator98@naver.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/de/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/es/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/character/es/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/character/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/es/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/es/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/es/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/uk/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-01-16 22:34:23 +01:00
Phillip Thelen
f8d315ff6e Upgrade to mongoose 7 (#14971)
* remove some unused dependencies

* update mongoose version

* make common tests pass

* Make unit tests pass

* make api v3 integration tests pass

* fix lint issues

* fix issue with package-lock

* fix(lint): we don't need no .js

* fix(lint): update to latest config-habitrpg

* chore(npm): update package locks

* fix(test): replace deprecated fn

* chore(package): update eslint-habitrpg again

* fix(lint): server linting

* fix(lint): client linting

* fix(client): correct mangled common imports

* chore(npm): update package-locks

* fix(lint): punctuation, module

---------

Co-authored-by: SabreCat <sabrecat@gmail.com>
Co-authored-by: SabreCat <sabe@habitica.com>
2024-01-16 15:18:47 -06:00
Phillip Thelen
d0e4b533e3 Add new fields to admin panel (#14943)
* Add new fields to admin panel

* fix lint

* Update hall.js

* fix(plab): plab

* fix(lint): destructure assignment

* fix(subs): coerce offset to number

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2024-01-16 14:45:57 -06:00
Natalie
d6d131647a Report Post Modal Design Refresh (#14774)
* WIP(chat flags): initial commit

* WIP(chat flags): actually disabling the button

* wip(chat flags): remove duplicated code

* fix(css): target intended modal

* WIP(report post modal): fix blockquote & missing string

* WIP(report post): blockquote formatting

* fix(sanity): remove dup string

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2024-01-16 14:42:02 -06:00
Natalie
4cbc3d7664 Slur swear blocker challenges redux (#15089)
* update packages on local/origin repo

* feat(challenges): add banned words & slur blocker to challenges

* feat(challenges): slur blocker work

* feat(challenges): slur blocker

* feat(challenges): more slur blocker

* feat(challenges): even more slur blocker

* feat(challenges): swear and slur blocker

* feat(challenges): update behavior based on public/private groups

* feat(profiles): slur/swear blocker

* feat(profiles): slur/swear blocker

* feat(profiles/PMs): slur/swear blocker upgrade

* feat(slur/swear): working on it

* feat(profiles/challenges): work on profile block & slack report

* feat(slur/swear blocker): work on Profiles

* feat(slur blocker): refactoring code

* feat(slur blocker): more refactoring

* feat(slur blocker): arghhhhhh

* fix(profiles): improve profanity check logic

* fix(slack): update Slack notification to include authorEmail and remove undefined

* feat(s/s blocker): work on challenges

* feat(s/s blocker): challenge update

* feat(s/s blocker): slack notifs refinements

* feat(s/s blocker): refine slack notifs & disallow use of challenges POST API route if user is chatRevoked:true in db

* update package.json and package-lock.json

* attempt to disable create challenge button for muted users

* another attempt to disable create challenge

* block muted users from creating challenges

* CSS button fun

* fix CSS button

* refactor(css): move button style to global
Also, disable Clone button if user is chat revoked

* fix(lint): remove unused fn

* fix(challenges): handle null slur check

* fix(groups): throw notFound earlier

* fix(challenges): CSS and logic updates

* fix(lint): remove whitespace

* fix(challenges): don't disable create buttons

* fix(slack): restore broken profile flag fields

* chore(cleanup): remove comments and whitespace

* chore(cleanup): one more white space

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2024-01-16 14:22:03 -06:00
KasaHNO3
8b2e13b5fd fix(faq): add language query in FAQ store action. (#15079)
Co-authored-by: Sabe Jones <sabe@habitica.com>
2024-01-10 17:00:13 -06:00
Sabe Jones
e5b873c9aa 5.15.2 2024-01-10 15:20:49 -06:00
Sabe Jones
2e904dcda0 fix(stable): default to empty string for current animals 2024-01-10 15:19:09 -06:00
Sabe Jones
5300de834f Squashed commit of the following:
commit 4950f403782ba12e54e2254a894b608673e27621
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Jan 5 16:02:08 2024 -0600

    fix(armoire): remove unreleased items at definition time

commit b195f0c45581c81f8aec7f5ddb105f5fc5aa7767
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Jan 5 15:37:09 2024 -0600

    Revert "fix(content): filter out unreleased gear"

    This reverts commit 6f9e526d94b1e473eba37e5f40fa6b889cccff1c.

commit 6f9e526d94b1e473eba37e5f40fa6b889cccff1c
Author: SabreCat <sabrecat@gmail.com>
Date:   Thu Jan 4 16:22:39 2024 -0600

    fix(content): filter out unreleased gear
2024-01-10 15:18:36 -06:00
Sabe Jones
b7def686e9 Squashed commit of the following:
commit 83bcd07e20
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Dec 22 17:24:45 2023 -0600

    fix(profile): revert state on error

commit 6aa6278727
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Dec 22 14:37:28 2023 -0600

    fix(test): no longer care about swears in profile

commit 0882c77038
Author: SabreCat <sabe@habitica.com>
Date:   Fri Dec 22 14:15:42 2023 -0600

    fix(lint): remove unused functions

commit 9b275ef72d
Author: SabreCat <sabe@habitica.com>
Date:   Fri Dec 22 14:09:11 2023 -0600

    fix(profiles): restore reporting functionality
    Also remove unused and/or unrelated code and clean up comments

commit f4ed8c1461
Merge: da16aa9c75 f8ba191eea
Author: SabreCat <sabe@habitica.com>
Date:   Fri Dec 22 12:11:00 2023 -0600

    Merge branch 'release' into slur-swear-blocker

commit da16aa9c75
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Dec 21 13:20:28 2023 -0500

    feat(s/s blocker): challenge updates to slack

commit 51bed61c4c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Dec 19 15:36:59 2023 -0500

    feat(s/s blocker): work on challenges

commit 139cbcb21c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Dec 13 13:20:45 2023 -0500

    fix(slack): update Slack notification to include authorEmail and remove undefined

commit 805b287721
Author: SabreCat <sabe@habitica.com>
Date:   Tue Dec 12 16:35:54 2023 -0600

    fix(profiles): improve profanity check logic

commit 02ef7e8822
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Dec 12 17:22:29 2023 -0500

    feat(slur blocker): arghhhhhh

commit 949dee9b1e
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Dec 12 13:57:29 2023 -0500

    feat(slur blocker): more refactoring

commit bf953998f4
Merge: d21aa687b7 f572aa442e
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Dec 11 15:20:06 2023 -0500

    Merge branch 'release' into slur-swear-blocker

commit d21aa687b7
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Dec 7 18:00:29 2023 -0500

    feat(slur blocker): refactoring code

commit f2db90c494
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Dec 6 12:12:55 2023 -0500

    feat(slur/swear blocker): work on Profiles

commit 8f9822ffe8
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Dec 4 17:25:17 2023 -0500

    feat(profiles/challenges): work on profile block & slack report

commit bdb2e06e5e
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Dec 1 16:11:27 2023 -0500

    feat(slur/swear): working on it

commit 7277b5cad5
Merge: 24d14277ab 941f1f976c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Dec 1 15:04:46 2023 -0500

    Merge branch 'profile-slur-swear-blocker' into slur-swear-blocker

commit 941f1f976c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Nov 30 14:34:30 2023 -0500

    feat(profiles/PMs): slur/swear blocker upgrade

commit 0863017efc
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 28 16:21:21 2023 -0500

    feat(profiles): slur/swear blocker

commit e9937d864f
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 27 15:24:37 2023 -0500

    feat(profiles): slur/swear blocker

commit 24d14277ab
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 27 14:12:46 2023 -0500

    feat(challenges): update behavior based on public/private groups

commit 1251f5b6a7
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 14 16:28:29 2023 -0500

    feat(challenges): swear and slur blocker

commit a771045ca7
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 14 15:46:16 2023 -0500

    feat(challenges): even more slur blocker

commit e5e91aa78a
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 14 14:31:25 2023 -0500

    feat(challenges): more slur blocker

commit 50e824e4e3
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 13 15:12:14 2023 -0500

    feat(challenges): slur blocker

commit 315ea24ef4
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Nov 3 12:31:12 2023 -0400

    feat(challenges): slur blocker work

commit 0f742d219f
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Nov 2 16:22:31 2023 -0400

    feat(challenges): add banned words & slur blocker to challenges

commit 40d6b60ee3
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Oct 23 13:00:46 2023 -0400

    update packages on local/origin repo
2024-01-10 15:14:11 -06:00
Sabe Jones
7a2c7c5b30 Merge branch 'develop' into release 2024-01-10 14:57:42 -06:00
SabreCat
167e6b2bf1 5.15.1 2024-01-04 14:33:04 -06:00
SabreCat
9b54e4d80a fix(backgrounds): correct index of bbash 2024-01-04 14:32:47 -06:00
SabreCat
987a27ffa1 5.15.0 2023-12-29 16:07:57 -06:00
SabreCat
7fb1c9db8c Squashed commit of the following:
commit 5b2f90356b
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Dec 15 16:19:02 2023 -0600

    fix(migration): full URL

commit a2962c0d10
Author: SabreCat <sabrecat@gmail.com>
Date:   Fri Dec 15 15:57:21 2023 -0600

    feat(migration): add birthday notif

commit 9da8e39dd0
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Dec 15 12:32:25 2023 -0500

    feat(script): awards 2024 Habitica birthday robes

commit 7de6b80ee6
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Dec 14 13:11:07 2023 -0500

    feat(content): add Habitica birthday item

commit 1bb95f5867
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Dec 14 11:43:12 2023 -0500

    fix(dates): fix availability dates to canonical

commit 8e7f49f253
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Dec 14 11:37:44 2023 -0500

    feat(content): make 2024 default backgroumd, fix errors

commit acc30f044e
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Dec 13 16:53:33 2023 -0500

    feat(content): the rest of the January content

commit 6a5e45c6d0
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Dec 13 16:49:33 2023 -0500

    feat(content): January content
2023-12-29 16:07:43 -06:00
SabreCat
f66b05f707 fix(potions): use normal release date notes 2023-12-29 15:57:46 -06:00
negue
5a19c25fea Pin Habitica Eslint Config (#15057)
* Pin Habitica Eslint Config

* fix lint
2023-12-27 18:20:49 +01:00
SabreCat
f8ba191eea fix(gala): correct seasonal shop quests/spell 2023-12-19 10:07:32 -06:00
SabreCat
a03d265cd3 5.14.2 2023-12-18 15:51:02 -06:00
SabreCat
0dbd597d0b Squashed commit of the following:
commit d03bdee783deff98ee24cc211f1498525bf36c70
Merge: b31ba93233 70f5aa1f55
Author: SabreCat <sabe@habitica.com>
Date:   Mon Dec 18 15:47:29 2023 -0600

    Merge branch 'release' into sabrecat/group-task-fixes

commit b31ba93233
Author: SabreCat <sabe@habitica.com>
Date:   Tue Oct 10 12:02:41 2023 -0500

    fix(groups): missing dot path step
    Also sync assignments on unassign as well as assign

commit 8012f0294d
Author: SabreCat <sabe@habitica.com>
Date:   Tue Oct 10 11:47:59 2023 -0500

    fix(groups): use assigned keys as source of truth

commit 616b1e1486
Author: SabreCat <sabe@habitica.com>
Date:   Tue Oct 10 11:33:28 2023 -0500

    fix(groups): clean up groups to copy tasks
    Fixes #14916
2023-12-18 15:50:58 -06:00
SabreCat
b97f85fa60 5.14.1 2023-12-18 07:25:01 -06:00
SabreCat
0a06fe6d2e fix(css): white g1g1 text in buy-gems 2023-12-18 07:24:42 -06:00
SabreCat
70f5aa1f55 5.14.0 2023-12-17 19:44:18 -06:00
SabreCat
5a384d8d16 chore(subproj): update habitica-images 2023-12-17 19:37:32 -06:00
SabreCat
4fea87af8a Squashed commit of the following:
commit 0e20f421645beaf231dd607b1c1d8db62e5804e4
Author: SabreCat <sabrecat@gmail.com>
Date:   Thu Dec 14 15:40:22 2023 -0600

    fix(g1g1): don't break modal off promo season

commit ca5436d05044d256303e9c5dcdf358b64467ae66
Author: SabreCat <sabe@habitica.com>
Date:   Tue Nov 28 20:42:55 2023 -0600

    fix(lint): move import

commit 08f58318da1a06c2d94227afd3224a5571990bac
Author: SabreCat <sabe@habitica.com>
Date:   Tue Nov 28 20:26:14 2023 -0600

    fix(vue): parenthesis

commit 8701ee330365ad0615b2179b801f8e15c3109bdd
Author: SabreCat <sabe@habitica.com>
Date:   Tue Nov 28 20:09:30 2023 -0600

    fix(g1g1): dynamically display end dates
2023-12-17 19:36:45 -06:00
SabreCat
8a45f753ca Merge branch '2023-winner-funderlamb' into release
by @CuriousMagpie
2023-12-17 19:36:15 -06:00
negue
19253cd9b5 Remove Storybook files and packages (#15040) 2023-12-13 20:18:13 +01:00
Natalie
eac5e58ac7 (fix): add quest modal text horizontal padding (#15053) 2023-12-11 16:55:24 -06:00
SabreCat
3eee1a572e Merge branch 'release' into develop 2023-12-07 16:16:25 -06:00
SabreCat
f572aa442e fix(lint): merge #14942 2023-12-07 16:15:53 -06:00
SabreCat
101be5d6a6 5.13.2 2023-12-06 13:36:08 -06:00
SabreCat
1c9c9908c5 fix(dev): use working version of MongoDB on run-rs
https://github.com/vkarpov15/run-rs/issues/47
2023-12-06 13:22:11 -06:00
Phillip Thelen
916cb03a3a automatic lint fixes (#14942)
* automatic lint fixes

* rerun lint

---------

Co-authored-by: negue <eugen.bolz@gmail.com>
2023-12-04 20:37:05 +01:00
SabreCat
bb095ae296 5.13.1 2023-12-01 16:44:47 -06:00
SabreCat
97c63e2be7 fix(faq): correct duped index 2023-12-01 16:44:40 -06:00
SabreCat
b7c6ded375 5.13.0 2023-11-28 15:08:17 -06:00
Natalie
8db8a8267b feat(content): December 2023 Content (#15023)
* feat(content): add December subscriber items, backgrounds, and enchanted armoire

* feat(content): correct item slot for armoire, change release dates for testing

* fix(backgrounds): correct start date

* fix(armoire): Add canonical start date

* fix(test): only count released items

---------

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: SabreCat <sabe@habitica.com>
2023-11-28 15:01:27 -06:00
SabreCat
4b9a5472bd 5.12.2 2023-11-22 15:35:41 -06:00
SabreCat
a374add2eb Squashed commit of the following:
commit f1cf5ea5831c24059f3a18f7d0888d30eb0efbc1
Author: SabreCat <sabe@habitica.com>
Date:   Fri Nov 3 16:53:13 2023 -0500

    fix(market): show selected class correctly
2023-11-22 15:35:12 -06:00
SabreCat
592c178544 Squashed commit of the following:
commit 0928372c649ebc8d298b72692e0accca4e912637
Author: SabreCat <sabe@habitica.com>
Date:   Tue Nov 21 15:02:53 2023 -0600

    fix(news): center images
2023-11-22 15:34:46 -06:00
Natalie
ed907c1ae5 fix(dates): upgrade dynamic end dating for quest bundle endings (#15015)
* fix(quest text): Updated end date for Oddballs to November 30.

* fix(dates): remove hard-coded bundle end-dates

* fix(dates): add dynamic dating to end of quest bundles

* fix(dates): commas are important

* fix(dates): November only has 30 days

* fix(dates): upgrade dynamic end dating for quest bundle endings
2023-11-22 15:28:23 -06:00
Natalie
021825ebb9 fix(shop): add November magic hatching potions to featured items in shop (#15014) 2023-11-22 15:14:42 -06:00
SabreCat
45aae7ff62 fix(test): challenge unlink issues 2023-11-16 13:45:18 -06:00
SabreCat
47bd890dd7 5.12.1 2023-11-14 15:49:32 -06:00
Natalie
add435d4f7 fix(dates) remove hard-coded end dates on bundles (#15011)
* fix(quest text): Updated end date for Oddballs to November 30.

* fix(dates): remove hard-coded bundle end-dates
2023-11-14 15:48:59 -06:00
SabreCat
d262a16269 Merge branch 'release' into develop 2023-11-13 14:37:49 -06:00
Weblate
aeef31d0d4 Merge branch 'develop' of github.com:HabitRPG/habitica into develop 2023-11-10 15:33:28 +01:00
SabreCat
5717e58613 Merge branch 'develop' into release 2023-11-07 08:59:53 -06:00
SabreCat
535477b804 5.12.0 2023-11-07 08:57:35 -06:00
Natalie
a80ef78be0 2023 November Content Prebuild (#14954)
* feat(content): October sub items

* feat(content): October bgs and armoire

* feat(content): add Dune Buddy achievement

* feat(releases): timed Backgrounds and Armoire

* feat(content): timed release achievement

* feat(content): November subscriber items

* feat(content): November pet quest bundle

* feat(content): November magic hatching potions

* feat(content): November backgrounds and armoire

* feat(content): new achievement code -- needs work

* update package.lock on local/origin repos

* fix(content): added October headgear info and November set name

* fix(typo): spelling is important

* feat(content): added logic to allow for pets & mounts to be in one achievement and fixed issues with image

* fix(armoire): correct month

* fix(armoire): deprecate armoireEmpty flag

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-11-07 08:55:50 -06:00
Nazar Paruna
f119304d9e Translated using Weblate (Ukrainian)
Currently translated at 82.4% (113 of 137 strings)

Translation: Habitica/Faq
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
2023-11-04 18:15:42 +01:00
Zachary Flower
cb168338ee Calculate background visibility, even if the task list is empty (#14870) 2023-11-03 15:58:58 -05:00
Phillip Thelen
1892d6288a Clean up translations (#14985) 2023-11-03 15:54:48 -05:00
Weblate
1aa81d1440 Added translation using Weblate (Chinese (Simplified) (zh_HK))
Added translation using Weblate (tl_PH (generated) (tl_PH))

Added translation using Weblate (no (generated) (no))

Added translation using Weblate (hi_IN (generated) (hi_IN))

Added translation using Weblate (fa_IR (generated) (fa_IR))

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.9% (1598 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 79.5% (109 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Ukrainian)

Currently translated at 65.6% (90 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.3% (1579 of 2961 strings)

Translated using Weblate (Russian)

Currently translated at 98.3% (2911 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Ukrainian)

Currently translated at 60.5% (83 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Ukrainian)

Currently translated at 57.6% (79 of 137 strings)

Added translation using Weblate (Chinese (Simplified) (zh_HK))

Added translation using Weblate (tl_PH (generated) (tl_PH))

Added translation using Weblate (no (generated) (no))

Added translation using Weblate (hi_IN (generated) (hi_IN))

Added translation using Weblate (fa_IR (generated) (fa_IR))

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.3% (1579 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 56.9% (78 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (226 of 226 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.0% (1570 of 2961 strings)

Translated using Weblate (Dutch)

Currently translated at 84.1% (2492 of 2961 strings)

Translated using Weblate (Ukrainian)

Currently translated at 39.4% (54 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Ukrainian)

Currently translated at 89.0% (228 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (279 of 279 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Ukrainian)

Currently translated at 89.0% (228 of 256 strings)

Translated using Weblate (Dutch)

Currently translated at 96.2% (152 of 158 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 96.2% (152 of 158 strings)

Translated using Weblate (French)

Currently translated at 100.0% (256 of 256 strings)

Translated using Weblate (French)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (French)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (French)

Currently translated at 100.0% (279 of 279 strings)

Translated using Weblate (French)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (French)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 56.0% (51 of 91 strings)

Translated using Weblate (French)

Currently translated at 78.5% (201 of 256 strings)

Translated using Weblate (French)

Currently translated at 99.2% (139 of 140 strings)

Translated using Weblate (French)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (French)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (French)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (Korean)

Currently translated at 72.1% (114 of 158 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 42.8% (39 of 91 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 98.4% (186 of 189 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 91.7% (145 of 158 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 64.8% (166 of 256 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.4% (2878 of 2953 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (225 of 225 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.8% (419 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.3% (150 of 151 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.4% (760 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 86.7% (222 of 256 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (225 of 225 strings)

Translated using Weblate (Ukrainian)

Currently translated at 95.5% (108 of 113 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.8% (419 of 424 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (819 of 819 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (279 of 279 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (French)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (French)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (French)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (French)

Currently translated at 100.0% (158 of 158 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Russian)

Currently translated at 98.8% (419 of 424 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.4% (2878 of 2953 strings)

Translated using Weblate (Portuguese)

Currently translated at 60.1% (1775 of 2953 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 93.7% (224 of 239 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.4% (186 of 189 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Russian)

Currently translated at 99.3% (814 of 819 strings)

Translated using Weblate (French)

Currently translated at 100.0% (819 of 819 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (189 of 189 strings)

Translated using Weblate (Portuguese)

Currently translated at 72.6% (308 of 424 strings)

Translated using Weblate (Portuguese)

Currently translated at 72.6% (308 of 424 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Portuguese)

Currently translated at 95.6% (777 of 812 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.3% (154 of 155 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Spanish)

Currently translated at 96.8% (217 of 224 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (225 of 225 strings)

Translated using Weblate (French)

Currently translated at 100.0% (151 of 151 strings)

Translated using Weblate (French)

Currently translated at 88.0% (133 of 151 strings)

Translated using Weblate (French)

Currently translated at 85.4% (129 of 151 strings)

Translated using Weblate (French)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (French)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (French)

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (French)

Currently translated at 100.0% (2911 of 2911 strings)

Translated using Weblate (French)

Currently translated at 99.6% (2901 of 2911 strings)

Translated using Weblate (French)

Currently translated at 99.6% (2900 of 2911 strings)

Translated using Weblate (French)

Currently translated at 83.4% (126 of 151 strings)

Translated using Weblate (French)

Currently translated at 72.1% (109 of 151 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (424 of 424 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 73.6% (67 of 91 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Sinhala)

Currently translated at 24.5% (38 of 155 strings)

Translated using Weblate (French)

Currently translated at 57.2% (87 of 152 strings)

Translated using Weblate (French)

Currently translated at 100.0% (91 of 91 strings)

Co-authored-by: AGM <yoartgm@gmail.com>
Co-authored-by: Aasim Kais <aasimabdullahmohamedkais@gmail.com>
Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Ana Paula Fagundes Gomes <paulinha0939@gmail.com>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Icaro <icaro.mascarenhas@outlook.com>
Co-authored-by: Inferno <mishaad051@gmail.com>
Co-authored-by: Jan met de Pet <stijn.koppers@gmail.com>
Co-authored-by: Lapin <sirocuro01@gmail.com>
Co-authored-by: Lucas Rafaldini <lucas.rafaldini@gmail.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Oliver Perkins <ollyboros@users.noreply.translate.habitica.com>
Co-authored-by: Raithe <RaitheOfDureya@gmail.com>
Co-authored-by: Sam Abian <samthony35@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Steffen Dobbelaar <steffendobbelaar@gmail.com>
Co-authored-by: Val <3qes0hnzh@mozmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 谢书凝 <xieshun5450@outlook.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/si/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/character/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/character/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/front/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/es/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/uk/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Inventory
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-11-03 18:22:53 +01:00
SabreCat
efe4483a04 Merge branch 'release' into develop 2023-10-31 15:18:01 -05:00
SabreCat
9cee9ebfe3 5.11.1 2023-10-31 11:42:19 -05:00
SabreCat
33b6de85cc feat(faq): unify platform FAQs
by @CuriousMagpie with edits by @SabreCat
2023-10-31 11:41:24 -05:00
SabreCat
aac3969e6a 5.11.0 2023-10-31 11:28:05 -05:00
SabreCat
61beb770f1 feat(content): subscriber items Nov 2023
by @CuriousMagpie
2023-10-31 11:18:23 -05:00
SabreCat
78ba41c3f8 chore(packages): update lock 2023-10-31 11:10:56 -05:00
SabreCat
1026a721ac Merge branch 'release' into develop 2023-10-25 16:06:52 -05:00
Natalie
affeca6045 fix(strings): remove/change "guild" to "group" (#14872)
* fix(string): questVice1Notes html changed to a mobile-device friendly format

* fix(strings): updated limited.json with "dateEnd" & "monthYYYY" months & put in chronological order

* fix(string): remove extra word from headSpecialSummer2022WarriorNotes

* fix(string): corrected armorSpecialSummer2022MageNotes

* fix: remove duplicated string and adjust upgrade button style

* fix(style): set border radii to 8px on upgrading-group id

* fix(payments): remove duplicate entry from another modal

* chore(fix): restore string inadvertently removed during a refactor

* chore(fix): comma dangle

* chore(typo): who knew, that Y was actually important...

* chore(typo): fix text in questBewilderNotes

* chore(string): clarify polar pets requirements

* couple small changes to the footer as pointed out by users

* chore(fix): correct name of Fabulous Party Hat

* fix(typo): correct February backgrounds release date to 2023, not 2022

* fix(trusted_domains): removed https:// from the beginning of localhost

* fix(config): correct habitica url format too

* fix(strings): remove/change "guild" to "group"

* fix(string): just Bank

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-10-25 16:05:31 -05:00
dependabot[bot]
05ac144e4f build(deps): bump jsonwebtoken from 9.0.1 to 9.0.2 (#14855)
Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 9.0.1 to 9.0.2.
- [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v9.0.1...v9.0.2)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:26:44 -04:00
dependabot[bot]
fdb5d75372 build(deps): bump jquery from 3.7.0 to 3.7.1 in /website/client (#14859)
Bumps [jquery](https://github.com/jquery/jquery) from 3.7.0 to 3.7.1.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.7.0...3.7.1)

---
updated-dependencies:
- dependency-name: jquery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:26:24 -04:00
dependabot[bot]
02770dd1a9 build(deps): bump @babel/register from 7.22.5 to 7.22.15 (#14865)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.22.5 to 7.22.15.
- [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.22.15/packages/babel-register)

---
updated-dependencies:
- dependency-name: "@babel/register"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:26:06 -04:00
dependabot[bot]
6aed03380a build(deps): bump uuid from 9.0.0 to 9.0.1 in /website/client (#14888)
Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.0 to 9.0.1.
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:24:14 -04:00
dependabot[bot]
be822b6bbe build(deps): bump get-func-name from 2.0.0 to 2.0.2 in /website/client (#14902)
Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2.
- [Release notes](https://github.com/chaijs/get-func-name/releases)
- [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2)

---
updated-dependencies:
- dependency-name: get-func-name
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:23:35 -04:00
dependabot[bot]
9aa15d9e64 build(deps): bump winston-loggly-bulk from 3.2.1 to 3.3.0 (#14926)
Bumps [winston-loggly-bulk](https://github.com/loggly/winston-loggly-bulk) from 3.2.1 to 3.3.0.
- [Release notes](https://github.com/loggly/winston-loggly-bulk/releases)
- [Commits](https://github.com/loggly/winston-loggly-bulk/compare/v3.2.1...3.3.0)

---
updated-dependencies:
- dependency-name: winston-loggly-bulk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:21:02 -04:00
dependabot[bot]
4e33a0f7f8 build(deps): bump fsevents from 1.2.9 to 1.2.13 in /website/client (#14937)
Bumps [fsevents](https://github.com/fsevents/fsevents) from 1.2.9 to 1.2.13.
- [Release notes](https://github.com/fsevents/fsevents/releases)
- [Commits](https://github.com/fsevents/fsevents/compare/v1.2.9...v1.2.13)

---
updated-dependencies:
- dependency-name: fsevents
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:20:34 -04:00
dependabot[bot]
7ff9f67aab build(deps): bump @babel/traverse from 7.22.5 to 7.23.2 (#14953)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.5 to 7.23.2.
- [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.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:17:03 -04:00
dependabot[bot]
43fcce7242 build(deps): bump core-js from 3.32.2 to 3.33.1 in /website/client (#14955)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.32.2 to 3.33.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.33.1/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:16:37 -04:00
dependabot[bot]
099274969e build(deps): bump nconf from 0.12.0 to 0.12.1 in /website/client (#14963)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/flatiron/nconf/releases)
- [Changelog](https://github.com/indexzero/nconf/blob/v0.12.1/CHANGELOG.md)
- [Commits](https://github.com/flatiron/nconf/compare/v0.12.0...v0.12.1)

---
updated-dependencies:
- dependency-name: nconf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:13:32 -04:00
dependabot[bot]
5bb97218bd build(deps): bump nconf from 0.12.0 to 0.12.1 (#14966)
Bumps [nconf](https://github.com/flatiron/nconf) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/flatiron/nconf/releases)
- [Changelog](https://github.com/indexzero/nconf/blob/v0.12.1/CHANGELOG.md)
- [Commits](https://github.com/flatiron/nconf/compare/v0.12.0...v0.12.1)

---
updated-dependencies:
- dependency-name: nconf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 14:12:48 -04:00
SabreCat
bc358c3aab 5.10.0 2023-10-24 09:34:31 -05:00
Natalie
581271e930 Reporting challenges (#14756)
* initial commit

* update logic to display flagged challenges properly to users and admins

* add report button to pages 'My Challenges' and 'Discover Challenges'

* allow mods to view flagged messages on challengeDetail view

* update showing flagged challenges for group challenges

* update showing flagged challenges for a specific challenge

* disallow closing a flagged challenge

* update notes to reflect apiParams properly

* fix css spacing

* update challenge en locales

* fix spacing

* update title of closeChallengeModal

* let user know flagged challenges cannot be cloned

* fix linting errors

* ensure flagged challenges cannot be declared with a winner and cloned via API

* define a non user challenge properly

* fix logic to check for a nonParticipant and nonLeader user when grabbing flagged challenges

* fix linting of max character of 100 / line

* remove reporting on 'my challenges' and 'discover challenges'

* WIP(challenges): disable clone button and add notes to new functions

* WIP(challenges): smol changes

* WIP(challenges): clone button only disabled for admin and flagged user; other users can still clone but the flag goes along with the clone

* WIP(challenges): stop flags carrying over on cloned challenges

* WIP(challenges): typo fixing, undoing a smol change

* fix(challenges): improved query logic for flags

* WIP(challenges): more smol changes

* fix(challenges): refactor queries

* fix(challenges): correct My Challenges tab logic

* WIP(challenges): fix clone button state

* WIP(challenges): really fixed clone button & clear flags from clones

* WIP(challenge): implement new design for reporting modal

* WIP(challenge): making things pretty

* WIP(challenge): conquering the close button

* WIP(challenge): fixin some spacing

* WIP(challenge): smol fix

* WIP(challenge): making sure the button is actually disabled

* WIP(challenge): fix blockquote css

* fix(tests): no private guilds

* fix(lint): curlies etc

* fix(test): moderator permission

* fix(lint): sure man whatever

* fix(lint): bad vim no tabby

* fix(test): permissions not contrib lol

* fix(challenges): add icon and fix leaky CSS

* fix(challenge): correct clone button behavior

---------

Co-authored-by: Julius Jung <me@matchajune.io>
Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-10-24 09:24:56 -05:00
SabreCat
57fe1d6b22 Merge branch 'release' into develop 2023-10-17 17:53:22 -05:00
SabreCat
8537793308 5.9.1 2023-10-17 17:35:05 -05:00
Sabe Jones
38974617b5 fix(event): sale in 2023 not just 2022 2023-10-17 22:34:05 +00:00
Sabe Jones
4974712d6c fix(stats): enforce sensible maxima in db 2023-10-17 22:31:43 +00:00
Sabe Jones
832acb1617 chore(strings): make Stable wording consistent with mobile by @CuriousMagpie 2023-10-17 22:30:25 +00:00
Sabe Jones
ce1d1a763b fix(quests): level up if appropriate after completion 2023-10-17 22:29:02 +00:00
Natalie
7aecadfe68 fix(content): change test strings to Pets and Mounts from Stable(s) (#14912) 2023-10-17 17:27:43 -05:00
SabreCat
06f522e2c9 5.9.0 2023-10-17 09:09:16 -05:00
SabreCat
f7ac6e8eb1 fix(css): achievement layout 2023-10-17 09:09:00 -05:00
SabreCat
8ea1ace239 feat(achievement): add db migration 2023-10-16 20:23:03 -05:00
SabreCat
1da6eeb169 feat(content): Dune Buddy Achievement 2023-10-16 20:15:08 -05:00
SabreCat
b539dd2b2e 5.8.0 2023-10-09 13:32:14 -05:00
SabreCat
71e565ea9a Merge branch 'release' into develop 2023-10-09 13:31:50 -05:00
SabreCat
565f38f7ed fix(gear): capitalization/punctuation 2023-10-09 13:03:45 -05:00
CuriousMagpie
56ccf19c26 feat(content): October bgs and armoire 2023-10-09 12:55:16 -05:00
Weblate
6a5097c16e Translated using Weblate (French)
Currently translated at 91.2% (83 of 91 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 81.9% (77 of 94 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 96.4% (109 of 113 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 91.6% (120 of 131 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 26.3% (40 of 152 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 63.7% (58 of 91 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 93.6% (44 of 47 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 81.6% (183 of 224 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 90.8% (119 of 131 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 78.4% (331 of 422 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.2% (2831 of 2911 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 91.7% (167 of 182 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 23.6% (36 of 152 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 93.0% (711 of 764 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 58.2% (53 of 91 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 91.4% (43 of 47 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 73.5% (597 of 812 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 78.4% (167 of 213 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.0% (2825 of 2911 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.7% (400 of 422 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 96.8% (2820 of 2911 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 35.5% (54 of 152 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 52.7% (48 of 91 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.8% (1568 of 2911 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Arabic)

Currently translated at 98.0% (152 of 155 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Galician)

Currently translated at 98.9% (180 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Galician)

Currently translated at 96.9% (409 of 422 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Turkish)

Currently translated at 97.8% (92 of 94 strings)

Translated using Weblate (French)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (2911 of 2911 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Polish)

Currently translated at 99.5% (212 of 213 strings)

Translated using Weblate (Polish)

Currently translated at 98.4% (129 of 131 strings)

Translated using Weblate (Polish)

Currently translated at 99.5% (223 of 224 strings)

Translated using Weblate (Polish)

Currently translated at 95.1% (773 of 812 strings)

Translated using Weblate (French)

Currently translated at 99.4% (2896 of 2911 strings)

Translated using Weblate (French)

Currently translated at 51.9% (79 of 152 strings)

Translated using Weblate (French)

Currently translated at 98.3% (799 of 812 strings)

Translated using Weblate (Indonesian)

Currently translated at 78.0% (71 of 91 strings)

Translated using Weblate (Hindi)

Currently translated at 97.8% (184 of 188 strings)

Translated using Weblate (Hindi)

Currently translated at 70.9% (110 of 155 strings)

Translated using Weblate (Hindi)

Currently translated at 29.6% (16 of 54 strings)

Translated using Weblate (Hindi)

Currently translated at 86.6% (13 of 15 strings)

Translated using Weblate (Galician)

Currently translated at 58.6% (1706 of 2911 strings)

Translated using Weblate (Galician)

Currently translated at 65.4% (500 of 764 strings)

Translated using Weblate (French)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (French)

Currently translated at 99.1% (2887 of 2911 strings)

Translated using Weblate (French)

Currently translated at 51.3% (78 of 152 strings)

Translated using Weblate (French)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.1% (62 of 91 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.3% (154 of 155 strings)

Translated using Weblate (French)

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (English (en@lolcat))

Currently translated at 5.4% (44 of 812 strings)

Translated using Weblate (English (en@lolcat))

Currently translated at 6.5% (53 of 812 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (Serbian)

Currently translated at 27.0% (42 of 155 strings)

Translated using Weblate (Belarusian)

Currently translated at 58.1% (1694 of 2911 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.8% (1567 of 2911 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.6% (1562 of 2911 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.5% (1558 of 2911 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (2911 of 2911 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 65.7% (100 of 152 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2878 of 2911 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 69.2% (63 of 91 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (2851 of 2911 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.6% (2873 of 2911 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 87.5% (7 of 8 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.3% (218 of 224 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (47 of 47 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Andrii <andrii.koket@gmail.com>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Deleted User <maximrudenkodeal@gmail.com>
Co-authored-by: Florence <paratflo@hotmail.com>
Co-authored-by: Inky Clouds <johnwatsonwrites@gmail.com>
Co-authored-by: Jan <darkbutterfly7530@gmail.com>
Co-authored-by: Justcallme rye <Blizzardscf32@gmail.com>
Co-authored-by: Luísa Bettin <puffycolors@gmail.com>
Co-authored-by: M <maperray@gmail.com>
Co-authored-by: Mateus Felipe Ribeiro Ambrósio <mateus.mfr10@gmail.com>
Co-authored-by: Maxim Rudenko <maximrudenkodeal@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Ognjen <ognjenzxz@gmail.com>
Co-authored-by: Raithe <RaitheOfDureya@gmail.com>
Co-authored-by: Remo Auväärt <remo.auvaart@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Svetlana <shkulepo@rambler.ru>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Victoria Koo <antongvictoria@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yumna Hassan <yumnasu24@gmail.com>
Co-authored-by: Zuz Q <zuzannakunik@gmail.com>
Co-authored-by: billypat <kreideraine@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ar/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/hi/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/id/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/en@lolcat/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/character/hi/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/id/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/content/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/death/et/
Translate-URL: https://translate.habitica.com/projects/habitica/death/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/death/hi/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/hi/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/front/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/front/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/be/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ar/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pl/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Death
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-10-09 18:25:48 +02:00
SabreCat
4ff1368db7 5.7.0 2023-10-03 16:36:18 -05:00
SabreCat
7025f92c0e fix(lint): unused var 2023-10-03 16:25:07 -05:00
SabreCat
3c73322980 fix(tests): one more 2023-10-03 16:19:50 -05:00
SabreCat
fbb9b2c65a fix(tests): post merge cleanup 2023-10-03 15:58:31 -05:00
SabreCat
a9f3360890 Squashed commit of the following:
commit 9d99b6b3d7
Author: SabreCat <sabe@habitica.com>
Date:   Thu Sep 14 09:57:42 2023 -0500

    fix(string): just Bank

commit a4d34d487a
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Sep 13 14:50:14 2023 -0400

    fix(strings): remove/change "guild" to "group"

commit dee572cd63
Merge: aefd8ec6c4 e332876d30
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Sep 13 13:54:50 2023 -0400

    Merge branch 'develop' into misc-string-fixes

commit aefd8ec6c4
Author: Sabe Jones <sabrecat@gmail.com>
Date:   Tue Jul 25 14:10:25 2023 -0500

    fix(config): correct habitica url format too

commit 990da1c8f2
Merge: c1d6e0b580 8558dcc3a8
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Jul 24 15:54:49 2023 -0400

    Merge branch 'develop' into misc-string-fixes

commit c1d6e0b580
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Jul 24 15:53:28 2023 -0400

    fix(trusted_domains): removed https:// from the beginning of localhost

commit b77cb874c9
Merge: 7285aa36bd 71e165433a
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu May 11 16:26:17 2023 -0400

    Merge branch 'develop' into misc-string-fixes

commit 7285aa36bd
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Feb 9 15:31:41 2023 -0500

    fix(typo): correct February backgrounds release date to 2023, not 2022

commit 7aca2ee908
Merge: 30edc124ac 0b8f2bc58e
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Feb 9 15:30:34 2023 -0500

    Merge branch 'develop' into misc-string-fixes

commit 30edc124ac
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Jan 30 13:27:10 2023 -0500

    chore(fix): correct name of Fabulous Party Hat

commit 20e336b749
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Jan 20 14:46:27 2023 -0500

    couple small changes to the footer as pointed out by users

commit 16a0255373
Merge: e9a1450b57 d85436afbf
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Jan 20 14:43:16 2023 -0500

    Merge branch 'develop' into misc-string-fixes

commit e9a1450b57
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jan 4 11:02:56 2023 -0500

    chore(string): clarify polar pets requirements

commit 9d25e07a4b
Merge: 906b7fcd43 c7aadede4d
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jan 4 11:01:16 2023 -0500

    Merge branch 'develop' into misc-string-fixes

commit 906b7fcd43
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Dec 16 13:00:59 2022 -0500

    chore(typo): fix text in questBewilderNotes

commit d0de66f378
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 8 16:32:26 2022 -0500

    chore(typo): who knew, that Y was actually important...

commit c0a93ae202
Merge: dbae5fb36b 978e8c4320
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 8 16:30:52 2022 -0500

    Merge branch 'develop' into misc-string-fixes

commit dbae5fb36b
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 7 13:06:54 2022 -0500

    chore(fix): comma dangle

commit 9365be609f
Merge: 8f2af4a7ea f6e5360bdd
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 7 12:35:56 2022 -0500

    Merge branch 'develop' into misc-string-fixes

commit 8f2af4a7ea
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Nov 7 12:35:04 2022 -0500

    chore(fix): restore string inadvertently removed during a refactor

commit 77fe9450cb
Merge: 5780b71ef8 13c0d12045
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Sep 19 15:07:41 2022 -0400

    Merge branch 'develop' into misc-string-fixes

commit 5780b71ef8
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 14 16:27:21 2022 -0500

    fix(payments): remove duplicate entry from another modal

commit f36d0ca0e2
Merge: 92b26fdecd 5f440f1bfa
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 14 16:15:01 2022 -0500

    Merge branch 'develop' into misc-string-fixes

commit 92b26fdecd
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 27 18:05:53 2022 -0400

    fix(style): set border radii to 8px on upgrading-group id

commit f359142aa5
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 27 17:47:19 2022 -0400

    fix: remove duplicated string and adjust upgrade button style

commit b67ef33b63
Merge: bd736235cc c09f078409
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 27 17:09:23 2022 -0400

    Merge branch 'misc-string-fixes' of https://github.com/CuriousMagpie/habitica into misc-string-fixes

commit c09f078409
Merge: 05811e3c70 ef3767f80b
Author: Natalie L <78037386+CuriousMagpie@users.noreply.github.com>
Date:   Wed Jul 27 17:05:52 2022 -0400

    Merge branch 'HabitRPG:develop' into misc-string-fixes

commit bd736235cc
Merge: 88368a8c21 ef3767f80b
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 27 17:03:30 2022 -0400

    Merge remote-tracking branch 'upstream/develop' into misc-string-fixes

commit 05811e3c70
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Jun 24 15:01:23 2022 -0400

    fix(string): corrected armorSpecialSummer2022MageNotes

commit 4031c97253
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Jun 23 12:26:51 2022 -0400

    fix(string): remove extra word from headSpecialSummer2022WarriorNotes

commit e4af5c250f
Merge: 88368a8c21 76de241675
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Jun 23 11:27:04 2022 -0400

    Merge branch 'develop' into misc-string-fixes

commit 88368a8c21
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Jun 21 13:49:46 2022 -0400

    fix(strings): updated limited.json with "dateEnd" & "monthYYYY" months & put in chronological order

commit 6ee08377e9
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Jun 20 15:36:58 2022 -0400

    fix(string): questVice1Notes html changed to a mobile-device friendly format
2023-10-03 13:32:11 -05:00
SabreCat
a0941ffa84 Squashed commit of the following:
commit 16d8b87e90
Merge: 07387faf48 6bea232d47
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Sep 14 22:30:00 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 07387faf48
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Sep 13 23:38:37 2023 +0200

    remove generate promoCode from ui

commit 6bea232d47
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Sep 11 12:55:31 2023 -0400

    build(deps): bump core-js from 3.32.1 to 3.32.2 in /website/client (#14867)

    Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.32.1 to 3.32.2.
    - [Release notes](https://github.com/zloirock/core-js/releases)
    - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/zloirock/core-js/commits/v3.32.2/packages/core-js)

    ---
    updated-dependencies:
    - dependency-name: core-js
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit cebb3f0f25
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Sep 11 12:43:49 2023 -0400

    build(deps): bump webpack from 4.46.0 to 4.47.0 in /website/client (#14868)

    Bumps [webpack](https://github.com/webpack/webpack) from 4.46.0 to 4.47.0.
    - [Release notes](https://github.com/webpack/webpack/releases)
    - [Commits](https://github.com/webpack/webpack/compare/v4.46.0...v4.47.0)

    ---
    updated-dependencies:
    - dependency-name: webpack
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit ea8563cd17
Merge: 3e16584dcf 6259955891
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Aug 29 21:23:02 2023 +0200

    Merge remote-tracking branch 'origin/negue/ui/setting' into negue/ui/setting

commit 3e16584dcf
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Aug 29 21:22:06 2023 +0200

    fix PR comments

commit 84ba44fb19
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Aug 29 20:38:54 2023 +0200

    fix PR comments

commit 6259955891
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 25 11:20:26 2023 -0400

    update form.scss

commit da82bd8e68
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Aug 24 21:40:02 2023 +0200

    remove ending

commit 82e5fd2a83
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Aug 21 22:25:41 2023 +0200

    fix spacing

commit 9ad06ea88b
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Aug 21 22:09:22 2023 +0200

    clean up debug row for login methods

commit 41cde37675
Merge: 8c568060f9 82ebe71eb4
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Aug 21 21:51:22 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 8c568060f9
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Aug 21 21:49:31 2023 +0200

    fix PR comments

commit 36f7a4711d
Merge: d279af7897 647b27c55f
Author: negue <eugen.bolz@gmail.com>
Date:   Fri Aug 11 20:04:15 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit d279af7897
Merge: ffbed3e044 b20ea44d49
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Aug 9 21:13:37 2023 +0200

    Merge branch 'negue/refactor/routes' into negue/ui/setting

commit b20ea44d49
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Aug 9 21:04:12 2023 +0200

    Split Vue.Router routes

commit ffbed3e044
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jul 23 00:00:24 2023 +0200

    remove console

commit 4c350b0180
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jul 22 23:34:20 2023 +0200

    update Bailey Notification Text + fix popover

commit c105b9ecf9
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jul 22 23:21:53 2023 +0200

    fix change password setting

commit 06410b4807
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jul 22 22:50:00 2023 +0200

    fix reset account texts

commit ccfdd9bb9c
Merge: 35c75304f1 8558dcc3a8
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jul 22 22:48:13 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 35c75304f1
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jul 2 20:16:06 2023 +0200

    more fixes

commit 203e961464
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jul 2 19:45:17 2023 +0200

    fix notification settings

commit ec94604791
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 22:00:45 2023 +0200

    applied same styling to promoCode.vue

commit 0177b3a76b
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 21:41:05 2023 +0200

    move promoCode.vue to pages/settings

commit 8fbb600273
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 21:40:35 2023 +0200

    saveCancelButtons.vue allow to hide the cancel part

commit 4915f2a3fb
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 21:09:07 2023 +0200

    Hide Transactions Page again

commit 8b5ae17f02
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 20:52:03 2023 +0200

    also check for invalid arguments in the password settings

commit aa97ed5299
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 20:25:53 2023 +0200

    fix localhost externalLinks check

commit 87a4e4931b
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Jun 25 20:01:31 2023 +0200

    show notification on username change + fix userEmail checks

commit 6a6f55f6fc
Merge: f9ff5e5c55 e49d26eacd
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jun 24 22:54:00 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit f9ff5e5c55
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 22:41:42 2023 +0200

    check password inputs and mark invalid for "password change" setting

commit 4497514eeb
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 21:59:21 2023 +0200

    show notification when chaning display name

commit 3232f12f0d
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 21:55:25 2023 +0200

    check current password valid style in "delete account" and "reset account"

commit 582a2f1304
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 21:27:20 2023 +0200

    mark password field of email setting as invalid on wrong password

commit 8e3b8a962a
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 21:24:46 2023 +0200

    refactor currentPasswordInput.vue to use validatedTextInput.vue

commit 61521507a4
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 20:20:56 2023 +0200

    fix username setting:
    - unsaved values check
    - @ char must be first in input, otherwise not remove it for checks

commit f74c29a065
Merge: c4b6f0c39c d4a5823916
Author: negue <eugen.bolz@gmail.com>
Date:   Tue May 30 19:54:06 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit c4b6f0c39c
Merge: 37eee140ad 6e3a367832
Author: negue <eugen.bolz@gmail.com>
Date:   Fri May 12 22:08:08 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 37eee140ad
Author: negue <eugen.bolz@gmail.com>
Date:   Fri May 12 21:57:27 2023 +0200

    delete account without password

commit 48a6801f4e
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 22:06:29 2023 +0200

    fix duplicate json entry

commit 47a2189f49
Merge: a56b4a4457 49f45d27e3
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 21:48:21 2023 +0200

    Merge remote-tracking branch 'origin/release' into negue/ui/setting

commit a56b4a4457
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 21:37:31 2023 +0200

    show current class on setting panel

commit 9c973cca2a
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 21:15:46 2023 +0200

    fix selectDifficulty.vue - refactor selectList.vue

commit 95b37b3ba3
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 20:45:09 2023 +0200

    migrate restoreValues fix to new setting component

commit 7947b1c67d
Merge: ad3e4d604a 71e165433a
Author: negue <eugen.bolz@gmail.com>
Date:   Mon May 8 20:41:31 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit ad3e4d604a
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Apr 29 01:18:25 2023 +0200

    style fixes

commit cea13d5bc3
Merge: 73a5e5fcab b159182188
Author: negue <eugen.bolz@gmail.com>
Date:   Fri Apr 28 23:58:09 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 73a5e5fcab
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Apr 25 20:51:14 2023 +0200

    style / padding issues

commit 0a10eb32cc
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Apr 15 20:54:08 2023 +0200

    fix "setting new password" invalid check

commit a79bec3fa5
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Apr 11 23:15:15 2023 +0200

    add password for other logins

commit 9ff17fd6dd
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Apr 11 23:05:19 2023 +0200

    "fix values" use keydown event to mark as change

commit 1f470942a9
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Apr 6 00:19:18 2023 +0200

    delete old api.vue

commit b4904a8b84
Merge: b5da7ccc70 c8b98678d0
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Apr 6 00:18:07 2023 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit b5da7ccc70
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Apr 6 00:11:36 2023 +0200

    refactor webhook ui to use save/cancel buttons

commit f49f67ff5c
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Apr 5 22:56:37 2023 +0200

    remove unused settings

commit cc73b44b25
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 29 23:40:30 2023 +0200

    remove advancedCollapsed settings to start it opened

commit e0300e8710
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 29 22:58:09 2023 +0200

    remove displayInviteToPartyWhenPartyIs1 setting

commit 1741ddfc64
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Mar 20 23:00:17 2023 +0100

    webhook margins

commit 24a43d027c
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Mar 20 22:40:19 2023 +0100

    userid tooltip

commit 42fcb20bc4
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Mar 16 00:51:10 2023 +0100

    remove balance for choosing class

commit 160848473d
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Mar 16 00:20:56 2023 +0100

    show real class setting modal if enough gems available

commit f74ba9738d
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Mar 16 00:10:53 2023 +0100

    update apple icon and size

commit bf961bc728
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 15 23:59:42 2023 +0100

    Copied API Token Notification

commit 28f0220b4e
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 15 23:53:33 2023 +0100

    remove blue color of setting links

commit b53ccace95
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 15 23:43:06 2023 +0100

    fix username/email setting input width

commit 1dfa5b275d
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Mar 15 23:11:32 2023 +0100

    developer mode

commit 776618d2db
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Mar 14 21:11:52 2023 +0100

    Add new Pause Dailies Setting

commit 576c80af7e
Merge: dec1a1159d 377b152ffd
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Mar 14 21:04:05 2023 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit dec1a1159d
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Mar 14 21:00:52 2023 +0100

    developer mode dummy row

commit 1e80a7d145
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Mar 11 00:03:33 2023 +0100

    WIP webhook row

commit cc4bedbe2d
Author: negue <eugen.bolz@gmail.com>
Date:   Fri Mar 10 20:28:57 2023 +0100

    add spritely login creds message to the new api-row / redirect old url to the new one

commit f9833aa78a
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Mar 9 02:23:39 2023 +0100

    API Token Row

commit 123c9b9bb1
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Mar 6 22:46:50 2023 +0100

    "Your User Data" Row instead of Page

commit 0ade5663ae
Author: negue <eugen.bolz@gmail.com>
Date:   Fri Mar 3 22:43:03 2023 +0100

    userid row

commit b4f2236ab8
Author: negue <eugen.bolz@gmail.com>
Date:   Fri Mar 3 22:22:32 2023 +0100

    rename folder of setting rows

commit 3b050861c4
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Feb 21 21:11:48 2023 +0100

    move remaining setting to generalSettings.vue - delete site.vue - start with siteData.vue

commit b09298fb01
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Feb 21 20:56:03 2023 +0100

    move taskSettings.vue and add it to the settings list

commit 5ed25066ec
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Feb 21 20:06:13 2023 +0100

    size/margin for transactions

commit 25e77cbd95
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Feb 21 19:52:12 2023 +0100

    move purchaseHistory.vue

commit 8e4e1bcb0f
Merge: bb14d09aa4 85c50d50e9
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Feb 21 19:04:31 2023 +0100

    Merge remote-tracking branch 'origin/negue/ui/setting' into negue/ui/setting

commit 85c50d50e9
Author: SabreCat <sabe@habitica.com>
Date:   Thu Feb 16 14:23:27 2023 -0600

    fix(css): remove redundant formatting for a elements

commit bb14d09aa4
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Feb 16 01:34:09 2023 +0100

    remove console

commit 8c5e722c72
Author: negue <eugen.bolz@gmail.com>
Date:   Thu Feb 16 01:26:43 2023 +0100

    first try with the refactored UI of Login Methods

commit 9c8770051d
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 19:13:16 2023 +0100

    fix dayStartAdjustmentSetting.vue for 0 value

commit ee2ff3881b
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 18:37:46 2023 +0100

    fix color after refactor

commit 121e7485ca
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 18:29:00 2023 +0100

    mark audioThemeSetting as changed

commit 98c6570003
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 18:05:55 2023 +0100

    fix ul/li style in resetAccount.vue

commit fed824f705
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 17:49:36 2023 +0100

    fix color of gem price

commit 80365e537d
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Feb 11 17:44:55 2023 +0100

    fix "fixValuesSetting.vue"

commit d3e15c5413
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Feb 8 01:06:27 2023 +0100

    open forgot password in new tab

commit 31edec9ec5
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Feb 8 01:03:19 2023 +0100

    move validatedTextInput.vue to shared components + fix check pos/size + input-error cleanup

commit 2adfd8c259
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Feb 5 20:19:30 2023 +0100

    hide class setting until level 10

commit 64fb4c0cf9
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Feb 5 19:32:40 2023 +0100

    delete old modals (refactored into new settings ui)

commit b5be137a8d
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Feb 5 19:27:26 2023 +0100

    enable forgot password link in settings

commit bec75c6e12
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Feb 5 18:52:54 2023 +0100

    reset account + password required in api

commit 64f7e7a1d9
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Jan 30 23:22:55 2023 +0100

    fix compile

commit 7ffb5101be
Merge: 2bfb130b92 9f64633a57
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Jan 30 22:47:05 2023 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 2bfb130b92
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Jan 30 22:44:23 2023 +0100

    remove restore-modal and replace it with the finished fix values setting

commit 89530a133c
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Jan 18 19:22:36 2023 +0100

    wip fix values

commit 428647fc71
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jan 14 21:50:22 2023 +0100

    refactor change class to design update + clean up old site.vue settings

commit 1f16819bc1
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Jan 11 22:41:05 2023 +0100

    WIP fix values

commit 6fef3d0579
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jan 7 22:51:30 2023 +0100

    check for unsaved changes when pressing cancel

commit bef8a4cdfc
Merge: 494f32c3e3 c7aadede4d
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Jan 7 22:10:53 2023 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 494f32c3e3
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Dec 21 00:55:31 2022 +0100

    Class Setting

commit bda210cfbb
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Dec 20 23:01:41 2022 +0100

    removes username, email and display name from site.vue

commit 38198d7df6
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Dec 20 22:36:27 2022 +0100

    WIP class setting

commit dddcfa637f
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Dec 20 22:31:36 2022 +0100

    fix styles

commit ce0a5cf974
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Dec 11 23:57:07 2022 +0100

    Scroll into opened Setting

commit 7e0a95ddff
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Dec 11 23:43:44 2022 +0100

    Audio Theme Setting

commit 9c556662fe
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Dec 11 00:25:30 2022 +0100

    prepare header settings but still hidden

commit 30d8b27534
Merge: a1d1a788b2 580139ff69
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Dec 10 23:36:36 2022 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit a1d1a788b2
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Dec 10 23:34:33 2022 +0100

    DayStartAdjustmentSetting

commit ddee94a393
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Dec 10 20:00:12 2022 +0100

    disable reset account button when password empty

commit 30a6db4c2d
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Dec 10 19:54:21 2022 +0100

    hide & reset previous setting when switching to a different one

commit 78093848d7
Author: negue <eugen.bolz@gmail.com>
Date:   Wed Dec 7 22:19:15 2022 +0100

    validated text input (in/valid border color + icon)

commit e1b444ea63
Author: negue <eugen.bolz@gmail.com>
Date:   Tue Dec 6 22:09:54 2022 +0100

    re-enable box-shadow on hover

commit 96dc4e47ae
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 28 01:13:47 2022 +0100

    remove console log

commit 69ad07daad
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 28 01:01:17 2022 +0100

    dateFormatSetting

commit bc11c0cf75
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 28 00:49:24 2022 +0100

    move shared components / mixins

commit 0d1a189c64
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 28 00:44:21 2022 +0100

    language Setting + imports cleanup

commit 29ebd89030
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 27 23:23:02 2022 +0100

    fix icon size + fix display name valid checks

commit 5c7747517b
Merge: fd5cbc3026 90b34c4dac
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 27 23:08:35 2022 +0100

    Merge remote-tracking branch 'origin/release' into negue/ui/setting

commit fd5cbc3026
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 23 00:14:21 2022 +0100

    fix conflicts

commit 49361217b0
Merge: edb427158f 04e2a39a9f
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 23 00:12:38 2022 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit edb427158f
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 23 00:03:19 2022 +0100

    disable save button if nothing was changed

commit c7e40e9446
Author: negue <negue@users.noreply.github.com>
Date:   Tue Nov 22 23:36:37 2022 +0100

    delete account row

commit 4bf740c531
Author: negue <negue@users.noreply.github.com>
Date:   Tue Nov 22 23:14:24 2022 +0100

    Shared Modal Visible State

commit d718153717
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 20 18:06:20 2022 +0100

    resetAccount

commit e25922f8b3
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 16 23:39:26 2022 +0100

    rename functional components for compiler

commit fdbc2c0eee
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 16 01:44:50 2022 +0100

    password setting row

commit 5fd5e6275a
Author: negue <negue@users.noreply.github.com>
Date:   Tue Nov 15 17:35:44 2022 +0100

    update package-lock.json again

commit 9d742fd9a1
Author: negue <negue@users.noreply.github.com>
Date:   Tue Nov 15 17:24:15 2022 +0100

    update package-lock.json

commit cd588e74d5
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 14 02:12:39 2022 +0100

    displayNameSetting.vue

commit 265970c5ef
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 14 02:09:47 2022 +0100

    fix lint

commit a2b510caca
Merge: 0bae5fbe02 4dca69f14b
Author: negue <negue@users.noreply.github.com>
Date:   Mon Nov 14 01:15:02 2022 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 0bae5fbe02
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 13 22:00:34 2022 +0100

    userEmailSetting

commit 23da70fa2e
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 13 20:38:14 2022 +0100

    extract save / cancel buttons and the shared inlineSetting "logic"

commit 82047380f3
Author: negue <negue@users.noreply.github.com>
Date:   Sun Nov 13 20:18:21 2022 +0100

    first setting (username) in the new layout

commit 39150349c7
Author: negue <negue@users.noreply.github.com>
Date:   Wed Nov 2 21:42:12 2022 +0100

    Working on M1 - will be reverted on full merge

commit f7787b318c
Merge: 4c0ecc9938 53fb28cc48
Author: negue <negue@users.noreply.github.com>
Date:   Tue Nov 1 14:20:24 2022 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 4c0ecc9938
Merge: 2f53613a45 62b4315b3d
Author: negue <negue@users.noreply.github.com>
Date:   Sun Oct 30 12:49:34 2022 +0100

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit 2f53613a45
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Oct 10 22:54:41 2022 +0200

    split routes for ease of dev

commit 390f0fc69d
Merge: cf222ee63a 137f7d53dc
Author: negue <eugen.bolz@gmail.com>
Date:   Mon Oct 10 22:50:43 2022 +0200

    Merge remote-tracking branch 'origin/develop' into negue/ui/setting

commit cf222ee63a
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Oct 2 23:15:35 2022 +0200

    Update remaining Notification labels

commit f837cce125
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Oct 2 22:45:12 2022 +0200

    move site popup settings to notifications

commit fc5181c3a7
Author: negue <eugen.bolz@gmail.com>
Date:   Sun Oct 2 21:12:24 2022 +0200

    fix styling in notification settings

commit 7b5568ed23
Author: negue <eugen.bolz@gmail.com>
Date:   Sat Sep 10 16:00:56 2022 +0200

    wip notification settings
2023-10-03 13:30:44 -05:00
SabreCat
a9757b2d74 Squashed commit of the following:
commit 3aba0abedd
Author: SabreCat <sabe@habitica.com>
Date:   Mon Oct 2 20:51:20 2023 -0500

    fix(router): use state to pass modal launch info

commit 541eadd319
Merge: c0bb56c8c2 89fff49d02
Author: SabreCat <sabe@habitica.com>
Date:   Mon Oct 2 20:12:40 2023 -0500

    Merge branch 'release' into report-profile-modal

commit c0bb56c8c2
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 27 16:15:28 2023 -0500

    test(profiles): add integrations

commit 9b644e9ad8
Author: SabreCat <sabe@habitica.com>
Date:   Tue Sep 26 17:17:22 2023 -0500

    fix(profile): adjust margin

commit bfefe5dfa9
Author: SabreCat <sabe@habitica.com>
Date:   Tue Sep 26 17:12:24 2023 -0500

    fix(profiles): moar layout fixes

commit 8f211ee3e2
Author: SabreCat <sabe@habitica.com>
Date:   Mon Sep 25 17:32:04 2023 -0500

    fix(profile): fix admin actions
    Correct "user is banned" banner
    Fix bouncing modal
    Add "Days" smart plural
    Fix leaky CSS on Market page
    Refactor some redundant functions

commit b1d23ec88b
Merge: ee9709a9e1 a63cc84779
Author: SabreCat <sabe@habitica.com>
Date:   Mon Sep 25 15:37:54 2023 -0500

    Merge branch 'release' into report-profile-modal

commit ee9709a9e1
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Sep 18 16:30:30 2023 -0400

    WIP(profile): add banned banner, toggle switches now toggle, add "days" to Next Login Reward

commit f80928a895
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Sep 18 13:43:34 2023 -0400

    update(node): update node modules

commit 1d552f7e80
Author: SabreCat <sabe@habitica.com>
Date:   Fri Sep 15 16:52:22 2023 -0500

    fix(import): remove empty import

commit f55d74a95d
Author: SabreCat <sabe@habitica.com>
Date:   Fri Sep 15 16:39:50 2023 -0500

    refactor(profiles): remove email feature
    also still more visual cleanup of profile modal

commit 311c743284
Author: SabreCat <sabe@habitica.com>
Date:   Fri Sep 15 15:44:56 2023 -0500

    refactor(profile): remove page view

commit f8632bf50d
Merge: ec85159c65 9e25360102
Author: SabreCat <sabe@habitica.com>
Date:   Fri Sep 15 15:23:21 2023 -0500

    Merge branch 'release' into report-profile-modal

commit ec85159c65
Author: SabreCat <sabe@habitica.com>
Date:   Mon Sep 11 22:53:14 2023 -0500

    feat(profiles): load modal instead of page?

commit 9986082914
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 8 14:49:57 2023 -0400

    WIP(profile): fixed a comment, woohoo

commit 6262a9ba0c
Merge: ae2b614df2 ea2b007b1a
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 8 13:40:23 2023 -0400

    Merge remote-tracking branch 'origin/report-profile-modal' into report-profile-modal

commit ea2b007b1a
Author: SabreCat <sabe@habitica.com>
Date:   Thu Sep 7 16:54:19 2023 -0500

    fix(profile): focus behavior

commit ae2b614df2
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Sep 7 17:47:08 2023 -0400

    WIP(profile): styling updates

commit 2e0723f1b9
Author: SabreCat <sabe@habitica.com>
Date:   Thu Sep 7 15:37:59 2023 -0500

    feat(moderation): unflag profile
    Also a few stylistic tweaks

commit edcf8113de
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 6 16:39:02 2023 -0500

    WIP(profile): dropdown draft

commit 0691483d63
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Sep 6 16:33:30 2023 -0400

    WIP(profile): Styling and string updates

commit 7e9d57d10a
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 6 11:40:31 2023 -0500

    feat(profile): functional dropdown buttons

commit a2989b2833
Merge: af6575e40c e072d7c09c
Author: SabreCat <sabe@habitica.com>
Date:   Wed Sep 6 10:04:57 2023 -0500

    Merge branch 'release' into report-profile-modal

commit af6575e40c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Sep 6 11:01:05 2023 -0400

    WIP(profile): comment cleanup

commit 7b1de37202
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Sep 5 17:22:14 2023 -0400

    WIP(profile): remove shadowban tooltip

commit d1177c32b9
Merge: 321a01b081 31f821021b
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Sep 5 17:02:40 2023 -0400

    Merge branch 'sabrecat/report-profile' into report-profile-modal

commit 321a01b081
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 1 16:14:36 2023 -0400

    WIP(profile): close button finally workinating

commit e143d36d28
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 1 15:52:38 2023 -0400

    WIP(profile): close icon moved to profile.vue

commit 31f821021b
Merge: a8f5e25d38 8957c5c009
Author: SabreCat <sabe@habitica.com>
Date:   Fri Sep 1 14:52:31 2023 -0500

    Merge branch 'report-profile-modal' into sabrecat/report-profile

commit 8957c5c009
Merge: d340f06a22 0aec3866a4
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 1 15:38:12 2023 -0400

    Merge remote-tracking branch 'origin/report-profile-modal' into report-profile-modal

commit d340f06a22
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 1 15:37:57 2023 -0400

    WIP(profile): fixed user not found error

commit 0aec3866a4
Merge: b01f323b14 ac7c8e0eb6
Author: Natalie <78037386+CuriousMagpie@users.noreply.github.com>
Date:   Fri Sep 1 15:28:58 2023 -0400

    Merge branch 'HabitRPG:develop' into report-profile-modal

commit a8f5e25d38
Author: SabreCat <sabe@habitica.com>
Date:   Thu Aug 31 17:02:07 2023 -0500

    feat(community): basic "report profile"

commit b01f323b14
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Aug 31 17:42:12 2023 -0400

    WIP(profile): removed refactoring crud, located where close icon should be (profileModal.vue)

commit ce7d51a20c
Merge: 010f2299f0 ac7c8e0eb6
Author: SabreCat <sabe@habitica.com>
Date:   Thu Aug 31 14:20:37 2023 -0500

    Merge branch 'release' into sabrecat/report-profile

commit 18b41acd94
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Aug 31 12:23:41 2023 -0400

    WIP(profile): moar buttonz

commit 9387b3a6bc
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 30 17:21:36 2023 -0400

    WIP(profile): buttons

commit b3ea48c4f5
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 25 15:52:41 2023 -0400

    WIP(profile): work on achievement component

commit a1ceb2ea75
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 25 14:39:12 2023 -0400

    WIP(profile): create achievements component

commit 4a24d9b80b
Merge: 8fe263a377 1e05297e96
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 23 13:14:39 2023 -0400

    Merge branch 'develop' into report-profile-modal

commit 1e05297e96
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 23 13:12:52 2023 -0400

    package updates

commit 8fe263a377
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 23 12:12:36 2023 -0400

    update(dependencies): ran npm install to update dependencies

commit 190fe048a1
Merge: 3ea48ab5cb fa83d1a9cf
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 23 11:52:08 2023 -0400

    Merge branch 'develop' into report-profile-modal

commit 3ea48ab5cb
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 11 17:12:31 2023 -0400

    WIP(user profile): dropdown menu and toggles and colors oh my

commit c301a2b460
Merge: 1da6af11b5 647b27c55f
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 11 12:40:07 2023 -0400

    Merge branch 'develop' into report-profile-modal

commit 1da6af11b5
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Aug 10 16:50:07 2023 -0400

    WIP(user profile): moved some CSS classes out of unscoped and into the scoped section, started on toggle buttons

commit dd55cbc928
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 9 15:38:46 2023 -0400

    WIP(user profile): workin on the hamburger (kebab?) menu

commit 3834093207
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Aug 8 14:14:40 2023 -0400

    WIP(user profiles): working on the drop down menu

commit f2be588195
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Aug 7 16:10:30 2023 -0400

    WIP(user profile): options menu

commit 010f2299f0
Author: SabreCat <sabe@habitica.com>
Date:   Mon Aug 7 11:49:04 2023 -0500

    fix(lint): eof and const

commit 4551dbf4b3
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Aug 4 15:34:05 2023 -0400

    WIP(user profile): styling the top portion of the modal

commit 19a9fe3644
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Aug 3 15:06:51 2023 -0400

    WIP(user profile): adding buttons

commit dfdb305b1c
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 2 14:41:20 2023 -0400

    WIP(user profile): layout

commit ded4eee693
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Aug 2 12:04:02 2023 -0400

    WIP(user profile): start flex grid & tidy up CSS

commit aaca48be32
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Jul 28 16:44:06 2023 -0400

    WIP(user profile): mostly css updates

commit e531985b87
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Jul 27 16:49:44 2023 -0400

    WIP(user profile): one infinitesimal change that's hardly worth the electricity it's made from

commit eb4021fcc7
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 26 16:33:05 2023 -0400

    feat(content): upgrade profile page

commit 1b25394f3e
Merge: c50cee0d88 8558dcc3a8
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Jul 26 11:50:12 2023 -0400

    Merge branch 'develop' into report-profile-modal

commit c50cee0d88
Author: SabreCat <sabe@habitica.com>
Date:   Wed Jul 12 16:32:25 2023 -0500

    fix(flagging): debug params issue
    Also add and document the "source" body param

commit 55848c58be
Author: SabreCat <sabe@habitica.com>
Date:   Mon Jul 10 16:24:20 2023 -0500

    WIP(members): basic report a user API

commit dda6180792
Author: SabreCat <sabe@habitica.com>
Date:   Thu Jul 6 10:05:07 2023 -0500

    fix(lint): remove console.info
2023-10-03 13:29:26 -05:00
SabreCat
89fff49d02 5.6.0 2023-09-29 15:13:32 -05:00
CuriousMagpie
b8b0d668c9 feat(content): October sub items 2023-09-29 14:51:45 -05:00
SabreCat
1d3006ae29 chore(event): schedule spooky gems 2023-09-27 14:09:50 -05:00
SabreCat
a63cc84779 5.5.0 2023-09-20 19:47:44 -05:00
SabreCat
a06974d354 chore(subproj): update images 2023-09-20 19:47:37 -05:00
Natalie
f72eef6bff feat(content): prebuild Fall Festival (#14869)
* feat(content): prebuild Fall Festival

* fix(typos): because 2023 is not the same as 2024

* feat(css): having stylesheets is important

* feat(content): ready for review & testing

* fix(tests): account for Sept 09 bundle

* fix(gala): use multi event list more
fix a couple of strings too

* feat(content): Warrior and Rogue text
also fix timing of quest bundle feature

* fix(strings): correct stat boosts

* fix(content): missing mage
also adds missing margin to purchase gems button in buy modal

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-09-20 19:46:34 -05:00
SabreCat
9e25360102 5.4.1 2023-09-12 09:46:28 -05:00
SabreCat
ce70c73d49 fix(test): temporarily use real timer 2023-09-12 09:45:40 -05:00
SabreCat
cdd87abcf9 Merge branch 'release' into 2023-09-pet-quest-bundle 2023-09-12 09:42:48 -05:00
dependabot[bot]
6bea232d47 build(deps): bump core-js from 3.32.1 to 3.32.2 in /website/client (#14867)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.32.1 to 3.32.2.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.32.2/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-11 12:55:31 -04:00
dependabot[bot]
cebb3f0f25 build(deps): bump webpack from 4.46.0 to 4.47.0 in /website/client (#14868)
Bumps [webpack](https://github.com/webpack/webpack) from 4.46.0 to 4.47.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.46.0...v4.47.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-11 12:43:49 -04:00
SabreCat
e072d7c09c Merge branch 'develop' into release 2023-09-05 13:39:59 -05:00
Weblate
e332876d30 Merge branch 'origin/develop' into Weblate. 2023-09-05 20:32:36 +02:00
SabreCat
08d71cc0bb 5.4.0 2023-09-05 13:30:26 -05:00
Natalie
c4f870c421 feat(content): add September 2023 Backgrounds and Enchanted Armoire items (#14845)
* feat(content): add Sept 2023 backgrounds and enchanted armoire items

* fix(content): fix broken strings in September items

* chore(sprites): update spritesheet

* fix(strings): w.

* fix(strings): capitalization, missing words

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-09-05 13:23:20 -05:00
Weblate
6421f6bbe0 Translated using Weblate (Portuguese)
Currently translated at 67.8% (152 of 224 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.4% (181 of 182 strings)

Translated using Weblate (Portuguese)

Currently translated at 81.6% (174 of 213 strings)

Translated using Weblate (Portuguese)

Currently translated at 60.2% (135 of 224 strings)

Translated using Weblate (Korean)

Currently translated at 25.0% (38 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 58.7% (1706 of 2905 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Serbian)

Currently translated at 50.0% (4 of 8 strings)

Translated using Weblate (Serbian)

Currently translated at 71.5% (302 of 422 strings)

Translated using Weblate (Serbian)

Currently translated at 59.0% (1714 of 2905 strings)

Translated using Weblate (Serbian)

Currently translated at 50.0% (27 of 54 strings)

Translated using Weblate (Serbian)

Currently translated at 55.7% (449 of 805 strings)

Translated using Weblate (Serbian)

Currently translated at 55.2% (445 of 805 strings)

Translated using Weblate (Serbian)

Currently translated at 53.4% (430 of 805 strings)

Translated using Weblate (Serbian)

Currently translated at 53.2% (429 of 805 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 97.3% (148 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 90.1% (137 of 152 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.5% (793 of 805 strings)

Translated using Weblate (Polish)

Currently translated at 87.5% (133 of 152 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Bartosz Babik <kotka-wali0h@icloud.com>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Kimminjae <aezir07@gmail.com>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Mateus Felipe Ribeiro Ambrósio <mateus.mfr10@gmail.com>
Co-authored-by: Ognjen <ognjenzxz@gmail.com>
Co-authored-by: Raithe <RaitheOfDureya@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt/
Translation: Habitica/Backgrounds
Translation: Habitica/Contrib
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Groups
Translation: Habitica/Overview
Translation: Habitica/Settings
Translation: Habitica/Subscriber
2023-09-05 17:39:52 +02:00
Weblate
ac7c8e0eb6 Merge branch 'origin/develop' into Weblate. 2023-08-30 21:53:35 +02:00
Weblate
7c9df3b32f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Polish)

Currently translated at 89.2% (199 of 223 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 86.9% (194 of 223 strings)

Translated using Weblate (Polish)

Currently translated at 60.7% (1763 of 2901 strings)

Translated using Weblate (Polish)

Currently translated at 60.7% (1763 of 2901 strings)

Translated using Weblate (Polish)

Currently translated at 78.2% (119 of 152 strings)

Co-authored-by: Bartosz Babik <kotka-wali0h@icloud.com>
Co-authored-by: Bogdan Derdziak <bagtirr@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: konhi <hello.konhi@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pl/
Translation: Habitica/Achievements
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Gear
Translation: Habitica/Messages
Translation: Habitica/Pets
Translation: Habitica/Rebirth
Translation: Habitica/Subscriber
2023-08-30 21:53:26 +02:00
SabreCat
edefae72bd 5.3.0 2023-08-30 14:52:04 -05:00
SabreCat
132ecc8bb1 fix(images): correct Tiptop Teapot set 2023-08-30 14:51:23 -05:00
Natalie
ca5b02d0ea feat(content): September 2023 subscriber items (#14844)
* feat(content): add June subscriber items

* feat(content): September subscriber items

* fix(image)

fixed filename for April sub item shop set

* chore(sprites): update habitica-images

* fix(images): add missing subscriber items

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-08-30 14:33:44 -05:00
CuriousMagpie
941194b7c7 feat(content): add September pet quest bundle 2023-08-29 16:59:05 -04:00
Weblate
d8a7cad1a1 Translated using Weblate (Russian)
Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Polish)

Currently translated at 73.0% (111 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 71.7% (109 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 65.7% (100 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Korean)

Currently translated at 24.3% (37 of 152 strings)

Translated using Weblate (Korean)

Currently translated at 60.1% (1746 of 2901 strings)

Translated using Weblate (Polish)

Currently translated at 55.2% (84 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 32.8% (50 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 60.7% (1762 of 2901 strings)

Translated using Weblate (Polish)

Currently translated at 31.5% (48 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (155 of 155 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Russian)

Currently translated at 96.6% (408 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 53.4% (1550 of 2901 strings)

Translated using Weblate (Russian)

Currently translated at 96.8% (217 of 224 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Russian)

Currently translated at 75.0% (114 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Ukrainian)

Currently translated at 52.4% (1522 of 2901 strings)

Translated using Weblate (Russian)

Currently translated at 78.0% (71 of 91 strings)

Translated using Weblate (Ukrainian)

Currently translated at 52.4% (1522 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 52.4% (1522 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Russian)

Currently translated at 65.9% (60 of 91 strings)

Translated using Weblate (Korean)

Currently translated at 20.3% (31 of 152 strings)

Translated using Weblate (Korean)

Currently translated at 98.4% (185 of 188 strings)

Translated using Weblate (Korean)

Currently translated at 73.5% (592 of 805 strings)

Translated using Weblate (Korean)

Currently translated at 59.1% (132 of 223 strings)

Translated using Weblate (Korean)

Currently translated at 81.8% (625 of 764 strings)

Translated using Weblate (Korean)

Currently translated at 59.4% (1726 of 2901 strings)

Translated using Weblate (Korean)

Currently translated at 50.5% (46 of 91 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.1% (410 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 51.8% (1504 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 51.8% (1504 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 51.8% (1504 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.5% (793 of 805 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Bartosz Babik <kotka-wali0h@icloud.com>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Kimminjae <aezir07@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Sabe Jones <sabe@habitica.com>
Co-authored-by: Svetlana <shkulepo@rambler.ru>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Vladyslav <vladignatiuk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 김경은 <kekim.lang@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Subscriber
2023-08-28 22:44:39 +02:00
dependabot[bot]
fa83d1a9cf build(deps-dev): bump sinon from 15.1.2 to 15.2.0 (#14723)
Bumps [sinon](https://github.com/sinonjs/sinon) from 15.1.2 to 15.2.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v15.1.2...v15.2.0)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:35:52 -04:00
dependabot[bot]
d94851f759 build(deps-dev): bump chalk from 5.2.0 to 5.3.0 (#14736)
Bumps [chalk](https://github.com/chalk/chalk) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/compare/v5.2.0...v5.3.0)

---
updated-dependencies:
- dependency-name: chalk
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:33:18 -04:00
dependabot[bot]
2137c190b3 build(deps): bump smartbanner.js in /website/client (#14745)
Bumps [smartbanner.js](https://github.com/ain/smartbanner.js) from 1.19.2 to 1.19.3.
- [Commits](https://github.com/ain/smartbanner.js/compare/v1.19.2...v1.19.3)

---
updated-dependencies:
- dependency-name: smartbanner.js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:32:42 -04:00
dependabot[bot]
428e693711 build(deps): bump jsonwebtoken from 9.0.0 to 9.0.1 (#14747)
Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 9.0.0 to 9.0.1.
- [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:32:14 -04:00
dependabot[bot]
a7aa489960 build(deps): bump winston from 3.9.0 to 3.10.0 (#14759)
Bumps [winston](https://github.com/winstonjs/winston) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.9.0...v3.10.0)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:29:45 -04:00
dependabot[bot]
c917c7c4a9 build(deps): bump fast-xml-parser from 4.2.4 to 4.2.6 (#14768)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 4.2.4 to 4.2.6.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.2.4...v4.2.6)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:27:43 -04:00
dependabot[bot]
e661838ed7 build(deps): bump word-wrap from 1.2.3 to 1.2.4 in /website/client (#14769)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:27:07 -04:00
dependabot[bot]
af09b6b454 build(deps): bump word-wrap from 1.2.3 to 1.2.4 (#14771)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:26:29 -04:00
dependabot[bot]
f8b3891a0c build(deps): bump xml2js from 0.6.0 to 0.6.2 (#14789)
Bumps [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) from 0.6.0 to 0.6.2.
- [Commits](https://github.com/Leonidas-from-XIV/node-xml2js/compare/0.6.0...0.6.2)

---
updated-dependencies:
- dependency-name: xml2js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:25:12 -04:00
dependabot[bot]
631d18244b build(deps): bump rate-limiter-flexible from 2.4.1 to 2.4.2 (#14792)
Bumps [rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/animir/node-rate-limiter-flexible/releases)
- [Commits](https://github.com/animir/node-rate-limiter-flexible/commits)

---
updated-dependencies:
- dependency-name: rate-limiter-flexible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:23:47 -04:00
dependabot[bot]
7883ba8228 chore(deps): bump @babel/preset-env from 7.22.5 to 7.22.10 (#14814)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.22.5 to 7.22.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.10/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:17:58 -04:00
dependabot[bot]
605c2265c5 chore(deps): bump superagent from 8.0.9 to 8.1.2 (#14823)
Bumps [superagent](https://github.com/ladjs/superagent) from 8.0.9 to 8.1.2.
- [Release notes](https://github.com/ladjs/superagent/releases)
- [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/ladjs/superagent/compare/v8.0.9...v8.1.2)

---
updated-dependencies:
- dependency-name: superagent
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:17:30 -04:00
dependabot[bot]
1bb0319012 chore(deps): bump bcrypt from 5.1.0 to 5.1.1 (#14824)
Bumps [bcrypt](https://github.com/kelektiv/node.bcrypt.js) from 5.1.0 to 5.1.1.
- [Release notes](https://github.com/kelektiv/node.bcrypt.js/releases)
- [Changelog](https://github.com/kelektiv/node.bcrypt.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kelektiv/node.bcrypt.js/compare/v5.1.0...v5.1.1)

---
updated-dependencies:
- dependency-name: bcrypt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:17:01 -04:00
dependabot[bot]
1f0fd7d8b4 chore(deps): bump core-js from 3.31.0 to 3.32.1 in /website/client (#14827)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.31.0 to 3.32.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.32.1/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:13:07 -04:00
dependabot[bot]
6b4b53a430 chore(deps): bump intro.js from 7.0.1 to 7.2.0 in /website/client (#14828)
Bumps [intro.js](https://github.com/usablica/intro.js) from 7.0.1 to 7.2.0.
- [Release notes](https://github.com/usablica/intro.js/releases)
- [Changelog](https://github.com/usablica/intro.js/blob/master/tsconfig.release.json)
- [Commits](https://github.com/usablica/intro.js/compare/v7.0.1...v7.2.0)

---
updated-dependencies:
- dependency-name: intro.js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 14:12:31 -04:00
SabreCat
331ea18c42 Merge branch 'develop' into release 2023-08-22 12:33:29 -05:00
Weblate
db53d87cba Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 50.1% (1455 of 2901 strings)

Translated using Weblate (Croatian)

Currently translated at 87.2% (328 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 49.3% (1431 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (799 of 805 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2867 of 2901 strings)

Translated using Weblate (Portuguese)

Currently translated at 61.1% (1775 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 64.4% (98 of 152 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Japanese)

Currently translated at 98.4% (129 of 131 strings)

Translated using Weblate (Ukrainian)

Currently translated at 49.0% (1422 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.8% (1418 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.8% (1417 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.6% (1410 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.6% (1410 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2867 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.7% (375 of 376 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2867 of 2901 strings)

Translated using Weblate (Portuguese)

Currently translated at 61.1% (1775 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.5% (222 of 223 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.5% (1407 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.8% (2867 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 64.4% (98 of 152 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.9% (186 of 188 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.5% (793 of 805 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.0% (1393 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 48.0% (1393 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1392 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1392 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1391 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1391 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1390 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.9% (1390 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1389 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1389 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1388 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1388 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1387 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.8% (1387 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.7% (1386 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.7% (1386 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.7% (1385 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.7% (1385 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1383 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1383 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1382 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1382 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1381 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.6% (1381 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1380 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1380 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1379 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1379 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1378 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.5% (1378 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.3% (1373 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.2% (1371 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.2% (1370 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.1% (1369 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.1% (1369 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.1% (1369 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.1% (1367 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.1% (1367 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.0% (1366 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.0% (1366 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 47.0% (1364 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.8% (1358 of 2901 strings)

Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Deni Zubin <deni.zubin@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Vladyslav <vladignatiuk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 照水 <d332zms@hotmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/content/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Gear
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Questscontent
Translation: Habitica/Subscriber
2023-08-22 19:34:17 +02:00
SabreCat
ebebbbaac5 5.2.0 2023-08-22 12:25:30 -05:00
SabreCat
63376b918e Squashed commit of the following:
commit b7fb903dcab2dbdc55ddd27e9cbd8054f0d5e2a8
Author: SabreCat <sabe@habitica.com>
Date:   Sat Aug 19 19:44:42 2023 -0500

    fix(invites): add missing param

commit 30053cc8b86fc1992d872a068e60f3dd5a456a07
Author: SabreCat <sabe@habitica.com>
Date:   Sat Aug 19 19:06:51 2023 -0500

    fix(party): enforce size limit when using @-names

commit 62dd314cda4165bedbc6b490a8e2f21de87deaf4
Author: SabreCat <sabe@habitica.com>
Date:   Sat Aug 19 19:01:15 2023 -0500

    Revert "Revert "fix(parties): actual 30 not 29""

    This reverts commit 63414a80fe.
2023-08-22 12:25:17 -05:00
SabreCat
ba96cd6e24 Squashed commit of the following:
commit 22971a0c0bd1c25e147fdc9d662fd55ca522193b
Author: SabreCat <sabe@habitica.com>
Date:   Fri Aug 18 21:13:49 2023 -0500

    fix(auth): don't mix include/exclude

commit efbb8fa136587a4c781660246cb426968cfe108a
Author: SabreCat <sabe@habitica.com>
Date:   Fri Aug 18 20:51:30 2023 -0500

    refactor(auth): remove unneeded query field
2023-08-22 12:24:16 -05:00
SabreCat
9e0e2a83be Squashed commit of the following:
commit 474fa530a0392ff6e7461eaff64c81a67b5e4eff
Author: SabreCat <sabe@habitica.com>
Date:   Fri Aug 18 21:44:09 2023 -0500

    fix(challenges): filter out groups without perms
2023-08-22 12:23:39 -05:00
SabreCat
1fa926ac04 Squashed commit of the following:
commit 91d5efa683bb2f1c71b291fab4ff5924bddae1ce
Author: SabreCat <sabe@habitica.com>
Date:   Fri Aug 18 22:18:57 2023 -0500

    refactor(static): remove broken, unused apps page
2023-08-22 12:23:20 -05:00
SabreCat
c71f0b3fda Squashed commit of the following:
commit 6d74f87db332fd28c7522cabc0f96a390d36e64f
Author: SabreCat <sabe@habitica.com>
Date:   Fri Aug 18 20:04:52 2023 -0500

    fix(i18n): default to EN for empties
2023-08-22 12:23:02 -05:00
Natalie L
e8f5958f77 feat(content): add boneless boss achievement (#14788)
* feat(content): add June subscriber items

* feat(content): add boneless boss achievement

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-08-22 12:23:43 -05:00
SabreCat
2803db73e5 5.1.4 2023-08-17 15:39:35 -05:00
SabreCat
0f9adf6675 Merge branch 'sabrecat/more-group-fixes' into release 2023-08-17 15:29:36 -05:00
SabreCat
63414a80fe Revert "fix(parties): actual 30 not 29"
This reverts commit bf0e640fa6.
2023-08-17 14:22:33 -05:00
SabreCat
e73e8bfb9e Revert "fix(parties): actual 30 not 29"
This reverts commit bf0e640fa6.
2023-08-16 16:56:01 -05:00
SabreCat
694fe5a273 Merge branch 'develop' into release 2023-08-16 16:40:49 -05:00
Weblate
82ebe71eb4 Translated using Weblate (Ukrainian)
Currently translated at 46.8% (1358 of 2901 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (419 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.8% (1358 of 2901 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.7% (1356 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (91 of 91 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.3% (800 of 805 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.7% (1356 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.7% (1356 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 46.4% (1348 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.1% (112 of 113 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (419 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 45.5% (1321 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 45.5% (1320 of 2901 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 45.3% (1316 of 2901 strings)

Translated using Weblate (Ukrainian)

Currently translated at 44.5% (1293 of 2901 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.1% (410 of 422 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (419 of 422 strings)

Translated using Weblate (French)

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 44.8% (1292 of 2881 strings)

Translated using Weblate (Japanese)

Currently translated at 99.5% (223 of 224 strings)

Translated using Weblate (French)

Currently translated at 46.7% (71 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 72.5% (66 of 91 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.6% (57 of 91 strings)

Translated using Weblate (Japanese)

Currently translated at 64.8% (59 of 91 strings)

Translated using Weblate (French)

Currently translated at 80.2% (73 of 91 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (French)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (French)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (French)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (French)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (French)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (French)

Currently translated at 99.5% (420 of 422 strings)

Translated using Weblate (French)

Currently translated at 100.0% (2881 of 2881 strings)

Translated using Weblate (French)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (French)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (French)

Currently translated at 44.7% (68 of 152 strings)

Translated using Weblate (French)

Currently translated at 65.9% (60 of 91 strings)

Translated using Weblate (French)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (French)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (French)

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Ukrainian)

Currently translated at 44.3% (1279 of 2881 strings)

Translated using Weblate (French)

Currently translated at 99.2% (2860 of 2881 strings)

Translated using Weblate (French)

Currently translated at 37.5% (57 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 68.1% (62 of 91 strings)

Translated using Weblate (Arabic)

Currently translated at 90.4% (340 of 376 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (113 of 113 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Japanese)

Currently translated at 94.7% (400 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 43.3% (1250 of 2881 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.6% (57 of 91 strings)

Translated using Weblate (Russian)

Currently translated at 97.8% (46 of 47 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (131 of 131 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.3% (398 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (422 of 422 strings)

Translated using Weblate (Ukrainian)

Currently translated at 42.7% (1231 of 2881 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (224 of 224 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 61.5% (56 of 91 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (213 of 213 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 93.6% (395 of 422 strings)

Co-authored-by: Ali Adnan <ali0088552211@gmail.com>
Co-authored-by: Carlos Henrique Silva <marcoantoniobad@gmail.com>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Jerry Chen <minecjraft@qq.com>
Co-authored-by: Lucas Fieri <lucasfieri@gmail.com>
Co-authored-by: Sha Kong-Brooks <sha.kongbrooks@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Vladyslav <vladignatiuk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Естай <akseleu@yahoo.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ar/
Translate-URL: https://translate.habitica.com/projects/habitica/content/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/death/en_GB/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/front/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/front/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Death
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Subscriber
2023-08-16 23:02:00 +02:00
SabreCat
58d58ff962 fix(guilds): correct various errors 2023-08-16 15:56:10 -05:00
SabreCat
04dcb27501 5.1.3 2023-08-16 15:01:54 -05:00
SabreCat
c9395ba1ca fix(strings): patch up Orb, quests, potions 2023-08-16 15:01:41 -05:00
SabreCat
e9845e7b01 Merge branch 'release' into develop 2023-08-15 15:51:20 -05:00
SabreCat
faa7ff6328 5.1.2 2023-08-15 15:51:10 -05:00
SabreCat
50cc7ee09a fix(profile): skip redundant navigation 2023-08-15 15:48:30 -05:00
SabreCat
db56134832 Merge branch 'sabrecat/leave-challenge' into release 2023-08-15 15:32:23 -05:00
SabreCat
1ea954ab10 fix(challenge): don't pierce privacy on GET/:id 2023-08-15 15:21:28 -05:00
SabreCat
e405372319 Merge branch 'release' into develop 2023-08-15 14:55:06 -05:00
SabreCat
8f64afe9df fix(challenges): leave chal from invalid group 2023-08-15 14:54:22 -05:00
SabreCat
bf0e640fa6 fix(parties): actual 30 not 29 2023-08-15 14:33:32 -05:00
SabreCat
a6792a4f08 5.1.1 2023-08-14 14:36:49 -05:00
SabreCat
0007736f5c Merge branch 'sabrecat/distant-cliff' into release 2023-08-14 14:36:41 -05:00
Natalie L
d564944507 feat(content): add August Pet Quest Bundles and Magic Hatching Potions (#14786)
* feat(content): add June subscriber items

* feat(content): add August pet quest bundle and magic hatching potions

* fix(time): updated start time to 0800EDT

* fix(content): correct start date for potions

---------

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-08-14 14:37:42 -05:00
negue
b679cfb935 Split Vue.Router routes (#14812) 2023-08-11 15:34:59 -05:00
SabreCat
464e4f10b2 feat(chats): increase chat entries to 400 2023-08-11 14:34:27 -05:00
SabreCat
647b27c55f Merge branch 'release' into develop 2023-08-10 16:32:27 -05:00
SabreCat
ac4e6490d9 5.1.0 2023-08-10 12:52:42 -05:00
SabreCat
a3784e98a3 fix(gear): correct stat assignment 2023-08-10 12:52:02 -05:00
SabreCat
5931f02692 feat(content): 2023 August Armoire and Backgrounds by @CuriousMagpie 2023-08-10 12:36:48 -05:00
SabreCat
e21aa074e4 5.0.1 2023-08-08 14:47:44 -05:00
SabreCat
fd038bd150 fix(groups): redirect guild url to group plan 2023-08-08 13:44:21 -05:00
Weblate
699be3a3cc Merge branch 'origin/develop' into Weblate. 2023-08-08 16:28:31 +02:00
SabreCat
bb7e0e22ec 5.0.0 2023-08-08 09:24:27 -05:00
SabreCat
a79a088a8f Merge branch 'sabrecat/unsociable' into release 2023-08-08 09:24:06 -05:00
SabreCat
60c0e6b3df fix(lint): whitespace 2023-08-08 01:26:56 -05:00
SabreCat
43c10f75c3 fix(lint): arrow fn 2023-08-08 01:08:11 -05:00
SabreCat
d4e3e83d46 fix(challenges): map IDs 2023-08-07 23:53:55 -05:00
SabreCat
013f8bcca7 fix(challenges): fetch purchased 2023-08-07 22:56:58 -05:00
SabreCat
ebd0cb72de fix(challenges): better screening 2023-08-07 22:26:56 -05:00
SabreCat
c44b1670cf fix(challenges): revert to working 2023-08-07 22:00:47 -05:00
SabreCat
39477c6f11 fix(lint): or/and, import 2023-08-07 21:33:31 -05:00
SabreCat
1371b80635 fix(groups): add back string
also fix party seeking analytics and a spurious text decoration
2023-08-07 15:55:29 -05:00
SabreCat
9fa355fbcc fix(sunset): release candidate 2023-08-07 15:04:44 -05:00
Weblate
b594d2bb29 Translated using Weblate (French)
Currently translated at 97.7% (218 of 223 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (420 of 420 strings)

Translated using Weblate (Ukrainian)

Currently translated at 42.7% (1230 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (150 of 150 strings)

Translated using Weblate (Persian)

Currently translated at 10.5% (16 of 152 strings)

Translated using Weblate (French)

Currently translated at 97.3% (217 of 223 strings)

Translated using Weblate (Turkish)

Currently translated at 81.8% (108 of 132 strings)

Translated using Weblate (Turkish)

Currently translated at 75.0% (6 of 8 strings)

Translated using Weblate (Turkish)

Currently translated at 52.3% (144 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 41.8% (1204 of 2875 strings)

Translated using Weblate (Turkish)

Currently translated at 59.7% (1718 of 2875 strings)

Translated using Weblate (French)

Currently translated at 98.5% (2833 of 2875 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Ukrainian)

Currently translated at 93.3% (140 of 150 strings)

Translated using Weblate (French)

Currently translated at 34.6% (52 of 150 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Turkish)

Currently translated at 62.7% (501 of 798 strings)

Translated using Weblate (Italian)

Currently translated at 98.8% (789 of 798 strings)

Translated using Weblate (French)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 76.2% (93 of 122 strings)

Translated using Weblate (Filipino)

Currently translated at 80.9% (646 of 798 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Ukrainian)

Currently translated at 40.9% (1176 of 2875 strings)

Translated using Weblate (Russian)

Currently translated at 98.7% (2838 of 2875 strings)

Translated using Weblate (Indonesian)

Currently translated at 84.3% (2425 of 2875 strings)

Translated using Weblate (Russian)

Currently translated at 65.3% (98 of 150 strings)

Translated using Weblate (Dutch)

Currently translated at 97.3% (146 of 150 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (150 of 150 strings)

Translated using Weblate (Polish)

Currently translated at 95.9% (766 of 798 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (420 of 420 strings)

Translated using Weblate (Indonesian)

Currently translated at 72.6% (109 of 150 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Ukrainian)

Currently translated at 39.4% (1134 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 71.3% (107 of 150 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 98.5% (135 of 137 strings)

Translated using Weblate (Polish)

Currently translated at 86.0% (192 of 223 strings)

Translated using Weblate (Polish)

Currently translated at 99.2% (131 of 132 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Polish)

Currently translated at 99.5% (418 of 420 strings)

Translated using Weblate (Ukrainian)

Currently translated at 38.1% (1097 of 2875 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 98.1% (216 of 220 strings)

Translated using Weblate (Polish)

Currently translated at 96.4% (405 of 420 strings)

Translated using Weblate (Ukrainian)

Currently translated at 38.0% (1093 of 2875 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 59.3% (1706 of 2875 strings)

Translated using Weblate (Galician)

Currently translated at 95.7% (45 of 47 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (420 of 420 strings)

Translated using Weblate (Korean)

Currently translated at 73.5% (587 of 798 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Ukrainian)

Currently translated at 37.9% (1090 of 2875 strings)

Translated using Weblate (Korean)

Currently translated at 29.2% (31 of 106 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 57.5% (61 of 106 strings)

Translated using Weblate (German)

Currently translated at 71.6% (76 of 106 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Filipino)

Currently translated at 78.3% (625 of 798 strings)

Translated using Weblate (Filipino)

Currently translated at 85.4% (358 of 419 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Ukrainian)

Currently translated at 37.6% (1081 of 2875 strings)

Translated using Weblate (Indonesian)

Currently translated at 79.4% (2285 of 2875 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (German)

Currently translated at 99.2% (131 of 132 strings)

Translated using Weblate (German)

Currently translated at 83.6% (102 of 122 strings)

Translated using Weblate (German)

Currently translated at 99.4% (187 of 188 strings)

Translated using Weblate (Russian)

Currently translated at 99.2% (792 of 798 strings)

Translated using Weblate (German)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (Ukrainian)

Currently translated at 36.6% (1054 of 2875 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (French)

Currently translated at 98.5% (2832 of 2875 strings)

Translated using Weblate (French)

Currently translated at 98.2% (2825 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 35.1% (1011 of 2875 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Ukrainian)

Currently translated at 34.0% (980 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 32.8% (945 of 2875 strings)

Translated using Weblate (Indonesian)

Currently translated at 78.8% (2266 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 32.4% (933 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 78.4% (2256 of 2875 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (131 of 132 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.9% (402 of 419 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 95.9% (402 of 419 strings)

Translated using Weblate (Ukrainian)

Currently translated at 32.1% (924 of 2875 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (Dutch)

Currently translated at 92.2% (736 of 798 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.4% (786 of 798 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Indonesian)

Currently translated at 78.1% (2246 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 32.1% (924 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 31.4% (903 of 2875 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Indonesian)

Currently translated at 77.7% (2236 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 30.8% (887 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Ukrainian)

Currently translated at 30.7% (884 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 97.3% (744 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 96.0% (734 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 96.0% (734 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (223 of 223 strings)

Translated using Weblate (Ukrainian)

Currently translated at 30.7% (884 of 2875 strings)

Translated using Weblate (Indonesian)

Currently translated at 77.4% (2226 of 2875 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.0% (105 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 95.5% (730 of 764 strings)

Translated using Weblate (Czech)

Currently translated at 85.5% (130 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 98.6% (2837 of 2875 strings)

Translated using Weblate (Russian)

Currently translated at 99.4% (187 of 188 strings)

Translated using Weblate (Russian)

Currently translated at 99.1% (791 of 798 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Russian)

Currently translated at 98.1% (218 of 222 strings)

Translated using Weblate (Indonesian)

Currently translated at 77.0% (2216 of 2875 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (English (en@lolcat))

Currently translated at 28.9% (44 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 29.0% (833 of 2871 strings)

Translated using Weblate (Indonesian)

Currently translated at 76.9% (2207 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.1% (104 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 94.6% (723 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (Dutch)

Currently translated at 91.6% (731 of 798 strings)

Translated using Weblate (Polish)

Currently translated at 61.1% (1755 of 2871 strings)

Co-authored-by: @SpiffZyx <spiffzyx@icloud.com>
Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Alejo González <alejoplus.max@gmail.com>
Co-authored-by: Ali Ghaffaari <ali.ghaffaari@gmail.com>
Co-authored-by: Antonio <nikola.orwell@gmail.com>
Co-authored-by: Bogdan Derdziak <bagtirr@gmail.com>
Co-authored-by: Brooke Abbey <brookeoclock@gmail.com>
Co-authored-by: BryanLim <youmakemysonlooklikeelonmusk@gmail.com>
Co-authored-by: Dahae Kim <SuperCoonMochi@gmail.com>
Co-authored-by: Deni Zubin <deni.zubin@gmail.com>
Co-authored-by: Ellen A M <ellen_a_m@hotmail.com>
Co-authored-by: Emmanuel Kan <berinojke@gmail.com>
Co-authored-by: Falzart <muh_fauzi_ramadhan@yahoo.co.id>
Co-authored-by: HenryFord <mihka2018geimer@gmail.com>
Co-authored-by: Jerry Chen <minecjraft@qq.com>
Co-authored-by: Julian H <julian.henin29@gmail.com>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Lolzia <zuzaksup@gmail.com>
Co-authored-by: Mandy Mielke <mielkemandy@outlook.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Nodaysoff <convoron@yandex.ru>
Co-authored-by: Raithe <RaitheOfDureya@gmail.com>
Co-authored-by: Rémi <rem130499@gmail.com>
Co-authored-by: Sergey Shevelev <vlkgamer45@gmail.com>
Co-authored-by: Sofia <cornaasasa@gmail.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Val <3qes0hnzh@mozmail.com>
Co-authored-by: Vanadium <v1512137980@gmail.com>
Co-authored-by: Vlada <vladaplisak@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: billypat <kreideraine@gmail.com>
Co-authored-by: sam de wit <samedewit@gmail.com>
Co-authored-by: Естай <akseleu@yahoo.com>
Co-authored-by: 照水 <d332zms@hotmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/cs/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@lolcat/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fa/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fil/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/fil/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/character/de/
Translate-URL: https://translate.habitica.com/projects/habitica/character/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/character/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/de/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/id/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/fil/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/id/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/front/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/front/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/id/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/fil/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/id/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/id/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pl/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Contrib
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-08-07 19:59:53 +02:00
SabreCat
a8b52ab656 fix(chat): correctly map CG bullet points 2023-08-07 12:51:19 -05:00
SabreCat
cce6d91611 fix(groups): return Plans on GET guilds 2023-08-07 12:24:43 -05:00
SabreCat
3109a03055 fix(sunset): Challenge filtering, transactions 2023-08-03 16:30:00 -05:00
SabreCat
14518b8213 fix(tests): avoid mystery pollution in challenges 2023-08-02 20:35:52 -05:00
SabreCat
3ad31c7cd0 fix(tests): release candidate 2023-08-02 20:04:09 -05:00
SabreCat
bfa6d24e47 fix(lint): whoops only 2023-08-02 18:33:40 -05:00
SabreCat
8c88f56d08 fix(tests): chat related 2023-08-02 18:07:19 -05:00
SabreCat
1df3f9d9f3 fix(tests): lint, GET group-plans 2023-08-02 17:00:41 -05:00
SabreCat
b5a0dad7f7 fix(tests): GET groups 2023-08-02 16:48:41 -05:00
SabreCat
9b34c3e11a fix(tests): GET invites 2023-08-02 16:17:16 -05:00
SabreCat
9d61bd724a fix(tests): GET members 2023-08-02 16:02:53 -05:00
SabreCat
13c21139dd fix(tests): GET groups 2023-08-02 15:14:02 -05:00
SabreCat
8e85de53cb fix(tests): POST groups 2023-08-01 20:35:00 -05:00
SabreCat
bf222351e5 4.277.4 2023-08-01 18:38:31 -05:00
SabreCat
6867aab74b fix(faq): better mobile routing, new q 2023-08-01 18:38:21 -05:00
SabreCat
0cae808b7e fix(lint): more destructuring fanciness 2023-08-01 17:45:09 -05:00
SabreCat
81be8316a0 fix(lint): why weren't we destructuring already 2023-08-01 17:20:00 -05:00
SabreCat
d7071d6b4d fix(tests): leave/reject/quests 2023-08-01 16:53:48 -05:00
SabreCat
150cd16b1c Merge branch 'release' into sabrecat/unsociable 2023-08-01 15:27:16 -05:00
SabreCat
38ac4c53d1 4.277.3 2023-08-01 13:44:54 -05:00
SabreCat
9b8bb99039 fix(profile): revert accidental changes 2023-08-01 13:44:49 -05:00
SabreCat
f8bcc81fe6 4.277.2 2023-08-01 13:02:00 -05:00
SabreCat
cc18acd69a Merge branch 'sabrecat/chat-warning' into release 2023-08-01 13:01:15 -05:00
SabreCat
c5a2e5a2e0 fix(chat): fill in the blank 2023-07-31 19:25:07 -05:00
SabreCat
1532f8f774 Merge branch 'sabrecat/chat-warning' into sabrecat/unsociable 2023-07-31 18:44:43 -05:00
SabreCat
aa4426c800 fix(event): corrections to contributor goodies 2023-07-31 18:44:08 -05:00
SabreCat
0140b9beb7 feat(chat): veteran awards 2023-07-31 16:38:30 -05:00
SabreCat
8f92993045 4.277.1 2023-07-31 12:10:32 -05:00
SabreCat
7697d87358 Merge branch 'develop' into sabrecat/unsociable 2023-07-31 12:08:58 -05:00
SabreCat
712205d253 Merge branch 'develop' into sabrecat/chat-warning 2023-07-31 12:07:48 -05:00
Sabe Jones
ede036e94b Universal routing for migrations (#14772)
* refactor(notifs): universal routing for migrations

* fix(lint): remove whitespace

* chore(content): update migration for new scheme

* fix(migration): account for cake

* chore(images): update sprite CSS

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-07-31 12:07:46 -05:00
SabreCat
67c16c137b Merge branch 'release' into develop 2023-07-31 12:07:26 -05:00
SabreCat
c2ced5c925 fix(tests): manyfix 2023-07-28 16:29:51 -05:00
SabreCat
b09ae3f053 fix(lint): commas etc 2023-07-28 16:15:35 -05:00
SabreCat
4c60371ebd fix(tests): fix fix fix 2023-07-28 16:08:14 -05:00
SabreCat
16be591ed8 fix(tests): subscriptions, group updates 2023-07-28 15:03:56 -05:00
SabreCat
f75a4f6982 fix(tests): quest block 2023-07-28 14:27:36 -05:00
SabreCat
330c3e1bf6 fix(lint): remove unused fn 2023-07-27 16:34:29 -05:00
SabreCat
0ba3cd3bdf fix(tests): cleanup continues 2023-07-27 16:18:25 -05:00
SabreCat
2cfe11619a fix(lint): quotes, destructuring, space 2023-07-26 17:09:29 -05:00
SabreCat
7607c67070 fix(tests): update challenges 2023-07-26 16:59:57 -05:00
CuriousMagpie
652dfa6ecc feat(content): upgrade profile page 2023-07-26 16:33:05 -04:00
SabreCat
d394858022 fix(tests): new approach attempt 2023-07-25 18:00:31 -05:00
SabreCat
26f5ef093f fix(tests): update Challenges block for sunset 2023-07-25 15:39:17 -05:00
SabreCat
714319d67b Merge branch 'sabrecat/item-notification-url' of https://github.com/HabitRPG/habitica into sabrecat/unsociable 2023-07-25 15:37:28 -05:00
SabreCat
cbaa3180cc Merge branch 'develop' into sabrecat/unsociable 2023-07-25 15:17:13 -05:00
SabreCat
b4866fd3b1 chore(content): update migration for new scheme 2023-07-25 15:09:50 -05:00
SabreCat
86646bbbdb Merge branch 'develop' into sabrecat/item-notification-url 2023-07-25 14:42:21 -05:00
SabreCat
5c4aa664b5 4.277.0 2023-07-25 14:17:04 -05:00
SabreCat
184a9df775 Merge branch 'develop' into release 2023-07-25 14:16:54 -05:00
Phillip Thelen
754d46f1f3 Optimise looking for party request (#14773)
* Reset looking for party state if a user joins a party

* filter out users that already received an invite in query

* fix(lfp): add back in-party filter
Temporary until migration to clear seeking flag from users in party

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-07-25 14:16:03 -05:00
Sabe Jones
683649ff1a Don't collapse different spell targets in party chat (#14775)
* fix(spells): don't collapse different targets

* fix(lint): indentation

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-07-25 14:15:12 -05:00
Natalie L
08ac059a7f feat(content): add August 2023 subscriber items (#14784)
* feat(content): add June subscriber items

* feat(content): add August subscriber items
2023-07-25 14:14:28 -05:00
Weblate
7c9b0f207c Merge branch 'origin/develop' into Weblate. 2023-07-25 21:11:35 +02:00
Weblate
f193b8de2c Translated using Weblate (English (en@lolcat))
Currently translated at 5.5% (44 of 798 strings)

Translated using Weblate (English (en@lolcat))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Russian)

Currently translated at 98.8% (2837 of 2871 strings)

Translated using Weblate (Ukrainian)

Currently translated at 90.5% (692 of 764 strings)

Translated using Weblate (Dutch)

Currently translated at 91.3% (729 of 798 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Japanese)

Currently translated at 99.6% (2862 of 2871 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (English (en@lolcat))

Currently translated at 3.6% (29 of 798 strings)

Translated using Weblate (Indonesian)

Currently translated at 76.6% (2197 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 85.2% (651 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 99.4% (187 of 188 strings)

Translated using Weblate (Japanese)

Currently translated at 99.2% (792 of 798 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 76.2% (2187 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 29.0% (833 of 2871 strings)

Translated using Weblate (Russian)

Currently translated at 98.5% (2830 of 2871 strings)

Translated using Weblate (Russian)

Currently translated at 98.5% (2830 of 2871 strings)

Translated using Weblate (Ukrainian)

Currently translated at 84.4% (645 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 84.2% (644 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 75.9% (2177 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (188 of 188 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (French)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 83.6% (639 of 764 strings)

Translated using Weblate (French)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (French)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 75.5% (2167 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 83.6% (639 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 75.2% (2157 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 82.9% (634 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 29.0% (833 of 2871 strings)

Translated using Weblate (Indonesian)

Currently translated at 74.8% (2147 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 81.4% (622 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Ukrainian)

Currently translated at 78.1% (597 of 764 strings)

Translated using Weblate (Croatian)

Currently translated at 77.0% (94 of 122 strings)

Translated using Weblate (Indonesian)

Currently translated at 74.5% (2137 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 77.7% (594 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 74.1% (2127 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 77.4% (592 of 764 strings)

Translated using Weblate (Vietnamese)

Currently translated at 97.3% (148 of 152 strings)

Translated using Weblate (Dutch)

Currently translated at 86.6% (2484 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 73.8% (2117 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.8% (587 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 29.0% (833 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 73.4% (2107 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 72.7% (2087 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 72.2% (2071 of 2867 strings)

Translated using Weblate (Spanish)

Currently translated at 51.8% (55 of 106 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 46.2% (49 of 106 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 74.5% (91 of 122 strings)

Translated using Weblate (Indonesian)

Currently translated at 71.9% (2064 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 71.6% (2054 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 97.1% (103 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.6% (822 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.6% (822 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.5% (819 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.5% (819 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.5% (819 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.5% (819 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 71.2% (2043 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 81.1% (86 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 81.1% (86 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 81.1% (86 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 76.7% (586 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.0% (573 of 764 strings)

Translated using Weblate (Dutch)

Currently translated at 86.6% (2483 of 2867 strings)

Translated using Weblate (Dutch)

Currently translated at 99.1% (121 of 122 strings)

Translated using Weblate (Indonesian)

Currently translated at 70.9% (2033 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 70.5% (2024 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 70.1% (2011 of 2867 strings)

Translated using Weblate (Russian)

Currently translated at 99.7% (789 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 69.2% (1984 of 2867 strings)

Translated using Weblate (Korean)

Currently translated at 73.8% (584 of 791 strings)

Translated using Weblate (Croatian)

Currently translated at 75.4% (92 of 122 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.8% (1974 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.6% (1968 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.6% (1968 of 2867 strings)

Translated using Weblate (Latvian)

Currently translated at 23.5% (25 of 106 strings)

Translated using Weblate (Latvian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.3% (1959 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.3% (1959 of 2867 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.3% (1959 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.3% (1959 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 68.0% (1950 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 67.1% (1926 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 67.1% (1924 of 2867 strings)

Translated using Weblate (Dutch)

Currently translated at 68.8% (73 of 106 strings)

Translated using Weblate (Latvian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Japanese)

Currently translated at 97.6% (409 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.9% (1919 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Latvian)

Currently translated at 70.3% (107 of 152 strings)

Translated using Weblate (Japanese)

Currently translated at 99.7% (2860 of 2867 strings)

Translated using Weblate (Japanese)

Currently translated at 99.5% (221 of 222 strings)

Translated using Weblate (Japanese)

Currently translated at 99.7% (2860 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Turkish)

Currently translated at 62.9% (498 of 791 strings)

Translated using Weblate (Belarusian)

Currently translated at 23.0% (35 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 98.6% (150 of 152 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Turkish)

Currently translated at 96.8% (91 of 94 strings)

Translated using Weblate (Ukrainian)

Currently translated at 28.4% (816 of 2867 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Belarusian)

Currently translated at 17.1% (26 of 152 strings)

Translated using Weblate (Belarusian)

Currently translated at 11.1% (17 of 152 strings)

Translated using Weblate (Dutch)

Currently translated at 86.5% (2480 of 2867 strings)

Translated using Weblate (Dutch)

Currently translated at 65.0% (69 of 106 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Korean)

Currently translated at 73.1% (579 of 791 strings)

Translated using Weblate (Croatian)

Currently translated at 91.7% (167 of 182 strings)

Translated using Weblate (Croatian)

Currently translated at 53.6% (119 of 222 strings)

Translated using Weblate (Croatian)

Currently translated at 80.7% (617 of 764 strings)

Translated using Weblate (Croatian)

Currently translated at 67.0% (63 of 94 strings)

Translated using Weblate (Croatian)

Currently translated at 88.9% (194 of 218 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Croatian)

Currently translated at 81.9% (308 of 376 strings)

Translated using Weblate (Croatian)

Currently translated at 63.1% (77 of 122 strings)

Translated using Weblate (Croatian)

Currently translated at 71.8% (158 of 220 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 79.2% (84 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.0% (573 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 97.7% (217 of 222 strings)

Translated using Weblate (Dutch)

Currently translated at 95.4% (212 of 222 strings)

Translated using Weblate (Turkish)

Currently translated at 75.8% (318 of 419 strings)

Translated using Weblate (Ukrainian)

Currently translated at 73.5% (78 of 106 strings)

Translated using Weblate (Dutch)

Currently translated at 51.8% (55 of 106 strings)

Translated using Weblate (Dutch)

Currently translated at 91.7% (726 of 791 strings)

Translated using Weblate (Turkish)

Currently translated at 59.2% (469 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Portuguese)

Currently translated at 61.9% (1775 of 2867 strings)

Translated using Weblate (Polish)

Currently translated at 96.0% (146 of 152 strings)

Translated using Weblate (Polish)

Currently translated at 61.1% (1754 of 2867 strings)

Translated using Weblate (Polish)

Currently translated at 75.9% (580 of 764 strings)

Translated using Weblate (Polish)

Currently translated at 96.4% (763 of 791 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Ukrainian)

Currently translated at 64.1% (68 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 64.1% (68 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.0% (573 of 764 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.8% (414 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Polish)

Currently translated at 96.3% (762 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Croatian)

Currently translated at 79.5% (105 of 132 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Croatian)

Currently translated at 72.0% (302 of 419 strings)

Translated using Weblate (Croatian)

Currently translated at 61.4% (75 of 122 strings)

Translated using Weblate (Polish)

Currently translated at 95.5% (756 of 791 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Croatian)

Currently translated at 27.3% (29 of 106 strings)

Translated using Weblate (Croatian)

Currently translated at 78.7% (104 of 132 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Croatian)

Currently translated at 61.4% (75 of 122 strings)

Translated using Weblate (Croatian)

Currently translated at 71.3% (157 of 220 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Japanese)

Currently translated at 98.9% (756 of 764 strings)

Translated using Weblate (Turkish)

Currently translated at 72.9% (89 of 122 strings)

Translated using Weblate (Polish)

Currently translated at 95.3% (754 of 791 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2867 of 2867 strings)

Translated using Weblate (Turkish)

Currently translated at 46.2% (49 of 106 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (15 of 15 strings)

Translated using Weblate (Turkish)

Currently translated at 73.5% (562 of 764 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 95.1% (753 of 791 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Turkish)

Currently translated at 71.3% (87 of 122 strings)

Translated using Weblate (Arabic)

Currently translated at 23.5% (25 of 106 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Turkish)

Currently translated at 48.0% (132 of 275 strings)

Translated using Weblate (Turkish)

Currently translated at 75.6% (317 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Turkish)

Currently translated at 41.5% (44 of 106 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Turkish)

Currently translated at 93.6% (44 of 47 strings)

Translated using Weblate (Turkish)

Currently translated at 93.4% (142 of 152 strings)

Translated using Weblate (Korean)

Currently translated at 72.9% (577 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Translated using Weblate (Polish)

Currently translated at 94.5% (748 of 791 strings)

Translated using Weblate (Polish)

Currently translated at 94.5% (748 of 791 strings)

Translated using Weblate (Polish)

Currently translated at 94.5% (748 of 791 strings)

Translated using Weblate (Polish)

Currently translated at 94.0% (744 of 791 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (2808 of 2867 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2867 of 2867 strings)

Translated using Weblate (Russian)

Currently translated at 99.6% (761 of 764 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Russian)

Currently translated at 99.6% (788 of 791 strings)

Translated using Weblate (Polish)

Currently translated at 94.0% (744 of 791 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Russian)

Currently translated at 98.1% (218 of 222 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Russian)

Currently translated at 98.8% (414 of 419 strings)

Translated using Weblate (Russian)

Currently translated at 99.4% (760 of 764 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (222 of 222 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.5% (1909 of 2867 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Ana Beatriz <anabeatriz.augusto06@yahoo.com>
Co-authored-by: Anony Moly <supersoda1233@gmail.com>
Co-authored-by: Bengisu Diri <bengisudiri@hotmail.com>
Co-authored-by: Benoit Hetru <me+hbtc@gahanka.net>
Co-authored-by: Bogdan Derdziak <bagtirr@gmail.com>
Co-authored-by: BryanLim <youmakemysonlooklikeelonmusk@gmail.com>
Co-authored-by: Chucklestone <utkuulassimsek@gmail.com>
Co-authored-by: Deni Zubin <deni.zubin@gmail.com>
Co-authored-by: Elsyana Z <frostaxter@gmail.com>
Co-authored-by: Evan Kletniek <rutakl2010@gmail.com>
Co-authored-by: Falzart <muh_fauzi_ramadhan@yahoo.co.id>
Co-authored-by: Full Name <supersoda1233@gmail.com>
Co-authored-by: Hinano_Miyako <sinemgokcebircan@gmail.com>
Co-authored-by: John Collins <munmedia9865@gmail.com>
Co-authored-by: João Pedro <lolpeople.mega@gmail.com>
Co-authored-by: Julian H <julian.henin29@gmail.com>
Co-authored-by: Justcallme rye <Blizzardscf32@gmail.com>
Co-authored-by: Kiryla <ansgar@tut.by>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Marek Tomek <markowalzky2@gmail.com>
Co-authored-by: Maria G <magu18ab@hotmail.com>
Co-authored-by: Melina Rake <melinarake@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Nodaysoff <convoron@yandex.ru>
Co-authored-by: Oleksandr Shtonda <oleksandrshtonda@gmail.com>
Co-authored-by: Omar Bertolla <scaram@icloud.com>
Co-authored-by: Rayane Benamre <thegamercore3@gmail.com>
Co-authored-by: Simon Hagman <dragonzimpan@gmail.com>
Co-authored-by: Svetlana <shkulepo@rambler.ru>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yuliia Pastukh <yuliya.bratash666@gmail.com>
Co-authored-by: billypat <kreideraine@gmail.com>
Co-authored-by: inesa <inessami200@gmail.com>
Co-authored-by: minhtan <minhtan11221122@gmail.com>
Co-authored-by: sam de wit <samedewit@gmail.com>
Co-authored-by: Ілля <bo4onok5@gmail.com>
Co-authored-by: Катерина <kate0712ann@gmail.com>
Co-authored-by: 왕효준 <gywns0417@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ar/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/be/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/it/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/lv/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sv/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/vi/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/en@lolcat/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/id/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/character/id/
Translate-URL: https://translate.habitica.com/projects/habitica/character/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/character/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/content/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/content/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/en@lolcat/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/death/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/death/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/defaulttasks/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ar/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/lv/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/front/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/front/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/id/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/lv/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/id/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/uk/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Death
Translation: Habitica/Defaulttasks
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Inventory
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-07-25 21:11:22 +02:00
Natalie L
812e2132d9 fix(config.json.example) (#14787)
* fix(string): questVice1Notes html changed to a mobile-device friendly format

* fix(strings): updated limited.json with "dateEnd" & "monthYYYY" months & put in chronological order

* fix(string): remove extra word from headSpecialSummer2022WarriorNotes

* fix(string): corrected armorSpecialSummer2022MageNotes

* fix: remove duplicated string and adjust upgrade button style

* fix(style): set border radii to 8px on upgrading-group id

* fix(payments): remove duplicate entry from another modal

* chore(fix): restore string inadvertently removed during a refactor

* chore(fix): comma dangle

* chore(typo): who knew, that Y was actually important...

* chore(typo): fix text in questBewilderNotes

* chore(string): clarify polar pets requirements

* couple small changes to the footer as pointed out by users

* chore(fix): correct name of Fabulous Party Hat

* fix(typo): correct February backgrounds release date to 2023, not 2022

* fix(trusted_domains): removed https:// from the beginning of localhost

* fix(config): correct habitica url format too

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-07-25 14:10:47 -05:00
SabreCat
282abecd21 fix(lint): remove whitespace 2023-07-20 16:07:16 -05:00
SabreCat
ba61c91296 refactor(notifs): universal routing for migrations 2023-07-19 16:42:45 -05:00
SabreCat
d49736dd69 fix(migration): include purchased fields 2023-07-19 15:21:00 -05:00
SabreCat
16b766beef fix(migration): actually terminate 2023-07-19 14:46:04 -05:00
SabreCat
8558dcc3a8 4.276.2 2023-07-18 10:34:02 -05:00
SabreCat
f8a8b61726 Merge branch 'phillip/chat-skill-merge' into release 2023-07-18 10:33:55 -05:00
SabreCat
067a1de49e fix(lint): newlines, console 2023-07-18 10:20:58 -05:00
SabreCat
65ef3bfeca fix(migration): casing 2023-07-18 10:04:56 -05:00
SabreCat
af04657856 feat(event): Summer Splash Orcas 2023-07-18 09:12:28 -05:00
SabreCat
a26c5906d6 chore(guilds): migration to return banked Gems 2023-07-17 16:55:21 -05:00
SabreCat
08a5bff815 Merge branch 'release' into sabrecat/unsociable 2023-07-17 16:11:14 -05:00
SabreCat
6089b02746 4.276.1 2023-07-13 14:45:37 -05:00
SabreCat
f3f69b1871 fix(lfp): white background for seeker card 2023-07-13 14:45:31 -05:00
SabreCat
259f7ef588 fix(chat): add default to switch block 2023-07-11 18:25:59 -05:00
SabreCat
106a0c9ed8 fix(chat): collapse repetitive spells for real now 2023-07-11 17:01:17 -05:00
SabreCat
578083dde6 chore(faq): sync up 2023-07-11 14:15:27 -05:00
SabreCat
9706d7ac64 Merge branch 'natalie/antisocial' into sabrecat/unsociable 2023-07-11 12:04:50 -05:00
CuriousMagpie
93564c5d52 WIP(faq): contributor gear date correction 2023-07-11 11:33:41 -04:00
Phillip Thelen
74ba5c0b27 bring merging to MVP 2023-07-11 15:10:50 +02:00
SabreCat
bb54a6532d fix(chat): correct bad length check 2023-07-10 15:37:46 -05:00
SabreCat
3c36c59bb3 Merge branch 'develop' into phillip/chat-skill-merge 2023-07-10 15:12:12 -05:00
SabreCat
2308961de6 fix(lint): address fatal errors 2023-07-10 15:11:22 -05:00
Phillip Thelen
2d71a902f1 Merge skill casting messages together 2023-07-10 16:27:31 +02:00
SabreCat
2e94bfc489 fix(faq): updated Linguist vebiage
by @CuriousMagpie
2023-07-06 15:28:08 -05:00
SabreCat
1deb903186 Merge branch 'release' into sabrecat/chat-warning 2023-07-06 15:23:46 -05:00
SabreCat
8c00b91cc6 feat(faq): update sunset faq 2023-07-06 15:23:42 -05:00
CuriousMagpie
5c8a3f7771 WIP(faq): correct Linguist guidelines link 2023-07-06 13:20:10 -04:00
SabreCat
70d59be39b 4.276.0 2023-07-04 13:23:29 -05:00
Natalie L
c562c93158 feat(content): add July 2023 backgrounds and Enchanted Armoire (#14733)
* feat(content): add June subscriber items

* feat(content): add July backgrounds and Enchanted Armoire Items

* Update backgrounds.json

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2023-07-04 13:23:06 -05:00
CuriousMagpie
8ac03e311b WIP(faq): update Linguists section 2023-06-30 12:56:39 -04:00
SabreCat
7a430889a8 Merge branch 'develop' into sabrecat/chat-warning 2023-06-29 14:53:15 -05:00
SabreCat
f84b5f163c Merge branch 'develop' into sabrecat/unsociable 2023-06-29 14:53:00 -05:00
SabreCat
519da49886 4.275.0 2023-06-29 14:51:37 -05:00
Weblate
79d50cb3e0 Merge branch 'origin/develop' into Weblate. 2023-06-29 21:36:09 +02:00
Weblate
c588c2b2ff Translated using Weblate (Korean)
Currently translated at 97.8% (46 of 47 strings)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Deleted translation using Weblate (Acehnese)

Added translation using Weblate (Acehnese)

Translated using Weblate (Scots)

Currently translated at 90.9% (111 of 122 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2863 of 2863 strings)

Translated using Weblate (Portuguese)

Currently translated at 62.0% (1777 of 2863 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (218 of 218 strings)

Added translation using Weblate (Acehnese)

Translated using Weblate (Russian)

Currently translated at 97.4% (2790 of 2863 strings)

Translated using Weblate (Russian)

Currently translated at 96.7% (2769 of 2863 strings)

Translated using Weblate (Croatian)

Currently translated at 26.4% (28 of 106 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Swedish)

Currently translated at 98.6% (150 of 152 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.3% (2817 of 2863 strings)

Translated using Weblate (Swedish)

Currently translated at 98.6% (150 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 96.4% (2761 of 2863 strings)

Translated using Weblate (Swedish)

Currently translated at 76.6% (321 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Malay)

Currently translated at 48.2% (54 of 112 strings)

Translated using Weblate (Korean)

Currently translated at 72.9% (577 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Galician)

Currently translated at 65.5% (501 of 764 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Malay)

Currently translated at 54.3% (430 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2863 of 2863 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Russian)

Currently translated at 99.1% (784 of 791 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Korean)

Currently translated at 72.3% (572 of 791 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Japanese)

Currently translated at 97.4% (268 of 275 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (137 of 137 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (275 of 275 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (2859 of 2863 strings)

Translated using Weblate (German)

Currently translated at 63.2% (67 of 106 strings)

Translated using Weblate (German)

Currently translated at 81.1% (99 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 98.5% (135 of 137 strings)

Translated using Weblate (German)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 98.5% (271 of 275 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (German)

Currently translated at 99.4% (787 of 791 strings)

Translated using Weblate (German)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Korean)

Currently translated at 99.7% (375 of 376 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.5% (2851 of 2863 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1892 of 2863 strings)

Translated using Weblate (Russian)

Currently translated at 95.0% (116 of 122 strings)

Translated using Weblate (Russian)

Currently translated at 98.1% (217 of 221 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.3% (2844 of 2863 strings)

Translated using Weblate (Russian)

Currently translated at 90.9% (111 of 122 strings)

Translated using Weblate (Russian)

Currently translated at 98.8% (782 of 791 strings)

Translated using Weblate (Malay)

Currently translated at 53.2% (421 of 791 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.2% (131 of 132 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.5% (413 of 419 strings)

Translated using Weblate (Hebrew)

Currently translated at 63.7% (267 of 419 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.3% (2843 of 2863 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1891 of 2863 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Ukrainian)

Currently translated at 55.6% (59 of 106 strings)

Translated using Weblate (Dutch)

Currently translated at 49.0% (52 of 106 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Dutch)

Currently translated at 89.7% (710 of 791 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Malay)

Currently translated at 52.3% (414 of 791 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.0% (1891 of 2863 strings)

Translated using Weblate (Hebrew)

Currently translated at 56.5% (237 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.7% (1891 of 2831 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 65.5% (501 of 764 strings)

Translated using Weblate (Russian)

Currently translated at 98.1% (217 of 221 strings)

Translated using Weblate (Hebrew)

Currently translated at 60.1% (133 of 221 strings)

Translated using Weblate (Hebrew)

Currently translated at 50.3% (211 of 419 strings)

Translated using Weblate (Russian)

Currently translated at 99.5% (217 of 218 strings)

Translated using Weblate (Russian)

Currently translated at 98.3% (179 of 182 strings)

Translated using Weblate (Russian)

Currently translated at 98.3% (179 of 182 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (221 of 221 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 65.5% (501 of 764 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Malay)

Currently translated at 52.0% (412 of 791 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 66.4% (1881 of 2831 strings)

Translated using Weblate (Hebrew)

Currently translated at 41.0% (325 of 791 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.6% (150 of 152 strings)

Translated using Weblate (Hebrew)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Dutch)

Currently translated at 97.3% (148 of 152 strings)

Translated using Weblate (Malay)

Currently translated at 82.0% (87 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 65.2% (1848 of 2831 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (221 of 221 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (135 of 135 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Indonesian)

Currently translated at 92.6% (388 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 64.9% (1838 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 91.1% (382 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 64.2% (1818 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 98.6% (754 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (221 of 221 strings)

Translated using Weblate (French)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Portuguese)

Currently translated at 38.6% (41 of 106 strings)

Translated using Weblate (Malay)

Currently translated at 74.5% (79 of 106 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.0% (219 of 221 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 91.1% (382 of 419 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2835 of 2835 strings)

Translated using Weblate (Indonesian)

Currently translated at 63.5% (1798 of 2831 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 97.3% (744 of 764 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 89.4% (375 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 62.8% (1778 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 93.4% (714 of 764 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Ana Beatriz <anabeatriz.augusto06@yahoo.com>
Co-authored-by: Andreway <watermelontvandreway2@gmail.com>
Co-authored-by: Antje Schubert <antje.schubert96@web.de>
Co-authored-by: Arthur Ouzlaner <panther1984@gmail.com>
Co-authored-by: Benoit Hetru <me+hbtc@gahanka.net>
Co-authored-by: BryanLim <youmakemysonlooklikeelonmusk@gmail.com>
Co-authored-by: Deni Zubin <deni.zubin@gmail.com>
Co-authored-by: Falzart <muh_fauzi_ramadhan@yahoo.co.id>
Co-authored-by: Hanafi <naflizo@gmail.com>
Co-authored-by: Jan Willem Middag <jwmiddag@gmail.com>
Co-authored-by: Jinnel <1210678078@qq.com>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Natalie Luhrs <eilatan@gmail.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Rostislav <rostislav.zem@gmail.com>
Co-authored-by: Sara Olson <sara@habitica.com>
Co-authored-by: Simon Hagman <dragonzimpan@gmail.com>
Co-authored-by: Svetlana <shkulepo@rambler.ru>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Thiago Braga <thibraga06@gmail.com>
Co-authored-by: Timur Niyazov <timmy568@gmail.com>
Co-authored-by: Vladyslav Yavnyk <yavnyjvladislav@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: lilia petervari <lilipetervari@gmail.com>
Co-authored-by: Ілля <bo4onok5@gmail.com>
Co-authored-by: Естай <akseleu@yahoo.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/de/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/he/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sv/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/he/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/de/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/sco/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/front/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/id/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/es/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/he/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/id/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/sv/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/id/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/id/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/he/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/hr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/id/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/pt_BR/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-06-29 21:35:54 +02:00
Natalie L
77a490283c feat(content): add July 2023 subscriber items (#14732)
* feat(content): add June subscriber items

* feat(content): add July subscriber items
2023-06-29 14:35:05 -05:00
dependabot[bot]
e49d26eacd build(deps): bump stripe from 12.8.0 to 12.9.0 (#14699)
Bumps [stripe](https://github.com/stripe/stripe-node) from 12.8.0 to 12.9.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v12.8.0...v12.9.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:50:08 -04:00
dependabot[bot]
7b0fd57eb9 build(deps): bump @babel/core from 7.22.1 to 7.22.5 (#14700)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.22.1 to 7.22.5.
- [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.22.5/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:49:41 -04:00
dependabot[bot]
7171334e31 build(deps): bump @babel/register from 7.21.0 to 7.22.5 (#14702)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.21.0 to 7.22.5.
- [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.22.5/packages/babel-register)

---
updated-dependencies:
- dependency-name: "@babel/register"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:49:16 -04:00
dependabot[bot]
a3235214b2 build(deps): bump core-js from 3.30.2 to 3.31.0 in /website/client (#14704)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.30.2 to 3.31.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/commits/v3.31.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:48:45 -04:00
dependabot[bot]
fca234c45a build(deps-dev): bump sinon from 15.1.0 to 15.1.2 (#14713)
Bumps [sinon](https://github.com/sinonjs/sinon) from 15.1.0 to 15.1.2.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v15.1.0...v15.1.2)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:47:21 -04:00
dependabot[bot]
7519023f06 build(deps): bump sass from 1.62.1 to 1.63.4 in /website/client (#14719)
Bumps [sass](https://github.com/sass/dart-sass) from 1.62.1 to 1.63.4.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.62.1...1.63.4)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-21 13:46:01 -04:00
CuriousMagpie
ad118095ef WIP(faq): add link to translate.habitica.com to sunsetFaqPara14 2023-06-21 11:45:23 -04:00
SabreCat
7ecad94a51 fix(faq): remove timezone 2023-06-20 17:28:54 -05:00
SabreCat
328b37322e wip(faq): layout rewrite 2023-06-20 17:28:04 -05:00
CuriousMagpie
81f7fbc2d5 WIP(faq): rawr why css no work? 2023-06-20 18:07:21 -04:00
SabreCat
9590ce939a Merge remote-tracking branch 'private/natalie/antisocial' into sabrecat/unsociable 2023-06-20 15:16:29 -05:00
CuriousMagpie
fff6fbfbd6 WIP(faq): line 155 2023-06-20 16:16:04 -04:00
SabreCat
52abf8acf3 Merge remote-tracking branch 'private/natalie/antisocial' into sabrecat/unsociable 2023-06-20 15:14:43 -05:00
SabreCat
bc61443246 Merge remote-tracking branch 'private/natalie/string-sweep' into sabrecat/unsociable 2023-06-20 15:14:06 -05:00
CuriousMagpie
cd8594a8b9 Merge branch 'sabrecat/unsociable' into natalie/antisocial 2023-06-20 16:13:10 -04:00
CuriousMagpie
f3600f64e8 WIP(faq): add date 2023-06-20 16:10:56 -04:00
SabreCat
752cd57bb1 Merge branch 'natalie/antisocial' into sabrecat/unsociable 2023-06-19 19:06:05 -05:00
SabreCat
5d6bf131f4 fix(sunset): update layouts and links 2023-06-19 19:04:07 -05:00
SabreCat
8445f45b31 Merge branch 'release' into sabrecat/unsociable 2023-06-19 18:14:22 -05:00
SabreCat
df84d7c7b1 Merge branch 'release' into develop 2023-06-19 16:36:39 -05:00
SabreCat
e837ebec49 4.274.0 2023-06-19 16:36:13 -05:00
Natalie L
c7ed693e18 feat(gala): Add 2023 Summer Splash Gala Items (#14712)
* feat(content): add June subscriber items

* feat(gala): add images

* feat(gala): add code

* feat(gala): text strings

* feat(gala): testing and final updates

* feat(gala): fixed a couple of typos

* fix(event): proofread strings and dates
Also replace empty descriptions for Rogue and Healer

* fix(event): NO EGG

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-06-19 16:36:05 -05:00
Ash
e72a25ad02 Fixes #14438: a11y: add semantic roles to habit and todo controls (#14467)
* a11y: add aria roles to habit control

* a11y: add role to todo checkboxes

* a11y: add aria-labels to score buttons
Helps with screen readers

* add i18n to aria-labels
2023-06-19 17:00:16 -04:00
CuriousMagpie
7dab47db16 WIP(string-sweep): inn complete 2023-06-15 14:05:00 -04:00
CuriousMagpie
a88ca5a1a8 WIP(string-sweep): tavern complete 2023-06-15 13:59:36 -04:00
CuriousMagpie
c91d115793 WIP(string-sweep): guild/s complete 2023-06-15 13:47:14 -04:00
CuriousMagpie
e3502bd280 Merge remote-tracking branch 'private/sabrecat/unsociable' into natalie/string-sweep 2023-06-15 12:42:13 -04:00
CuriousMagpie
8b5ff7c2f9 WIP(faq): working on Dan'l 2023-06-15 11:40:12 -04:00
SabreCat
3ac260026b WIP(sunset): fixes 2023-06-14 17:11:52 -05:00
CuriousMagpie
80e7fda8ef WIP(string-sweep): de-guildify more strings 2023-06-14 18:05:29 -04:00
SabreCat
1e7ea399b1 fix(sunset): don't show banner after rollout 2023-06-14 16:45:21 -05:00
CuriousMagpie
9c889a42aa Merge remote-tracking branch 'private/sabrecat/unsociable' into natalie/string-sweep 2023-06-14 17:45:03 -04:00
SabreCat
952b99599b Merge branch 'sabrecat/chat-warning' into sabrecat/unsociable 2023-06-14 16:41:37 -05:00
CuriousMagpie
973fa2edc2 WIP(faq): update spacing and font size 2023-06-14 16:43:18 -04:00
CuriousMagpie
5e04040f5f WIP(faq): initial round of edits 2023-06-14 12:09:49 -04:00
SabreCat
2c12d5ee29 4.273.3 2023-06-13 14:57:37 -05:00
Weblate
c3f0abadd7 Merge branch 'origin/develop' into Weblate. 2023-06-13 21:54:27 +02:00
Phillip Thelen
adf0a2efca Fix perkMonthCount not being editable/saving (#14711)
Co-authored-by: SabreCat <sabe@habitica.com>
2023-06-13 14:51:58 -05:00
SabreCat
e4523c09dc Merge branch 'release' into develop 2023-06-13 14:40:41 -05:00
SabreCat
91d98b86e1 fix(lint): whitespace 2023-06-13 14:40:26 -05:00
Weblate
779fb8bce5 Translated using Weblate (Indonesian)
Currently translated at 62.0% (1758 of 2831 strings)

Translated using Weblate (Malay)

Currently translated at 70.7% (75 of 106 strings)

Translated using Weblate (Japanese)

Currently translated at 98.9% (756 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 61.9% (1753 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 87.8% (368 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 61.8% (1752 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 92.1% (704 of 764 strings)

Translated using Weblate (Malay)

Currently translated at 61.3% (65 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 85.9% (360 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 61.4% (1740 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 89.5% (684 of 764 strings)

Translated using Weblate (Malay)

Currently translated at 59.4% (63 of 106 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 92.6% (202 of 218 strings)

Translated using Weblate (Indonesian)

Currently translated at 84.7% (355 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 60.6% (1718 of 2831 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.9% (641 of 764 strings)

Translated using Weblate (Irish)

Currently translated at 75.0% (114 of 152 strings)

Translated using Weblate (Irish)

Currently translated at 75.0% (114 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 95.4% (211 of 221 strings)

Translated using Weblate (Russian)

Currently translated at 99.4% (760 of 764 strings)

Translated using Weblate (English (Pirate))

Currently translated at 82.2% (125 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Russian)

Currently translated at 96.3% (213 of 221 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Russian)

Currently translated at 95.5% (259 of 271 strings)

Translated using Weblate (Indonesian)

Currently translated at 60.6% (1718 of 2831 strings)

Translated using Weblate (Russian)

Currently translated at 89.6% (95 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Malay)

Currently translated at 52.8% (56 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (791 of 791 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Malay)

Currently translated at 98.6% (150 of 152 strings)

Translated using Weblate (Russian)

Currently translated at 98.5% (413 of 419 strings)

Translated using Weblate (Serbian)

Currently translated at 23.5% (25 of 106 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (784 of 784 strings)

Translated using Weblate (Malay)

Currently translated at 52.8% (56 of 106 strings)

Translated using Weblate (Malay)

Currently translated at 85.1% (115 of 135 strings)

Translated using Weblate (Indonesian)

Currently translated at 81.6% (342 of 419 strings)

Co-authored-by: Abiel Meza <mezaabiel@gmail.com>
Co-authored-by: Anastasia Wysocka <legitemail.uwu420@gmail.com>
Co-authored-by: Edward McGibney <edwardmcgibney95@gmail.com>
Co-authored-by: Falzart <muh_fauzi_ramadhan@yahoo.co.id>
Co-authored-by: Hanafi <naflizo@gmail.com>
Co-authored-by: Lauren C <laurenc7834@gmail.com>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Miroslav <entferner@yandex.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: i3beograd <milica.the@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/en@pirate/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ga/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/id/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/sr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/id/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/es/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/nb_NO/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/id/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/id/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/ms/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Faq
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Npc
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-06-13 09:29:03 +02:00
SabreCat
f0fc83ed85 Merge branch 'release' into develop 2023-06-12 15:02:18 -05:00
SabreCat
30d2108c78 4.273.2 2023-06-12 15:02:06 -05:00
Natalie L
ab68e8a5fe feat(content): add June pet quest bundle (#14694)
* feat(content): add June subscriber items

* feat(content): add June pet quest bundle

* fix(bundle): correct timing and visual issues

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-06-12 15:01:34 -05:00
CuriousMagpie
2fc9480ae9 WIP(string-sweep): first smol batch 2023-06-12 14:56:07 -04:00
SabreCat
429afc1e71 feat(404): route retired links 2023-06-09 16:33:27 -05:00
SabreCat
80da313844 chore(cg): update Guidelines 2023-06-08 17:20:56 -05:00
dependabot[bot]
31e9100ba2 build(deps): bump @babel/preset-env from 7.21.5 to 7.22.5 (#14695)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.21.5 to 7.22.5.
- [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.22.5/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:45:46 -04:00
dependabot[bot]
0070f366bb build(deps): bump xml2js from 0.5.0 to 0.6.0 (#14673)
Bumps [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) from 0.5.0 to 0.6.0.
- [Commits](https://github.com/Leonidas-from-XIV/node-xml2js/compare/0.5.0...0.6.0)

---
updated-dependencies:
- dependency-name: xml2js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:38:28 -04:00
dependabot[bot]
2be6865a5c build(deps): bump winston from 3.8.2 to 3.9.0 (#14676)
Bumps [winston](https://github.com/winstonjs/winston) from 3.8.2 to 3.9.0.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.8.2...v3.9.0)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:37:58 -04:00
dependabot[bot]
db85768e9d build(deps): bump stripe from 12.6.0 to 12.8.0 (#14690)
Bumps [stripe](https://github.com/stripe/stripe-node) from 12.6.0 to 12.8.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v12.6.0...v12.8.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:34:03 -04:00
dependabot[bot]
3d40413882 build(deps): bump fast-xml-parser and is-svg (#14693)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) and [is-svg](https://github.com/sindresorhus/is-svg). These dependencies needed to be updated together.

Updates `fast-xml-parser` from 3.19.0 to 4.2.4
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/commits)

Updates `is-svg` from 4.3.1 to 4.4.0
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.3.1...v4.4.0)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-type: indirect
- dependency-name: is-svg
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:32:28 -04:00
dependabot[bot]
cc88e75950 build(deps): bump @babel/core from 7.21.8 to 7.22.1 (#14670)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.8 to 7.22.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.22.1/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 15:31:54 -04:00
SabreCat
de057dc1b2 WIP(sunset): close X, CG revisions 2023-06-07 17:03:07 -05:00
SabreCat
ff860b04fc Merge remote-tracking branch 'private/natalie/antisocial' into sabrecat/chat-warning 2023-06-07 15:02:11 -05:00
SabreCat
45dedbbdaa fix(banners): correct dismiss/show behavior 2023-06-07 15:00:51 -05:00
CuriousMagpie
b6359ad032 WIP(faq): pixelate Daniel's border 2023-06-07 13:33:58 -04:00
SabreCat
a5ae3e5877 4.273.1 2023-06-06 16:33:33 -05:00
SabreCat
60ed9d2944 Merge branch 'develop' into release 2023-06-06 16:33:27 -05:00
Natalie L
91fc4235aa fix(string): remove "due" string (#14683) 2023-06-06 16:33:01 -05:00
SabreCat
42e8dd1361 fix(vue): correct bad popovers breaking Chrome 2023-06-06 16:30:37 -05:00
CuriousMagpie
658a02bfc3 WIP(faq): add Daniel to sidebar 2023-06-06 15:26:31 -04:00
SabreCat
e1398e8d7c Merge branch 'develop' into sabrecat/unsociable 2023-06-06 09:22:37 -05:00
SabreCat
0185a1fbd6 Merge branch 'develop' into sabrecat/chat-warning 2023-06-06 09:22:23 -05:00
SabreCat
0a4bbbf173 4.273.0 2023-06-06 09:21:35 -05:00
SabreCat
df22f5f7bf Merge branch 'develop' into release 2023-06-06 09:21:25 -05:00
Natalie L
bb28bb5969 feat(content): add June backgrounds and Enchanted Armoire items (#14684)
* feat(content): add June subscriber items

* feat(content): add July backgrounds and Enchanted Armoire items

* feat(fix): correct sizing for aquarium background

* fix(strings): JSON formatting

* fix(sprites): add missing broad variant

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-06-06 09:17:22 -05:00
SabreCat
3b6c39dc9b fix(banner): restore close X on pause 2023-06-06 08:57:10 -05:00
Weblate
e4e8e0ff60 Translated using Weblate (Malay)
Currently translated at 51.8% (55 of 106 strings)

Translated using Weblate (Japanese)

Currently translated at 96.8% (214 of 221 strings)

Translated using Weblate (Malay)

Currently translated at 50.9% (54 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 81.1% (340 of 419 strings)

Translated using Weblate (Portuguese)

Currently translated at 60.1% (163 of 271 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (135 of 135 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (56 of 56 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (271 of 271 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Belarusian)

Currently translated at 71.3% (157 of 220 strings)

Translated using Weblate (Japanese)

Currently translated at 95.9% (212 of 221 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Japanese)

Currently translated at 97.4% (264 of 271 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (271 of 271 strings)

Translated using Weblate (Japanese)

Currently translated at 96.4% (404 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 80.6% (338 of 419 strings)

Translated using Weblate (Japanese)

Currently translated at 99.8% (2828 of 2831 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (784 of 784 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Japanese)

Currently translated at 94.1% (208 of 221 strings)

Translated using Weblate (Indonesian)

Currently translated at 91.8% (249 of 271 strings)

Translated using Weblate (Indonesian)

Currently translated at 79.4% (333 of 419 strings)

Translated using Weblate (Indonesian)

Currently translated at 60.6% (1718 of 2831 strings)

Translated using Weblate (Japanese)

Currently translated at 78.3% (83 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (French)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Galician)

Currently translated at 60.2% (1706 of 2831 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (271 of 271 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (221 of 221 strings)

Translated using Weblate (Indonesian)

Currently translated at 78.5% (213 of 271 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 54.7% (58 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (152 of 152 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (419 of 419 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Galician)

Currently translated at 100.0% (220 of 220 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (221 of 221 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (112 of 112 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (132 of 132 strings)

Translated using Weblate (Indonesian)

Currently translated at 63.4% (172 of 271 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (218 of 218 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (182 of 182 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (106 of 106 strings)

Translated using Weblate (Indonesian)

Currently translated at 83.3% (637 of 764 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (376 of 376 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (784 of 784 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (152 of 152 strings)

Co-authored-by: Adrián Chaves Fernández <adrian@chaves.io>
Co-authored-by: Falzart <muh_fauzi_ramadhan@yahoo.co.id>
Co-authored-by: Hanafi <naflizo@gmail.com>
Co-authored-by: Hanna Aniskevich <northernwind@tut.by>
Co-authored-by: LiziKnight <liziknight0316@outlook.com>
Co-authored-by: Sara Olson <sara@habitica.com>
Co-authored-by: TOMA Mitsuru <toma0001@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yatharth <megacutiemauandtuchchu@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/id/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/id/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/character/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/character/id/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/id/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/content/id/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/id/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ms/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/front/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/front/id/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/id/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/id/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/id/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/inventory/id/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/id/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/id/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/id/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/id/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/id/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/id/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/be/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/spells/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/gl/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/id/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/gl/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Inventory
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Spells
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2023-06-06 05:00:15 +02:00
SabreCat
7e2a35d7a9 WIP(sunset): fix private Guild and report form 2023-06-05 16:36:00 -05:00
SabreCat
84e5c00be1 WIP(announcement): correct layout and close X 2023-06-05 16:16:19 -05:00
SabreCat
187029f44f Merge remote-tracking branch 'private/natalie/antisocial' into sabrecat/chat-warning 2023-06-05 15:54:41 -05:00
CuriousMagpie
efbc7d1460 WIP(faq): sidebar formatting 2023-06-05 16:53:48 -04:00
SabreCat
36f84d083e Merge remote-tracking branch 'private/natalie/antisocial' into sabrecat/chat-warning 2023-06-05 15:32:46 -05:00
CuriousMagpie
2154ba5451 WIP(fix): change URL 2023-06-05 12:33:40 -04:00
SabreCat
cf0e45c68c Merge branch 'natalie/antisocial' into sabrecat/chat-warning 2023-06-02 16:14:20 -05:00
SabreCat
df5d1e95d1 chore(sunset): end standard guild creation API 2023-06-02 16:09:11 -05:00
CuriousMagpie
93d9038765 WIP(faq): initial formatting of main text, started on sidebar 2023-06-02 17:00:13 -04:00
SabreCat
f4e8bf9c2e feat(form): Ask a Question mode on bug report 2023-06-02 15:58:24 -05:00
SabreCat
9c7f1ae630 Merge branch 'release' into sabrecat/unsociable 2023-06-02 15:01:57 -05:00
SabreCat
302eabb30f WIP(faq): hack background to white 2023-06-02 14:58:16 -05:00
SabreCat
09695f637e Merge branch 'release' into natalie/antisocial 2023-06-02 14:12:52 -05:00
SabreCat
e9a15fcb83 fix(strings): JSON formatting 2023-06-02 13:55:04 -05:00
CuriousMagpie
97c8138340 feat(content): minor updates 2023-06-02 11:31:43 -04:00
SabreCat
a65b0d1f4d fix(banner): make dismissable 2023-06-01 16:33:11 -05:00
SabreCat
8d73e2949a Merge branch 'release' into sabrecat/unsociable 2023-06-01 15:42:47 -05:00
SabreCat
c0cf647873 fix(banner): only show when relevant 2023-05-31 16:55:21 -05:00
CuriousMagpie
d20e976176 feat(style): css work 2023-05-31 14:27:52 -04:00
SabreCat
739016ba01 WIP(chat): add warning banner 2023-05-30 16:25:29 -05:00
SabreCat
a5602eec8d 4.272.0 2023-05-30 15:28:16 -05:00
Natalie L
867eed176e feat(content): add June subscriber items (#14669)
Co-authored-by: SabreCat <sabe@habitica.com>
2023-05-30 15:26:16 -05:00
SabreCat
ba883ae104 chore(subproj): update habitica-images 2023-05-30 14:55:00 -05:00
SabreCat
deba7b6220 feat(faq): update for mobile workflows 2023-05-30 14:50:13 -05:00
CuriousMagpie
55d6ee3f7e feat(content): add staff and tiers 2023-05-30 12:01:21 -04:00
SabreCat
69c538858b 4.271.2 2023-05-25 14:42:53 -05:00
SabreCat
17072dcc45 Merge branch 'due-dates-in-todos' into release 2023-05-25 14:42:46 -05:00
SabreCat
2448f401f2 Merge branch 'increment-component' into release 2023-05-25 14:42:42 -05:00
CuriousMagpie
9ef13dad68 feat(content): starting add styling, string updates 2023-05-25 12:25:08 -04:00
CuriousMagpie
14fa69719b feat(content): static page created and strings in place 2023-05-24 16:18:31 -04:00
SabreCat
9228b070fa Merge branch 'release' into sabrecat/unsociable 2023-05-24 14:17:49 -05:00
SabreCat
5745e3df5f 4.271.1 2023-05-24 13:30:21 -05:00
Phillip Thelen
d4a5823916 Fix one-off issue for monthly subs (#14643)
* Fix initial plan.consecutive.offset for 1 month subs

* fix initial values for group plan subs

* Make perkMonthCount editable in admin panel

* Add aditional info to admin panel

* Implement automatic fix for affected users

* fix(lint): exclusive test, code style

* fixes

* fix issue with initialization

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-05-24 13:29:42 -05:00
CuriousMagpie
929b0196a4 add strings 2023-05-24 13:24:44 -04:00
CuriousMagpie
1b91f620e1 initial commit 2023-05-23 16:01:40 -04:00
CuriousMagpie
86b15cb580 fix(style): css fix, today if-statement added 2023-05-23 15:19:26 -04:00
SabreCat
8e5b66a73e Merge branch 'release' into develop 2023-05-23 09:16:50 -05:00
SabreCat
f755d4c133 4.271.0 2023-05-23 09:07:47 -05:00
SabreCat
102c71c4ca Merge remote-tracking branch 'CuriousMagpie/2023-05-pet-quest-bundle' into release 2023-05-22 15:14:18 -05:00
SabreCat
a7bde80349 Squashed commit of the following:
commit 27287ac3aa
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon May 22 15:59:20 2023 -0400

    fix(typo): typos fixed

commit a4df8097cf
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon May 22 15:57:17 2023 -0400

    feat(content): add migration script

commit 23ff7845c1
Merge: d02644e21b 8ba7117fa5
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon May 22 15:42:32 2023 -0400

    Merge branch 'develop' into achievement-dinosaur-dynasty

commit 8ba7117fa5
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon May 22 12:35:07 2023 -0400

    build(deps): bump stripe from 12.5.0 to 12.6.0 (#14662)

    Bumps [stripe](https://github.com/stripe/stripe-node) from 12.5.0 to 12.6.0.
    - [Release notes](https://github.com/stripe/stripe-node/releases)
    - [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/stripe/stripe-node/compare/v12.5.0...v12.6.0)

    ---
    updated-dependencies:
    - dependency-name: stripe
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit fe5d4a0551
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon May 22 12:34:28 2023 -0400

    build(deps-dev): bump sinon from 15.0.4 to 15.1.0 (#14661)

    Bumps [sinon](https://github.com/sinonjs/sinon) from 15.0.4 to 15.1.0.
    - [Release notes](https://github.com/sinonjs/sinon/releases)
    - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
    - [Commits](https://github.com/sinonjs/sinon/compare/v15.0.4...v15.1.0)

    ---
    updated-dependencies:
    - dependency-name: sinon
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit d02644e21b
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed May 17 11:36:28 2023 -0400

    feat(content): add dinosaur dynasty achievement
2023-05-22 15:13:49 -05:00
SabreCat
bedce203ee 4.270.3 2023-05-22 13:28:31 -05:00
dependabot[bot]
8ba7117fa5 build(deps): bump stripe from 12.5.0 to 12.6.0 (#14662)
Bumps [stripe](https://github.com/stripe/stripe-node) from 12.5.0 to 12.6.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v12.5.0...v12.6.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-22 12:35:07 -04:00
dependabot[bot]
fe5d4a0551 build(deps-dev): bump sinon from 15.0.4 to 15.1.0 (#14661)
Bumps [sinon](https://github.com/sinonjs/sinon) from 15.0.4 to 15.1.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v15.0.4...v15.1.0)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-22 12:34:28 -04:00
SabreCat
deebc09a79 fix(analytics): typo 2023-05-22 09:54:10 -05:00
SabreCat
b63f2fa1fa fix(analytics): add missing headers to 3 events 2023-05-19 14:54:30 -05:00
SabreCat
8d9602fb16 WIP(chat): first pass deprecation 2023-05-17 16:33:44 -05:00
CuriousMagpie
60b180681e Merge remote-tracking branch 'origin/due-dates-in-todos' into due-dates-in-todos 2023-05-17 13:30:45 -04:00
CuriousMagpie
7c1c18a329 fix(styling): update colors to be a11y-friendly and to show items due today in gray 2023-05-17 13:29:26 -04:00
CuriousMagpie
0b0cbb45f4 feat(content): add May pet quest bundle 2023-05-17 10:49:37 -04:00
SabreCat
0e03f079a7 Merge branch 'due-dates-in-todos' of https://github.com/CuriousMagpie/habitica into due-dates-in-todos 2023-05-16 14:27:56 -05:00
SabreCat
a71e44b331 fix(test): remove test for old function 2023-05-16 14:27:15 -05:00
Sabe Jones
48917fd8be Merge branch 'develop' into due-dates-in-todos 2023-05-16 14:18:22 -05:00
SabreCat
2a054a25ee fix(test): include user pref needed for date 2023-05-16 14:15:34 -05:00
SabreCat
d176c31382 4.270.2 2023-05-16 12:22:21 -05:00
Phillip Thelen
8150fef993 Database Access optimisations (#14544)
* Optimize database access during spell casting

* load less data when casting spells

* Begin migrating update calls to updateOne and updateMany

* Only update user objects that don’t have notification yet

* fix test

* fix spy

* Don’t unnecessarily update user when requesting invalid guild

* fix sort order for middlewares to not load user twice every request

* fix tests

* fix integration test

* fix skill usage not always deducting mp

* addtest case for blessing spell

* fix healAll

* fix lint

* Fix error for when some spells are used outside of party

* Add check to not run bulk spells in web client

* fix(tags): change const to let

---------

Co-authored-by: SabreCat <sabe@habitica.com>
2023-05-16 12:21:45 -05:00
SabreCat
f0637dcf49 4.270.1 2023-05-15 16:15:22 -05:00
SabreCat
0518b90eab Merge branch 'develop' into release 2023-05-15 16:11:30 -05:00
SabreCat
f968bdd3a9 fix(analytics): re-enable group chat tracking 2023-05-15 16:02:24 -05:00
negue
e3a1ea6180 save task column filter (#14587)
* save task column filter

* remove old setting

* fix tests
2023-05-15 16:01:32 -05:00
Natalie L
17f6054ef0 feat(content): add May magic hatching potions (#14641) 2023-05-15 15:59:49 -05:00
dependabot[bot]
9b8f213c63 build(deps): bump jquery from 3.6.4 to 3.7.0 in /website/client (#14653)
Bumps [jquery](https://github.com/jquery/jquery) from 3.6.4 to 3.7.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.6.4...3.7.0)

---
updated-dependencies:
- dependency-name: jquery
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-15 13:46:41 -04:00
CuriousMagpie
daccade2e2 disabled sell button when user tries to sell more items than they own 2023-05-15 12:03:58 -04:00
dependabot[bot]
48bb3e2886 build(deps): bump core-js from 3.30.1 to 3.30.2 in /website/client (#14635)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.30.1 to 3.30.2.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.30.2/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:47:35 -05:00
dependabot[bot]
308d557770 build(deps): bump superagent from 8.0.6 to 8.0.9 (#14473)
Bumps [superagent](https://github.com/ladjs/superagent) from 8.0.6 to 8.0.9.
- [Release notes](https://github.com/ladjs/superagent/releases)
- [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/ladjs/superagent/compare/v8.0.6...v8.0.9)

---
updated-dependencies:
- dependency-name: superagent
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:35:21 -05:00
dependabot[bot]
0f4816c674 build(deps): bump intro.js from 6.0.0 to 7.0.1 in /website/client (#14558)
Bumps [intro.js](https://github.com/usablica/intro.js) from 6.0.0 to 7.0.1.
- [Release notes](https://github.com/usablica/intro.js/releases)
- [Changelog](https://github.com/usablica/intro.js/blob/master/tsconfig.release.json)
- [Commits](https://github.com/usablica/intro.js/compare/v6.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: intro.js
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:35:06 -05:00
dependabot[bot]
f1b98a530d build(deps): bump jsonwebtoken from 8.5.1 to 9.0.0 (#14418)
Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 8.5.1 to 9.0.0.
- [Release notes](https://github.com/auth0/node-jsonwebtoken/releases)
- [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v8.5.1...v9.0.0)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:29:16 -05:00
dependabot[bot]
1498eba8d4 build(deps): bump @babel/preset-env from 7.20.2 to 7.21.5 (#14616)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.20.2 to 7.21.5.
- [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.21.5/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:28:41 -05:00
dependabot[bot]
fc16ffbf2d build(deps): bump dompurify from 2.4.3 to 3.0.3 in /website/client (#14639)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.3 to 3.0.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.4.3...3.0.3)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:22:06 -05:00
dependabot[bot]
021180fa59 build(deps): bump uuid from 8.3.2 to 9.0.0 in /website/client (#14227)
Bumps [uuid](https://github.com/uuidjs/uuid) from 8.3.2 to 9.0.0.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v8.3.2...v9.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:13:53 -05:00
dependabot[bot]
102e6a64ad chore(deps): bump sass from 1.34.0 to 1.62.1 in /website/client (#14614)
Bumps [sass](https://github.com/sass/dart-sass) from 1.34.0 to 1.62.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.34.0...1.62.1)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:07:36 -05:00
SabreCat
79a5c2ec5f Merge branch 'develop' into due-dates-in-todos 2023-05-12 16:06:18 -05:00
dependabot[bot]
8cd6e1654f build(deps): bump @babel/core from 7.21.4 to 7.21.8 (#14630)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.4 to 7.21.8.
- [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.21.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:05:20 -05:00
dependabot[bot]
63ea21c46d build(deps): bump stripe from 11.10.0 to 12.5.0 (#14646)
Bumps [stripe](https://github.com/stripe/stripe-node) from 11.10.0 to 12.5.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v11.10.0...v12.5.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 16:03:29 -05:00
CuriousMagpie
0a23dd5311 attempt to fix sellModal 2023-05-11 16:25:11 -04:00
SabreCat
6e3a367832 Merge branch 'release' into develop 2023-05-11 14:13:58 -05:00
SabreCat
f3348aca4c 4.270.0 2023-05-09 10:29:19 -05:00
SabreCat
90e1bc9d5e Merge branch 'sabrecat/link-tweak' into release 2023-05-09 10:29:14 -05:00
Natalie L
453bf3a961 feat(content): add May Backgrounds and Enchanted Armoire items (#14628) 2023-05-09 10:26:00 -05:00
SabreCat
b026daec90 fix(rya): wait for DOM finished before update 2023-05-05 16:27:19 -05:00
SabreCat
49f45d27e3 4.269.1 2023-05-04 16:08:53 -05:00
CuriousMagpie
479cfb76ef fix(to do dates): locate a string for "Due" 2023-05-04 16:40:11 -04:00
CuriousMagpie
0e0cd99ded fix(to do dates): Add the word "Due" to the HTML 2023-05-04 16:35:27 -04:00
CuriousMagpie
7e210c56b0 fix(to do dates): change formatDueDate () to show exact due dates 2023-05-04 16:29:54 -04:00
SabreCat
d92a03048b fix(analytics): tweak CTA event 2023-05-04 14:20:49 -05:00
SabreCat
8183699cb7 feat(analytics): differentiate party CTA scenarios 2023-05-03 16:04:22 -05:00
SabreCat
9f9e6c4950 feat(links): skip modal for user's own tasks 2023-05-03 16:00:58 -05:00
SabreCat
c77dd5f200 fix(analytics): move lfp events out of mounted 2023-05-02 16:52:50 -05:00
CuriousMagpie
06ac6ae80c fix(html): fix behavior of buyModal when gems are being purchased; typo correction 2023-05-02 13:23:31 -04:00
SabreCat
13e87b1ea0 fix(tests): linting 2023-05-02 10:11:57 -05:00
CuriousMagpie
4a32a29bea Merge branch 'develop' into increment-component 2023-05-02 11:03:46 -04:00
SabreCat
71e165433a Merge branch 'release' into develop 2023-05-02 09:53:39 -05:00
SabreCat
c2515a4042 4.269.0 2023-05-02 09:51:55 -05:00
SabreCat
e31bfdc22b fix(stats): allow negative EXP 2023-05-02 09:51:49 -05:00
SabreCat
e9e4265545 Squashed commit of the following:
commit 00affb306655a543f5d29b3af6361e686b577a97
Author: SabreCat <sabe@habitica.com>
Date:   Tue May 2 09:47:25 2023 -0500

    fix(tests): account for invite limit changes

commit 47661117f9fd661b8bc8f63b7cc7c8d5f8fa0fd7
Author: SabreCat <sabe@habitica.com>
Date:   Mon May 1 17:39:29 2023 -0500

    fix(lfp): final polish

commit 6a1e5af1db0dd90be3ced7e223f53c9183a206f5
Merge: 728ed2ddad 9e0777bb42
Author: SabreCat <sabe@habitica.com>
Date:   Mon May 1 16:54:12 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit 728ed2ddad7f0962d28f1ab0a271e3555b19296c
Author: SabreCat <sabe@habitica.com>
Date:   Thu Apr 27 16:51:06 2023 -0500

    fix(lfp): loading layout and page visit event

commit 8a56ab329bff922e05963e3ef78fbc26ff273924
Author: SabreCat <sabe@habitica.com>
Date:   Wed Apr 26 16:54:46 2023 -0500

    fix(faq): copy and style updates

commit 6fd00d7f30150a1802e5a37edbb914ef120caf9a
Author: SabreCat <sabe@habitica.com>
Date:   Fri Apr 21 17:12:52 2023 -0500

    feat(lfp): fixes, analytics, FAQ

commit 4b5d7304ad7cfc5f72320b23456ed2898e53caac
Author: SabreCat <sabe@habitica.com>
Date:   Mon Apr 17 15:13:03 2023 -0500

    fix(lfp): smol tweaks

commit 9a5476a2558eb17a603f4aae1b5b2d35773be8b4
Author: SabreCat <sabe@habitica.com>
Date:   Thu Apr 13 16:03:33 2023 -0500

    feat(lfp): refresh button

commit aa58f5018469f38a9a9d31c3bffa26bb88a8c672
Merge: bbb03d006e c8adf20804
Author: SabreCat <sabe@habitica.com>
Date:   Tue Apr 11 17:44:56 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit bbb03d006e8b122bb7206bdc778a31de422167bb
Author: SabreCat <sabe@habitica.com>
Date:   Tue Apr 4 18:30:50 2023 -0500

    fix(lint): whitespace and const

commit 23683ad29a4cce0b0da061ad6c030982034c0a9c
Author: SabreCat <sabe@habitica.com>
Date:   Tue Apr 4 17:02:57 2023 -0500

    chore(LFP): add analytics
    also re-fix loading state

commit 4477d84f5266c87f5583368029b72153f00f0568
Author: SabreCat <sabe@habitica.com>
Date:   Mon Apr 3 16:24:26 2023 -0500

    fix(LFP): address issues with loading

commit bdc5154f24bb5e50963376c3c0c9cc73c0b05ccc
Merge: 81923eef6f 229ed46425
Author: SabreCat <sabe@habitica.com>
Date:   Mon Apr 3 15:58:12 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit 81923eef6f0c627d079475a28f9d93d8e4628934
Author: SabreCat <sabe@habitica.com>
Date:   Thu Mar 30 16:44:49 2023 -0500

    feat(LFP): release candidate

commit fe1f8939fc6b09d36cfaf0b6e5838df04e41009d
Author: SabreCat <sabe@habitica.com>
Date:   Wed Mar 29 17:35:54 2023 -0500

    WIP(LFP): fixes

commit afc361f5a9f806cbd814ad910d1274e3a6609efd
Merge: d6b5cbdebc 7ede3acd01
Author: SabreCat <sabe@habitica.com>
Date:   Wed Mar 29 16:24:39 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit d6b5cbdebc2829e9325ea57fb5deeccc128c1635
Author: SabreCat <sabe@habitica.com>
Date:   Tue Mar 28 16:13:18 2023 -0500

    WIP(LFP): change copy, add close X, fix API response

commit 4274a4625862351ef0ecf33c8a3249ca5ebec7cb
Author: SabreCat <sabe@habitica.com>
Date:   Mon Mar 27 17:07:36 2023 -0500

    fix(LFP): layout, unset when stopping

commit 95abfcfa5f13c9cce6385206947a47f85b76d11d
Merge: 4a360eedd8 53c536b525
Author: SabreCat <sabe@habitica.com>
Date:   Mon Mar 27 16:32:46 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit 4a360eedd8b9cf41d3a0fe7a4cfaa72c5bd7bd26
Author: SabreCat <sabe@habitica.com>
Date:   Thu Mar 23 16:54:49 2023 -0500

    feat(LFP): completed style and infinite scroll

commit bbc439d9d03c9631a450236eb33af66f0428fa50
Author: SabreCat <sabe@habitica.com>
Date:   Tue Mar 21 10:40:26 2023 -0500

    WIP(LFP): nicer layout, buffs fix

commit 1658688597456663477ab19da61ae1b9bc85cf2a
Merge: 664507434f 027e61a93e
Author: SabreCat <sabe@habitica.com>
Date:   Tue Mar 21 09:29:02 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit 664507434f2f76e6bf3b61cdc9e3daddb81204af
Author: SabreCat <sabe@habitica.com>
Date:   Fri Mar 17 17:13:08 2023 -0500

    WIP(LFP): API and client adjustments

commit 2f0b6f2517f9e2d634cb23ee303cfb4542e998ce
Merge: 0db1704325 a16098ccda
Author: SabreCat <sabe@habitica.com>
Date:   Fri Mar 17 16:45:13 2023 -0500

    Merge branch 'release' into sabrecat/party-seeking

commit 0db1704325c3555f0b5d9c8d1dfc44177e90c093
Author: SabreCat <sabe@habitica.com>
Date:   Mon Mar 13 14:48:10 2023 -0500

    fix(modal): scrollbar for squashed viewports

commit 733c35192e0a4e31e1bebfdd7488cfc1f7587f36
Author: SabreCat <sabe@habitica.com>
Date:   Thu Mar 9 12:51:02 2023 -0600

    WIP(party): seekers functional rough

commit d4b854410b557db26eec6e6a26b6d174c02cee3a
Merge: 7fe919825a 0b6b967753
Author: SabreCat <sabe@habitica.com>
Date:   Thu Mar 9 10:07:28 2023 -0600

    Merge branch 'release' into sabrecat/party-seeking

commit 7fe919825abfb6d518cb93b91f5997d3831bd0b5
Author: SabreCat <sabe@habitica.com>
Date:   Thu Mar 2 14:40:09 2023 -0600

    feat(party): several adjustments to seeking feature

commit c93900efcf925f7aaa4c4cb56b4451f19adfb1b3
Author: SabreCat <sabe@habitica.com>
Date:   Wed Mar 1 20:37:11 2023 -0600

    feat(party): initial Seeking API

commit 8bb784daeceb14c23992a6f3af1054a900fc26c1
Merge: e19a661a21 f327795761
Author: SabreCat <sabe@habitica.com>
Date:   Wed Mar 1 18:58:20 2023 -0600

    Merge branch 'release' into sabrecat/party-seeking

commit e19a661a2163a50307a286379bffb44201ed392e
Author: SabreCat <sabe@habitica.com>
Date:   Fri Feb 24 15:51:42 2023 -0600

    WIP(parties): add seeking flag and modal toggle
2023-05-02 09:51:33 -05:00
SabreCat
9e0777bb42 fix(group-plans): tokenize and update ad text 2023-05-01 16:30:21 -05:00
SabreCat
c1532996d8 4.268.1 2023-05-01 10:47:53 -05:00
SabreCat
5aa2d9c68d fix(stats): allow negative HP 2023-05-01 10:47:42 -05:00
SabreCat
6ed5a0f44b 4.268.0 2023-04-28 16:19:07 -05:00
Natalie L
76845f5f20 feat(content): add May subscriber items (#14613)
Co-authored-by: SabreCat <sabe@habitica.com>
2023-04-28 16:18:45 -05:00
SabreCat
c931823f62 chore(subproj): update habitica-images 2023-04-28 15:55:06 -05:00
dependabot[bot]
b159182188 build(deps): bump json5 from 1.0.1 to 1.0.2 (#14441)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:39:05 -04:00
dependabot[bot]
ca1b8370a0 build(deps): bump stopword from 2.0.7 to 2.0.8 in /website/client (#14560)
Bumps [stopword](https://github.com/fergiemcdowall/stopword) from 2.0.7 to 2.0.8.
- [Release notes](https://github.com/fergiemcdowall/stopword/releases)
- [Commits](https://github.com/fergiemcdowall/stopword/compare/v.2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: stopword
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:35:11 -04:00
dependabot[bot]
a397da2b93 build(deps): bump jquery from 3.6.3 to 3.6.4 in /website/client (#14540)
Bumps [jquery](https://github.com/jquery/jquery) from 3.6.3 to 3.6.4.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.6.3...3.6.4)

---
updated-dependencies:
- dependency-name: jquery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:32:06 -04:00
dependabot[bot]
b5acc0e0d6 build(deps-dev): bump @babel/plugin-proposal-optional-chaining (#14522)
Bumps [@babel/plugin-proposal-optional-chaining](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-optional-chaining) from 7.20.7 to 7.21.0.
- [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.21.0/packages/babel-plugin-proposal-optional-chaining)

---
updated-dependencies:
- dependency-name: "@babel/plugin-proposal-optional-chaining"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:30:42 -04:00
dependabot[bot]
2635c5fcee build(deps): bump @babel/register from 7.18.9 to 7.21.0 (#14517)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.18.9 to 7.21.0.
- [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.21.0/packages/babel-register)

---
updated-dependencies:
- dependency-name: "@babel/register"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:29:55 -04:00
dependabot[bot]
ee2936834a build(deps): bump body-parser from 1.20.1 to 1.20.2 (#14518)
Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.20.1 to 1.20.2.
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.1...1.20.2)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:28:07 -04:00
dependabot[bot]
c94a5304c7 build(deps): bump xml2js from 0.4.23 to 0.5.0 (#14574)
Bumps [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) from 0.4.23 to 0.5.0.
- [Release notes](https://github.com/Leonidas-from-XIV/node-xml2js/releases)
- [Commits](https://github.com/Leonidas-from-XIV/node-xml2js/commits)

---
updated-dependencies:
- dependency-name: xml2js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:07:53 -04:00
dependabot[bot]
c6b004a474 build(deps): bump apple-auth from 1.0.7 to 1.0.9 (#14578)
Bumps [apple-auth](https://github.com/ananay/apple-auth) from 1.0.7 to 1.0.9.
- [Release notes](https://github.com/ananay/apple-auth/releases)
- [Commits](https://github.com/ananay/apple-auth/compare/1.0.7...1.0.9)

---
updated-dependencies:
- dependency-name: apple-auth
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 16:07:01 -04:00
dependabot[bot]
de918ec43b build(deps): bump core-js from 3.27.2 to 3.30.1 in /website/client (#14601)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.27.2 to 3.30.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.30.1/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 15:41:26 -04:00
dependabot[bot]
069e994b25 build(deps): bump @babel/core from 7.20.12 to 7.21.4 (#14566)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.12 to 7.21.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.4/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 15:39:50 -04:00
dependabot[bot]
663692f2d5 chore(deps-dev): bump sinon from 15.0.1 to 15.0.4 (#14605)
Bumps [sinon](https://github.com/sinonjs/sinon) from 15.0.1 to 15.0.4.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v15.0.1...v15.0.4)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 15:38:03 -04:00
dependabot[bot]
0ba4761083 chore(deps-dev): bump axios from 1.2.2 to 1.3.6 (#14606)
Bumps [axios](https://github.com/axios/axios) from 1.2.2 to 1.3.6.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/1.2.2...v1.3.6)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 15:37:30 -04:00
dependabot[bot]
afad3815a2 chore(deps): bump smartbanner.js in /website/client (#14610)
Bumps [smartbanner.js](https://github.com/ain/smartbanner.js) from 1.19.1 to 1.19.2.
- [Release notes](https://github.com/ain/smartbanner.js/releases)
- [Commits](https://github.com/ain/smartbanner.js/compare/v1.19.1...v1.19.2)

---
updated-dependencies:
- dependency-name: smartbanner.js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 15:25:55 -04:00
CuriousMagpie
0c85835dc2 update to sellModal, buyModal, and questDialogContent.vue 2023-04-07 10:41:43 -04:00
CuriousMagpie
54df8397a7 fixes to svg and other spacing 2023-04-06 17:00:37 -04:00
CuriousMagpie
0644032a4f style: more spacing updates 2023-04-05 13:50:14 -04:00
CuriousMagpie
44265ac616 style: more spacing updates 2023-04-03 14:56:43 -04:00
CuriousMagpie
ac3b953633 style: vertical spacing tweaks 2023-03-30 09:07:37 -04:00
CuriousMagpie
5de2921d22 Merge branch 'develop' into increment-component 2023-03-30 08:33:24 -04:00
CuriousMagpie
c1a0f8a8d1 style: buyModal, sellModal, buyQuestModal, questRewards 2023-03-28 15:07:49 -04:00
CuriousMagpie
7e9506391f more buyModal styling 2023-03-27 16:13:06 -04:00
CuriousMagpie
3c7ca56089 buyModal styling 2023-03-27 15:58:56 -04:00
CuriousMagpie
0d155535c3 Merge branch 'develop' into increment-component 2023-03-27 14:16:55 -04:00
CuriousMagpie
09a0d2b3b8 change spacing on buyModal 2023-03-23 16:01:33 -04:00
CuriousMagpie
83dcf8d56a tightening up spacing on buyModal, fixing footer 2023-03-22 13:15:11 -04:00
CuriousMagpie
bfc13bc21b Merge branch 'develop' into increment-component 2023-03-22 12:14:04 -04:00
CuriousMagpie
5afb46f237 fix close icon on buy & sell and keyboard input into number increment component is now a number, not a string 2023-03-21 16:08:26 -04:00
CuriousMagpie
9cc4fc19d3 more tiny updates 2023-03-21 11:26:31 -04:00
CuriousMagpie
cc81629f09 updates to buyModal styling 2023-03-18 17:18:41 -04:00
CuriousMagpie
e83db7a28a Merge branch 'develop' into increment-component 2023-03-17 11:47:17 -04:00
CuriousMagpie
80e193e4ce Merge branch 'develop' into increment-component 2023-03-15 12:38:07 -04:00
CuriousMagpie
76fa6ec1b8 updates to snumberIncrement, buyModal, and sellModal 2023-03-09 15:54:26 -05:00
CuriousMagpie
1ac4466c24 trying to make more components for the buy/sell modals 2023-03-02 14:33:27 -05:00
CuriousMagpie
03f0061c85 Merge branch 'develop' into increment-component 2023-03-01 15:46:04 -05:00
CuriousMagpie
c349de6908 finish up sellModal and questModal (also Time Travelers) 2023-02-15 12:54:26 -05:00
CuriousMagpie
fd7f3a646e add functionality and styling to sellModal and questModal 2023-02-14 17:22:05 -05:00
CuriousMagpie
7244c1bebc Merge branch 'develop' into increment-component 2023-02-14 15:30:18 -05:00
CuriousMagpie
20df5eeb8f buy modal complete! 2023-02-08 15:16:17 -05:00
CuriousMagpie
23f7dd94b6 more stylin' of the buy modal 2023-02-07 15:24:53 -05:00
CuriousMagpie
7125da4533 Merge branch 'develop' into increment-component 2023-02-07 14:05:48 -05:00
CuriousMagpie
684cb59a7c buyModal styling/functions 2023-02-06 16:23:20 -05:00
CuriousMagpie
9274fe9a10 Merge branch 'develop' into increment-component 2023-02-06 14:30:34 -05:00
CuriousMagpie
a21f083761 gem modal styling/functions 2023-01-25 16:44:14 -05:00
CuriousMagpie
c7e2834fc6 Merge branch 'develop' into increment-component 2023-01-25 14:35:39 -05:00
CuriousMagpie
a08c26b076 calculations working, style updates to subscriber gem modal 2022-12-22 16:50:55 -05:00
CuriousMagpie
f4aa88e1ff more style updates to buy modal 2022-12-21 16:58:22 -05:00
CuriousMagpie
53eab7aa29 Working on styling 2022-12-20 16:53:51 -05:00
CuriousMagpie
8374d61f52 why does NaN ask the user to buy gems? 2022-12-19 17:26:49 -05:00
CuriousMagpie
4c943b7575 number-increment works on buy modal and there was much rejoicing... 2022-12-16 16:51:19 -05:00
CuriousMagpie
24032b57f6 why clicky click no click? 2022-12-15 16:48:59 -05:00
CuriousMagpie
8628c774e5 more css changes to buy modal 2022-12-13 10:53:38 -05:00
CuriousMagpie
523f044914 css changes to buy modal 2022-12-09 17:04:35 -05:00
CuriousMagpie
892c9ad040 trying to make clicky clicky work 2022-12-09 11:47:57 -05:00
CuriousMagpie
570f39c620 Merge branch 'develop' into increment-component 2022-12-08 10:22:08 -05:00
CuriousMagpie
a73316ef9f Merge branch 'develop' into increment-component 2022-12-06 11:47:53 -05:00
CuriousMagpie
6d6195ae6a props attempt 2022-12-01 14:43:08 -05:00
CuriousMagpie
4ba66c7018 unbreaking what was broken yesterday 2022-11-30 17:16:51 -05:00
CuriousMagpie
54b9424c6e Merge branch 'develop' into increment-component 2022-11-30 12:04:09 -05:00
CuriousMagpie
af574634b0 tried to make if/else logic simpler, ended up breaking everything. 2022-11-29 17:13:48 -05:00
CuriousMagpie
d1e1c09b4a add conditionals, add component to buy & sell modals 2022-11-22 15:28:48 -05:00
CuriousMagpie
4f5a720c30 how to make component show up? 2022-11-18 15:27:18 -05:00
CuriousMagpie
4ddfdb84ac get most of the right parts in the same place 2022-11-17 14:57:58 -05:00
2438 changed files with 43986 additions and 295021 deletions

View File

@@ -1,6 +1,10 @@
/* eslint-disable import/no-commonjs */
module.exports = {
root: true,
extends: [
'habitrpg/lib/node'
'habitrpg/lib/node',
],
}
rules: {
'import/no-extraneous-dependencies': 'off',
},
};

View File

@@ -104,42 +104,6 @@ updates:
- 7.7.0
- 7.8.0
- 7.9.0
- dependency-name: "@storybook/addon-knobs"
versions:
- 6.1.17
- 6.1.18
- 6.1.20
- 6.1.21
- 6.2.2
- 6.2.3
- 6.2.7
- dependency-name: "@storybook/addon-links"
versions:
- 6.1.17
- 6.1.18
- 6.1.20
- 6.1.21
- 6.2.2
- 6.2.3
- 6.2.7
- dependency-name: "@storybook/vue"
versions:
- 6.1.17
- 6.1.18
- 6.1.20
- 6.1.21
- 6.2.2
- 6.2.3
- 6.2.7
- dependency-name: "@storybook/addon-actions"
versions:
- 6.1.17
- 6.1.18
- 6.1.20
- 6.1.21
- 6.2.2
- 6.2.3
- 6.2.7
- dependency-name: core-js
versions:
- 3.10.0

1
.gitignore vendored
View File

@@ -40,6 +40,7 @@ yarn.lock
!.elasticbeanstalk/*.global.yml
/.vscode
habitica.code-workspace
# webstorm fake webpack for path intellisense
webpack.webstorm.config

View File

@@ -1,30 +0,0 @@
FROM node:14
ENV ADMIN_EMAIL admin@habitica.com
ENV EMAILS_COMMUNITY_MANAGER_EMAIL admin@habitica.com
ENV AMAZON_PAYMENTS_CLIENT_ID amzn1.application-oa2-client.68ed9e6904ef438fbc1bf86bf494056e
ENV AMAZON_PAYMENTS_SELLER_ID AMQ3SB4SG5E91
ENV AMPLITUDE_KEY e8d4c24b3d6ef3ee73eeba715023dd43
ENV BASE_URL https://habitica.com
ENV FACEBOOK_KEY 128307497299777
ENV GA_ID UA-33510635-1
ENV GOOGLE_CLIENT_ID 1035232791481-32vtplgnjnd1aufv3mcu1lthf31795fq.apps.googleusercontent.com
ENV LOGGLY_CLIENT_TOKEN ab5663bf-241f-4d14-8783-7d80db77089a
ENV NODE_ENV production
ENV STRIPE_PUB_KEY pk_85fQ0yMECHNfHTSsZoxZXlPSwSNfA
ENV APPLE_AUTH_CLIENT_ID 9Q9SMRMCNN.com.habitrpg.ios.Habitica
# Install global packages
RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg
RUN git clone --branch release --depth 1 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN git config --global url."https://".insteadOf git://
RUN npm set unsafe-perm true
RUN npm install
# Start Habitica
EXPOSE 80 8080 36612
CMD ["node", "./website/transpiled-babel/index.js"]

View File

@@ -87,5 +87,5 @@
"REDIS_HOST": "aaabbbcccdddeeefff",
"REDIS_PORT": "1234",
"REDIS_PASSWORD": "12345678",
"TRUSTED_DOMAINS": "https://localhost,https://habitica.com"
"TRUSTED_DOMAINS": "localhost,habitica.com"
}

View File

@@ -51,7 +51,7 @@ gulp.task('build:prepare-mongo', async () => {
console.log('MongoDB data folder is missing, setting up.'); // eslint-disable-line no-console
// use run-rs without --keep, kill it as soon as the replica set starts
const runRsProcess = spawn('run-rs', ['-v', '4.2.8', '-l', 'ubuntu1804', '--dbpath', 'mongodb-data', '--number', '1', '--quiet']);
const runRsProcess = spawn('run-rs', ['-v', '4.1.1', '-l', 'ubuntu1804', '--dbpath', 'mongodb-data', '--number', '1', '--quiet']);
for await (const chunk of runRsProcess.stdout) {
const stringChunk = chunk.toString();

View File

@@ -2,7 +2,6 @@ import mongoose from 'mongoose';
import nconf from 'nconf';
import repl from 'repl';
import gulp from 'gulp';
import logger from '../website/server/libs/logger';
import {
getDevelopmentConnectionUrl,
getDefaultConnectionOptions,
@@ -39,10 +38,6 @@ const improveRepl = context => {
mongoose.connect(
connectionUrl,
mongooseOptions,
err => {
if (err) throw err;
logger.info('Connected with Mongoose');
},
);
};

View File

@@ -59,13 +59,15 @@ gulp.task('test:prepare:mongo', cb => {
const mongooseOptions = getDefaultConnectionOptions();
const connectionUrl = getDevelopmentConnectionUrl(TEST_DB_URI);
mongoose.connect(connectionUrl, mongooseOptions, err => {
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
return mongoose.connection.dropDatabase(err2 => {
if (err2) return cb(err2);
return mongoose.connection.close(cb);
mongoose.connect(connectionUrl, mongooseOptions)
.then(() => mongoose.connection.dropDatabase())
.then(() => mongoose.connection.close()).then(() => {
cb();
})
.catch(err => {
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
throw err;
});
});
});
gulp.task('test:prepare:server', gulp.series('test:prepare:mongo', done => {
@@ -116,8 +118,10 @@ gulp.task('test:common:safe', gulp.series('test:prepare:build', cb => {
pipe(runner);
}));
gulp.task('test:content', gulp.series('test:prepare:build',
runInChildProcess(CONTENT_TEST_COMMAND, LIMIT_MAX_BUFFER_OPTIONS)));
gulp.task('test:content', gulp.series(
'test:prepare:build',
runInChildProcess(CONTENT_TEST_COMMAND, LIMIT_MAX_BUFFER_OPTIONS),
));
gulp.task('test:content:clean', cb => {
pipe(exec(testBin(CONTENT_TEST_COMMAND), LIMIT_MAX_BUFFER_OPTIONS, () => cb()));
@@ -142,16 +146,20 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', cb => {
pipe(runner);
}));
gulp.task('test:api:unit:run',
runInChildProcess(integrationTestCommand('test/api/unit', 'coverage/api-unit')));
gulp.task(
'test:api:unit:run',
runInChildProcess(integrationTestCommand('test/api/unit', 'coverage/api-unit')),
);
gulp.task('test:api:unit:watch', () => gulp.watch(['website/server/libs/*', 'test/api/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit:run', done => done())));
gulp.task('test:api-v3:integration', gulp.series('test:prepare:mongo',
gulp.task('test:api-v3:integration', gulp.series(
'test:prepare:mongo',
runInChildProcess(
integrationTestCommand('test/api/v3/integration', 'coverage/api-v3-integration'),
LIMIT_MAX_BUFFER_OPTIONS,
)));
),
));
gulp.task('test:api-v3:integration:watch', () => gulp.watch([
'website/server/controllers/api-v3/**/*', 'common/script/ops/*', 'website/server/libs/*.js',
@@ -164,11 +172,13 @@ gulp.task('test:api-v3:integration:separate-server', runInChildProcess(
'LOAD_SERVER=0',
));
gulp.task('test:api-v4:integration', gulp.series('test:prepare:mongo',
gulp.task('test:api-v4:integration', gulp.series(
'test:prepare:mongo',
runInChildProcess(
integrationTestCommand('test/api/v4', 'api-v4-integration'),
LIMIT_MAX_BUFFER_OPTIONS,
)));
),
));
gulp.task('test:api-v4:integration:separate-server', runInChildProcess(
'mocha test/api/v4 --recursive --require ./test/helpers/start-server',

View File

@@ -3,6 +3,6 @@ module.exports = {
root: false,
rules: {
'no-console': 0,
'no-use-before-define': ['error', { functions: false }]
}
}
'no-use-before-define': ['error', { functions: false }],
},
};

View File

@@ -51,7 +51,8 @@ function getAchievementUpdate (newUser, oldUser) {
// Rebirth level
if (achievementsUpdate.rebirthLevel) {
achievementsUpdate.rebirthLevel = Math.max(
achievementsUpdate.rebirthLevel, oldAchievements.rebirthLevel,
achievementsUpdate.rebirthLevel,
oldAchievements.rebirthLevel,
);
} else if (oldAchievements.rebirthLevel) {
achievementsUpdate.rebirthLevel = oldAchievements.rebirthLevel;

View File

@@ -61,7 +61,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: {$ne: MIGRATION_NAME},
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2021-01-01')},
};

View File

@@ -105,7 +105,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};

View File

@@ -145,7 +145,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};

View File

@@ -105,7 +105,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};

View File

@@ -95,7 +95,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2022-01-01') },
};

View File

@@ -86,7 +86,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2022-01-01') },
};

View File

@@ -63,7 +63,7 @@ async function updateUser (user) {
&& pets['Wolf-Shade']
&& pets['Wolf-Skeleton']
&& pets['Wolf-White']
&& pets['Wolf-Zombie'] {
&& pets['Wolf-Zombie']) {
set['achievements.polarPro'] = true;
}
}
@@ -75,7 +75,7 @@ async function updateUser (user) {
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2022-11-01') },
};

View File

@@ -0,0 +1,158 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20230522_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['Parrot-Base']
&& pets['Parrot-CottonCandyBlue']
&& pets['Parrot-CottonCandyPink']
&& pets['Parrot-Desert']
&& pets['Parrot-Golden']
&& pets['Parrot-Red']
&& pets['Parrot-Shade']
&& pets['Parrot-Skeleton']
&& pets['Parrot-White']
&& pets['Parrot-Zombie']
&& pets['Rooster-Base']
&& pets['Rooster-CottonCandyBlue']
&& pets['Rooster-CottonCandyPink']
&& pets['Rooster-Desert']
&& pets['Rooster-Golden']
&& pets['Rooster-Red']
&& pets['Rooster-Shade']
&& pets['Rooster-Skeleton']
&& pets['Rooster-White']
&& pets['Rooster-Zombie']
&& pets['Triceratops-Base']
&& pets['Triceratops-CottonCandyBlue']
&& pets['Triceratops-CottonCandyPink']
&& pets['Triceratops-Desert']
&& pets['Triceratops-Golden']
&& pets['Triceratops-Red']
&& pets['Triceratops-Shade']
&& pets['Triceratops-Skeleton']
&& pets['Triceratops-White']
&& pets['Triceratops-Zombie']
&& pets['TRex-Base']
&& pets['TRex-CottonCandyBlue']
&& pets['TRex-CottonCandyPink']
&& pets['TRex-Desert']
&& pets['TRex-Golden']
&& pets['TRex-Red']
&& pets['TRex-Shade']
&& pets['TRex-Skeleton']
&& pets['TRex-White']
&& pets['TRex-Zombie']
&& pets['Pterodactyl-Base']
&& pets['Pterodactyl-CottonCandyBlue']
&& pets['Pterodactyl-CottonCandyPink']
&& pets['Pterodactyl-Desert']
&& pets['Pterodactyl-Golden']
&& pets['Pterodactyl-Red']
&& pets['Pterodactyl-Shade']
&& pets['Pterodactyl-Skeleton']
&& pets['Pterodactyl-White']
&& pets['Pterodactyl-Zombie']
&& pets['Owl-Base']
&& pets['Owl-CottonCandyBlue']
&& pets['Owl-CottonCandyPink']
&& pets['Owl-Desert']
&& pets['Owl-Golden']
&& pets['Owl-Red']
&& pets['Owl-Shade']
&& pets['Owl-Skeleton']
&& pets['Owl-White']
&& pets['Owl-Zombie']
&& pets['Velociraptor-Base']
&& pets['Velociraptor-CottonCandyBlue']
&& pets['Velociraptor-CottonCandyPink']
&& pets['Velociraptor-Desert']
&& pets['Velociraptor-Golden']
&& pets['Velociraptor-Red']
&& pets['Velociraptor-Shade']
&& pets['Velociraptor-Skeleton']
&& pets['Velociraptor-White']
&& pets['Velociraptor-Zombie']
&& pets['Penguin-Base']
&& pets['Penguin-CottonCandyBlue']
&& pets['Penguin-CottonCandyPink']
&& pets['Penguin-Desert']
&& pets['Penguin-Golden']
&& pets['Penguin-Red']
&& pets['Penguin-Shade']
&& pets['Penguin-Skeleton']
&& pets['Penguin-White']
&& pets['Penguin-Zombie']
&& pets['Falcon-Base']
&& pets['Falcon-CottonCandyBlue']
&& pets['Falcon-CottonCandyPink']
&& pets['Falcon-Desert']
&& pets['Falcon-Golden']
&& pets['Falcon-Red']
&& pets['Falcon-Shade']
&& pets['Falcon-Skeleton']
&& pets['Falcon-White']
&& pets['Falcon-Zombie']
&& pets['Peacock-Base']
&& pets['Peacock-CottonCandyBlue']
&& pets['Peacock-CottonCandyPink']
&& pets['Peacock-Desert']
&& pets['Peacock-Golden']
&& pets['Peacock-Red']
&& pets['Peacock-Shade']
&& pets['Peacock-Skeleton']
&& pets['Peacock-White']
&& pets['Peacock-Zombie']) {
set['achievements.dinosaurDynasty'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2023-04-15') },
};
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
}
};

View File

@@ -0,0 +1,79 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20230718_summer_splash_orcas';
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 };
const push = {};
if (user && user.items && user.items.pets && typeof user.items.pets['Orca-Base'] !== 'undefined') {
return;
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Orca-Base'] !== 'undefined') {
set['items.pets.Orca-Base'] = 5;
push.notifications = {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_orca_pet',
title: 'Orcas for Summer Splash!',
text: 'To celebrate Summer Splash, we\'ve given you an Orca Pet!',
destination: 'stable',
},
seen: false,
};
} else {
set['items.mounts.Orca-Base'] = true;
push.notifications = {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_orca_mount',
title: 'Orcas for Summer Splash!',
text: 'To celebrate Summer Splash, we\'ve given you an Orca Mount!',
destination: 'stable',
},
seen: false,
};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await user.updateOne({ $set: set, $push: push }).exec();
}
export default async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2023-06-18')},
};
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)
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,155 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20230731_naming_day';
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++;
let set;
let push;
const inc = {
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Red': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_Skeleton': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Zombie': 1,
'achievements.habiticaDays': 1,
};
if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.back_special_namingDay2020 !== 'undefined') {
set = { migration: MIGRATION_NAME };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_cake',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you some cake!',
destination: '/inventory/items',
},
seen: false,
},
};
} else if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.body_special_namingDay2018 !== 'undefined') {
set = { migration: MIGRATION_NAME, 'items.gear.owned.back_special_namingDay2020': true };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_back',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you a Royal Purple Gryphon Tail and cake!',
destination: '/inventory/equipment',
},
seen: false,
},
};
} else if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.head_special_namingDay2017 !== 'undefined') {
set = { migration: MIGRATION_NAME, 'items.gear.owned.body_special_namingDay2018': true };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_body',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you a Royal Purple Gryphon Cloak and cake!',
destination: '/inventory/equipment',
},
seen: false,
},
};
} else if (user && user.items && user.items.pets && typeof user.items.pets['Gryphon-RoyalPurple'] !== 'undefined') {
set = { migration: MIGRATION_NAME, 'items.gear.owned.head_special_namingDay2017': true };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_head',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you a Royal Purple Gryphon Helm and cake!',
destination: '/inventory/equipment',
},
seen: false,
},
};
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Gryphon-RoyalPurple'] !== 'undefined') {
set = { migration: MIGRATION_NAME, 'items.pets.Gryphon-RoyalPurple': 5 };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_pet',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you a Royal Purple Gryphon Pet and cake!',
destination: '/inventory/stable',
},
seen: false,
},
};
} else {
set = { migration: MIGRATION_NAME, 'items.mounts.Gryphon-RoyalPurple': true };
push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_mount',
title: 'Happy Naming Day!',
text: 'To celebrate the day we became Habitica, weve awarded you a Royal Purple Gryphon Mount and cake!',
destination: '/inventory/stable',
},
seen: false,
},
};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
if (push) {
return await user.updateOne({ $set: set, $inc: inc, $push: push }).exec();
} else {
return await user.updateOne({ $set: set, $inc: inc }).exec();
}
}
export default async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2023-07-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)
.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
}
};

View File

@@ -0,0 +1,72 @@
/* eslint-disable no-console */
import { model as User } from '../../../website/server/models/user';
import { model as Group } from '../../../website/server/models/group';
const guildsPerRun = 500;
const progressCount = 1000;
const guildsQuery = {
type: 'guild',
};
let count = 0;
async function updateGroup (guild) {
count++;
if (count % progressCount === 0) {
console.warn(`${count} ${guild._id}`);
}
if (guild.hasActiveGroupPlan()) {
return console.warn(`Guild ${guild._id} is active Group Plan`);
}
const leader = await User
.findOne({ _id: guild.leader })
.select({ _id: true })
.exec();
if (!leader) {
return console.warn(`Leader not found for Guild ${guild._id}`);
}
if (guild.balance > 0) {
await leader.updateBalance(
guild.balance,
'create_guild',
'',
`Guild Bank refund for ${guild.name} (${guild._id})`,
);
}
return guild.updateOne({ $set: { balance: 0 } }).exec();
}
export default async function processGroups () {
const guildFields = {
_id: 1,
balance: 1,
leader: 1,
name: 1,
purchased: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const foundGroups = await Group // eslint-disable-line no-await-in-loop
.find(guildsQuery)
.limit(guildsPerRun)
.sort({ _id: 1 })
.select(guildFields)
.exec();
if (foundGroups.length === 0) {
console.warn('All appropriate Guilds found and modified.');
console.warn(`\n${count} Guilds processed\n`);
break;
} else {
guildsQuery._id = {
$gt: foundGroups[foundGroups.length - 1],
};
}
await Promise.all(foundGroups.map(guild => updateGroup(guild))); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,62 @@
/* eslint-disable no-console */
import { model as User } from '../../../website/server/models/user';
import { TransactionModel as Transaction } from '../../../website/server/models/transaction';
const transactionsPerRun = 500;
const progressCount = 1000;
const transactionsQuery = {
transactionType: 'create_guild',
amount: { $gt: 0 },
};
let count = 0;
async function updateTransaction (transaction) {
count++;
if (count % progressCount === 0) {
console.warn(`${count} ${transaction._id}`);
}
const leader = await User
.findOne({ _id: transaction.userId })
.select({ _id: true })
.exec();
if (!leader) {
return console.warn(`User not found for transaction ${transaction._id}`);
}
return leader.updateOne(
{ $inc: { balance: transaction.amount }},
).exec();
}
export default async function processTransactions () {
const transactionFields = {
_id: 1,
userId: 1,
currency: 1,
amount: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const foundTransactions = await Transaction // eslint-disable-line no-await-in-loop
.find(transactionsQuery)
.limit(transactionsPerRun)
.sort({ _id: 1 })
.select(transactionFields)
.lean()
.exec();
if (foundTransactions.length === 0) {
console.warn('All appropriate transactions found and modified.');
console.warn(`\n${count} transactions processed\n`);
break;
} else {
transactionsQuery._id = {
$gt: foundTransactions[foundTransactions.length - 1],
};
}
await Promise.all(foundTransactions.map(txn => updateTransaction(txn))); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,144 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20230808_veteran_pet_ladder';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {};
let push = { notifications: { $each: [] }};
set.migration = MIGRATION_NAME;
if (user.items.pets['Fox-Veteran']) {
set['items.pets.Dragon-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_dragon',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Dragon.',
destination: '/inventory/stable',
},
seen: false,
});
} else if (user.items.pets['Bear-Veteran']) {
set['items.pets.Fox-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_fox',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Fox.',
destination: '/inventory/stable',
},
seen: false,
});
} else if (user.items.pets['Lion-Veteran']) {
set['items.pets.Bear-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_bear',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Bear.',
destination: '/inventory/stable',
},
seen: false,
});
} else if (user.items.pets['Tiger-Veteran']) {
set['items.pets.Lion-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_lion',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Lion.',
destination: '/inventory/stable',
},
seen: false,
});
} else if (user.items.pets['Wolf-Veteran']) {
set['items.pets.Tiger-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_tiger',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Tiger.',
destination: '/inventory/stable',
},
seen: false,
});
} else {
set['items.pets.Wolf-Veteran'] = 5;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'icon_pet_veteran_wolf',
title: 'Youve received a Veteran Pet!',
text: 'To commemorate being here for a new era of Habitica, weve awarded you a Veteran Wolf.',
destination: '/inventory/stable',
},
seen: false,
});
}
if (user.contributor.level > 0) {
set['items.gear.owned.armor_special_heroicTunic'] = true;
set['items.gear.owned.back_special_heroicAureole'] = true;
set['items.gear.owned.headAccessory_special_heroicCirclet'] = true;
push.notifications.$each.push({
type: 'ITEM_RECEIVED',
data: {
icon: 'heroic_set_icon',
title: 'Youve received the Heroic Set!',
text: 'To commemorate your hard work as a contributor, weve awarded you the Heroic Circlet, Heroic Aureole, and Heroic Tunic.',
destination: '/inventory/equipment',
},
seen: false,
});
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$set: set, $push: push}).exec();
}
export default async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': { $gt: new Date('2023-07-08') },
};
const fields = {
_id: 1,
items: 1,
migration: 1,
contributor: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,118 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20231017_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['Armadillo-Base']
&& pets['Armadillo-CottonCandyBlue']
&& pets['Armadillo-CottonCandyPink']
&& pets['Armadillo-Desert']
&& pets['Armadillo-Golden']
&& pets['Armadillo-Red']
&& pets['Armadillo-Shade']
&& pets['Armadillo-Skeleton']
&& pets['Armadillo-White']
&& pets['Armadillo-Zombie']
&& pets['Cactus-Base']
&& pets['Cactus-CottonCandyBlue']
&& pets['Cactus-CottonCandyPink']
&& pets['Cactus-Desert']
&& pets['Cactus-Golden']
&& pets['Cactus-Red']
&& pets['Cactus-Shade']
&& pets['Cactus-Skeleton']
&& pets['Cactus-White']
&& pets['Cactus-Zombie']
&& pets['Fox-Base']
&& pets['Fox-CottonCandyBlue']
&& pets['Fox-CottonCandyPink']
&& pets['Fox-Desert']
&& pets['Fox-Golden']
&& pets['Fox-Red']
&& pets['Fox-Shade']
&& pets['Fox-Skeleton']
&& pets['Fox-White']
&& pets['Fox-Zombie']
&& pets['Frog-Base']
&& pets['Frog-CottonCandyBlue']
&& pets['Frog-CottonCandyPink']
&& pets['Frog-Desert']
&& pets['Frog-Golden']
&& pets['Frog-Red']
&& pets['Frog-Shade']
&& pets['Frog-Skeleton']
&& pets['Frog-White']
&& pets['Frog-Zombie']
&& pets['Snake-Base']
&& pets['Snake-CottonCandyBlue']
&& pets['Snake-CottonCandyPink']
&& pets['Snake-Desert']
&& pets['Snake-Golden']
&& pets['Snake-Red']
&& pets['Snake-Shade']
&& pets['Snake-Skeleton']
&& pets['Snake-White']
&& pets['Snake-Zombie']
&& pets['Spider-Base']
&& pets['Spider-CottonCandyBlue']
&& pets['Spider-CottonCandyPink']
&& pets['Spider-Desert']
&& pets['Spider-Golden']
&& pets['Spider-Red']
&& pets['Spider-Shade']
&& pets['Spider-Skeleton']
&& pets['Spider-White']
&& pets['Spider-Zombie']) {
set['achievements.duneBuddy'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.updateOne({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2023-09-16') },
};
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
}
};

View File

@@ -0,0 +1,124 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20231114_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
let set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['Cactus-Zombie'] > 0
&& pets['Cactus-Skeleton'] > 0
&& pets['Cactus-Base'] > 0
&& pets['Cactus-Desert'] > 0
&& pets['Cactus-Red'] > 0
&& pets['Cactus-Shade'] > 0
&& pets['Cactus-White']> 0
&& pets['Cactus-Golden'] > 0
&& pets['Cactus-CottonCandyBlue'] > 0
&& pets['Cactus-CottonCandyPink'] > 0
&& pets['Hedgehog-Zombie'] > 0
&& pets['Hedgehog-Skeleton'] > 0
&& pets['Hedgehog-Base'] > 0
&& pets['Hedgehog-Desert'] > 0
&& pets['Hedgehog-Red'] > 0
&& pets['Hedgehog-Shade'] > 0
&& pets['Hedgehog-White'] > 0
&& pets['Hedgehog-Golder'] > 0
&& pets['Hedgehog-CottonCandyBlue'] > 0
&& pets['Hedgehog-CottonCandyPink'] > 0
&& pets['Rock-Zombie'] > 0
&& pets['Rock-Skeleton'] > 0
&& pets['Rock-Base'] > 0
&& pets['Rock-Desert'] > 0
&& pets['Rock-Red'] > 0
&& pets['Rock-Shade'] > 0
&& pets['Rock-White'] > 0
&& pets['Rock-Golden'] > 0
&& pets['Rock-CottonCandyBlue'] > 0
&& pets['Rock-CottonCandyPink'] > 0 ) {
set['achievements.roughRider'] = true;
}
}
if (user && user.items && user.items.mounts) {
const mounts = user.items.mounts;
if (mounts['Cactus-Zombie']
&& mounts['Cactus-Skeleton']
&& mounts['Cactus-Base']
&& mounts['Cactus-Desert']
&& mounts['Cactus-Red']
&& mounts['Cactus-Shade']
&& mounts['Cactus-White']
&& mounts['Cactus-Golden']
&& mounts['Cactus-CottonCandyPink']
&& mounts['Cactus-CottonCandyBlue']
&& mounts['Hedgehog-Zombie']
&& mounts['Hedgehog-Skeleton']
&& mounts['Hedgehog-Base']
&& mounts['Hedgehog-Desert']
&& mounts['Hedgehog-Red']
&& mounts['Hedgehog-Shade']
&& mounts['Hedgehog-White']
&& mounts['Hedgehog-Golden']
&& mounts['Hedgehog-CottonCandyPink']
&& mounts['Hedgehog-CottonCandyBlue']
&& mounts['Rock-Zombie']
&& mounts['Rock-Skeleton']
&& mounts['Rock-Base']
&& mounts['Rock-Desert']
&& mounts['Rock-Red']
&& mounts['Rock-Shade']
&& mounts['Rock-White']
&& mounts['Rock-Golden']
&& mounts['Rock-CottonCandyPink']
&& mounts['Rock-CottonCandyBlue'] ) {
set['achievements.roughRider'] = 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('2023-02-01') },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1]._id,
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,87 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20231228_nye';
import { model as User } from '../../../website/server/models/user';
import { v4 as uuid } from 'uuid';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = { migration: MIGRATION_NAME };
let push = {};
if (typeof user.items.gear.owned.head_special_nye2022 !== 'undefined') {
set['items.gear.owned.head_special_nye2023'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2021 !== 'undefined') {
set['items.gear.owned.head_special_nye2022'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2020 !== 'undefined') {
set['items.gear.owned.head_special_nye2021'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2019 !== 'undefined') {
set['items.gear.owned.head_special_nye2020'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2018 !== 'undefined') {
set['items.gear.owned.head_special_nye2019'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
set['items.gear.owned.head_special_nye2018'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
set['items.gear.owned.head_special_nye2017'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
set['items.gear.owned.head_special_nye2016'] = true;
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
set['items.gear.owned.head_special_nye2015'] = true;
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
set['items.gear.owned.head_special_nye2014'] = true;
} else {
set['items.gear.owned.head_special_nye'] = true;
}
push.notifications = {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_head_special_nye',
title: 'Happy New Year!',
text: 'Check your Equipment for this year\'s party hat!',
destination: 'inventory/equipment',
},
seen: false,
};
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.updateOne({_id: user._id}, {$set: set, $push: push}).exec();
}
export default async function processUsers () {
let query = {
'auth.timestamps.loggedin': { $gt: new Date('2023-12-01') },
migration: { $ne: MIGRATION_NAME },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -0,0 +1,102 @@
/* eslint-disable no-console */
import { v4 as uuid } from 'uuid';
import { model as User } from '../../../website/server/models/user';
const MIGRATION_NAME = '20240131_habit_birthday';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count += 1;
const inc = {
'items.food.Cake_Skeleton': 1,
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Zombie': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Red': 1,
'achievements.habitBirthdays': 1,
};
const set = {};
const push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_namingDay_cake',
title: 'Happy Habit Birthday!',
text: 'Habitica turns 11 today! Enjoy free party robes and cake!',
destination: 'inventory/equipment',
},
seen: false,
},
};
set.migration = MIGRATION_NAME;
if (typeof user.items.gear.owned.armor_special_birthday2023 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2024'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2022 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2023'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2021 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2022'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2020 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2021'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2019 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2020'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2018 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2019'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2017 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2018'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2016 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2017'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday2015 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2016'] = true;
} else if (typeof user.items.gear.owned.armor_special_birthday !== 'undefined') {
set['items.gear.owned.armor_special_birthday2015'] = true;
} else {
set['items.gear.owned.armor_special_birthday'] = true;
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.updateOne({_id: user._id}, {$inc: inc, $set: set, $push: push}).exec();
}
export default async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2023-12-23')},
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};

View File

@@ -1,118 +0,0 @@
let migrationName = '20180904_takeThis.js'; // Update per month
let authorName = 'Sabe'; // in case script author needs to know when their ...
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
/*
* Award Take This ladder items to participants in this month's challenge
*/
import monk from 'monk';
import nconf from 'nconf';
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
migration: {$ne: migrationName},
challenges: {$in: ['1044ec0c-4a85-48c5-9f36-d51c0c62c7d3']}, // Update per month
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
fields: [
'items.gear.owned',
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
count++;
let set = {};
let push;
if (typeof user.items.gear.owned.back_special_takeThis !== 'undefined') {
set = {migration: migrationName};
} else if (typeof user.items.gear.owned.body_special_takeThis !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.back_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.back_special_takeThis', _id: monk.id()}};
} else if (typeof user.items.gear.owned.head_special_takeThis !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.body_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.body_special_takeThis', _id: monk.id()}};
} else if (typeof user.items.gear.owned.armor_special_takeThis !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.head_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.head_special_takeThis', _id: monk.id()}};
} else if (typeof user.items.gear.owned.weapon_special_takeThis !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.armor_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_takeThis', _id: monk.id()}};
} else if (typeof user.items.gear.owned.shield_special_takeThis !== 'undefined') {
set = {migration: migrationName, 'items.gear.owned.weapon_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.weapon_special_takeThis', _id: monk.id()}};
} else {
set = {migration: migrationName, 'items.gear.owned.shield_special_takeThis': false};
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.shield_special_takeThis', _id: monk.id()}};
}
if (push) {
dbUsers.update({_id: user._id}, {$set: set, $push: push});
} else {
dbUsers.update({_id: user._id}, {$set: set});
}
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
}
}
process.exit(code);
}
module.exports = processUsers;

View File

@@ -1,10 +0,0 @@
import csv
with open(r"/home/slappybag/Documents/SurveyScrape.csv") as f:
reader = csv.reader(f, delimiter=',', quotechar='"')
column = []
for row in reader:
if row:
column.append(row[4])
print column

View File

@@ -21,12 +21,14 @@ async function handOutJackalopes () {
if (user.party._id) groupList.push(user.party._id);
groupList = groupList.concat(user.guilds);
const subscribedGroup = await Group.findOne({
_id: { $in: groupList },
'purchased.plan.planId': 'group_monthly',
'purchased.plan.dateTerminated': null,
},
{ _id: 1 });
const subscribedGroup = await Group.findOne(
{
_id: { $in: groupList },
'purchased.plan.planId': 'group_monthly',
'purchased.plan.dateTerminated': null,
},
{ _id: 1 },
);
if (subscribedGroup) {
User.update({ _id: user._id }, { $set: { 'items.mounts.Jackalope-RoyalPurple': true } }).exec();

View File

@@ -16,6 +16,7 @@ async function updateUser (user) {
if (count % progressCount === 0) {
console.warn(`${count} ${user._id}`);
// eslint-disable-next-line no-promise-executor-return
await new Promise(resolve => setTimeout(resolve, 5000));
}

7864
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +1,37 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.267.3",
"version": "5.18.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
"@babel/register": "^7.18.9",
"@babel/core": "^7.22.10",
"@babel/preset-env": "^7.22.10",
"@babel/register": "^7.22.15",
"@google-cloud/trace-agent": "^7.1.2",
"@parse/node-apn": "^5.1.3",
"@parse/node-apn": "^5.2.3",
"@slack/webhook": "^6.1.0",
"accepts": "^1.3.8",
"amazon-payments": "^0.2.9",
"amplitude": "^6.0.0",
"apidoc": "^0.54.0",
"apple-auth": "^1.0.7",
"bcrypt": "^5.1.0",
"body-parser": "^1.20.1",
"bootstrap": "^4.6.0",
"apple-auth": "^1.0.9",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2",
"bootstrap": "^4.6.2",
"compression": "^1.7.4",
"cookie-session": "^2.0.0",
"coupon-code": "^0.4.5",
"csv-stringify": "^5.6.5",
"cwait": "^1.1.1",
"domain-middleware": "~0.1.0",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
"eslint": "^8.55.0",
"eslint-config-habitrpg": "^6.2.3",
"eslint-plugin-mocha": "^5.0.0",
"express": "^4.18.2",
"express-basic-auth": "^1.2.1",
"express-validator": "^5.2.0",
"glob": "^8.1.0",
"got": "^11.8.3",
"got": "^11.8.6",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0",
"gulp-imagemin": "^7.1.0",
@@ -39,44 +39,42 @@
"gulp.spritesmith": "^6.13.0",
"habitica-markdown": "^3.0.0",
"helmet": "^4.6.0",
"image-size": "^1.0.2",
"in-app-purchase": "^1.11.3",
"js2xmlparser": "^5.0.0",
"jsonwebtoken": "^8.5.1",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^2.1.5",
"lodash": "^4.17.21",
"merge-stream": "^2.0.0",
"method-override": "^3.0.0",
"moment": "^2.29.4",
"moment-recur": "^1.0.7",
"mongoose": "^5.13.7",
"mongoose": "^7.6.3",
"morgan": "^1.10.0",
"nconf": "^0.12.0",
"nconf": "^0.12.1",
"node-gcm": "^1.0.5",
"nodemon": "^2.0.20",
"on-headers": "^1.0.2",
"passport": "^0.5.0",
"passport": "^0.5.3",
"passport-facebook": "^3.0.0",
"passport-google-oauth2": "^0.2.0",
"passport-google-oauth20": "2.0.0",
"paypal-rest-sdk": "^1.8.1",
"pp-ipn": "^1.1.0",
"ps-tree": "^1.0.0",
"rate-limiter-flexible": "^2.4.0",
"rate-limiter-flexible": "^2.4.2",
"redis": "^3.1.2",
"regenerator-runtime": "^0.13.11",
"remove-markdown": "^0.5.0",
"rimraf": "^3.0.2",
"short-uuid": "^4.2.2",
"stripe": "^11.10.0",
"superagent": "^8.0.6",
"stripe": "^12.18.0",
"superagent": "^8.1.2",
"universal-analytics": "^0.5.3",
"useragent": "^2.1.9",
"uuid": "^9.0.0",
"validator": "^13.9.0",
"vinyl-buffer": "^1.0.1",
"winston": "^3.8.2",
"winston-loggly-bulk": "^3.2.1",
"xml2js": "^0.4.23"
"validator": "^13.11.0",
"winston": "^3.10.0",
"winston-loggly-bulk": "^3.3.0",
"xml2js": "^0.6.2"
},
"private": true,
"engines": {
@@ -105,16 +103,16 @@
"client:unit": "cd website/client && npm run test:unit",
"start": "gulp nodemon",
"debug": "gulp nodemon --inspect",
"mongo:dev": "run-rs -v 4.2.8 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
"apidoc": "gulp apidoc"
},
"devDependencies": {
"axios": "^1.2.2",
"axios": "^1.4.0",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"chai-moment": "^0.1.0",
"chalk": "^5.2.0",
"chalk": "^5.3.0",
"cross-spawn": "^7.0.3",
"expect.js": "^0.3.1",
"istanbul": "^1.1.0-alpha.1",
@@ -122,7 +120,7 @@
"monk": "^7.3.4",
"require-again": "^2.0.0",
"run-rs": "^0.7.7",
"sinon": "^15.0.1",
"sinon": "^15.2.0",
"sinon-chai": "^3.7.0",
"sinon-stub-promise": "^4.0.0"
},

View File

@@ -44,6 +44,7 @@ async function deleteHabiticaData (user, email) {
{ _id: user._id },
{ $set: set },
);
// eslint-disable-next-line no-promise-executor-return
await new Promise(resolve => setTimeout(resolve, 1000));
const response = await axios.delete(
`${BASE_URL}/api/v3/user`,
@@ -96,6 +97,7 @@ async function processEmailAddress (email) {
return console.log(`No users found with email address ${email}`);
}
// eslint-disable-next-line no-promise-executor-return
await new Promise(resolve => setTimeout(resolve, 1000));
return Promise.all(users.map(user => (async () => {
await deleteAmplitudeData(user._id, email); // eslint-disable-line no-await-in-loop

View File

@@ -1,3 +1,5 @@
/* eslint-disable import/no-commonjs */
module.exports = {
extends: [
'habitrpg/lib/mocha',
@@ -7,6 +9,9 @@ module.exports = {
chai: true,
expect: true,
sinon: true,
sandbox: true
sandbox: true,
},
}
rules: {
'import/no-extraneous-dependencies': 'off',
},
};

View File

@@ -26,9 +26,7 @@ describe('bug-report', () => {
_id: userId,
});
const result = await bugReportLogic(
user, userMail, userMessage, userAgent,
);
const result = await bugReportLogic(user, userMail, userMessage, userAgent);
expect(emailLib.sendTxn).to.be.called;
expect(result).to.deep.equal({

View File

@@ -44,7 +44,7 @@ describe('mongodb', () => {
const mongoLibOverride = requireAgain(pathToMongoLib);
const options = mongoLibOverride.getDefaultConnectionOptions();
expect(options).to.have.all.keys(['useNewUrlParser', 'useUnifiedTopology', 'keepAlive', 'keepAliveInitialDelay']);
expect(options).to.have.all.keys(['useNewUrlParser', 'useUnifiedTopology']);
});
});
});

View File

@@ -227,7 +227,7 @@ describe('Password Utilities', () => {
expiresAt: moment().subtract({ minutes: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -264,7 +264,7 @@ describe('Password Utilities', () => {
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': 'invalid',
});
@@ -280,7 +280,7 @@ describe('Password Utilities', () => {
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});

View File

@@ -342,10 +342,12 @@ describe('Apple Payments', () => {
}]);
sub = common.content.subscriptionBlocks[newOption.subKey];
await applePayments.subscribe(user,
await applePayments.subscribe(
user,
receipt,
headers,
nextPaymentProcessing);
nextPaymentProcessing,
);
expect(iapSetupStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledOnce;
@@ -387,10 +389,12 @@ describe('Apple Payments', () => {
}]);
sub = common.content.subscriptionBlocks[newOption.subKey];
await applePayments.subscribe(user,
await applePayments.subscribe(
user,
receipt,
headers,
nextPaymentProcessing);
nextPaymentProcessing,
);
expect(iapSetupStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledOnce;
@@ -517,9 +521,7 @@ describe('Apple Payments', () => {
const secondUser = new User();
await secondUser.save();
await expect(applePayments.subscribe(
secondUser, receipt, headers, nextPaymentProcessing,
))
await expect(applePayments.subscribe(secondUser, receipt, headers, nextPaymentProcessing))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',
@@ -559,9 +561,7 @@ describe('Apple Payments', () => {
const thirdUser = new User();
await thirdUser.save();
await expect(applePayments.subscribe(
thirdUser, receipt, headers, nextPaymentProcessing,
))
await expect(applePayments.subscribe(thirdUser, receipt, headers, nextPaymentProcessing))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
name: 'NotAuthorized',

View File

@@ -748,9 +748,19 @@ describe('payments/index', () => {
});
it('does not add to plans.consecutive.offset if 1 month subscription', async () => {
data.sub.key = 'basic_earned';
await api.createSubscription(data);
expect(user.purchased.plan.extraMonths).to.eql(0);
expect(user.purchased.plan.consecutive.offset).to.eql(0);
});
it('resets plans.consecutive.offset if 1 month subscription', async () => {
user.purchased.plan.consecutive.offset = 1;
await user.save();
data.sub.key = 'basic_earned';
await api.createSubscription(data);
expect(user.purchased.plan.consecutive.offset).to.eql(0);
});
it('adds 5 to plan.consecutive.gemCapExtra for 3 month block', async () => {
@@ -1372,18 +1382,6 @@ describe('payments/index', () => {
expect(user.purchased.plan.mysteryItems).to.have.a.lengthOf(1);
expect(user.purchased.plan.mysteryItems).to.include('head_mystery_201605');
});
it('does not award mystery item when user already has the item in the mystery box', async () => {
user.purchased.plan.mysteryItems = [mayMysteryItem];
sandbox.spy(user.purchased.plan.mysteryItems, 'push');
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
await api.createSubscription(data);
expect(user.purchased.plan.mysteryItems.push).to.be.calledOnce;
expect(user.purchased.plan.mysteryItems.push).to.be.calledWith('head_mystery_201605');
});
});
});
@@ -1589,10 +1587,10 @@ describe('payments/index', () => {
it('sends gem donation message in each participant\'s language', async () => {
// TODO using english for both users because other languages are not loaded
// for api.buyGems
await recipient.update({
await recipient.updateOne({
'preferences.language': 'en',
});
await user.update({
await user.updateOne({
'preferences.language': 'en',
});
await api.buyGems(data);

View File

@@ -53,11 +53,9 @@ describe('cron middleware', () => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
Tasks.Task.findOne({ _id: task }, (secondErr, taskFound) => {
if (secondErr) return reject(err);
expect(secondErr).to.not.exist;
expect(taskFound).to.not.exist;
return resolve();
Tasks.Task.findOne({ _id: task }).then(foundTask => {
expect(foundTask).to.not.exist;
resolve();
});
return null;
@@ -78,10 +76,8 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
Tasks.Task.findOne({ _id: task }, (secondErr, taskFound) => {
if (secondErr) return reject(secondErr);
expect(secondErr).to.not.exist;
expect(taskFound).to.exist;
Tasks.Task.findOne({ _id: task }).then(foundTask => {
expect(foundTask).to.exist;
return resolve();
});
return null;
@@ -103,10 +99,8 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
Tasks.Task.findOne({ _id: task }, (secondErr, taskFound) => {
if (secondErr) return reject(secondErr);
expect(secondErr).to.not.exist;
expect(taskFound).to.not.exist;
Tasks.Task.findOne({ _id: task }).then(foundTask => {
expect(foundTask).to.not.exist;
return resolve();
});
return null;
@@ -170,8 +164,7 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
return User.findOne({ _id: user._id }, (secondErr, updatedUser) => {
if (secondErr) return reject(secondErr);
return User.findOne({ _id: user._id }).then(updatedUser => {
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
return resolve();
});
@@ -188,8 +181,7 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
return Tasks.Task.findOne({ _id: todo._id }, (secondErr, todoFound) => {
if (secondErr) return reject(secondErr);
return Tasks.Task.findOne({ _id: todo._id }).then(todoFound => {
expect(todoFound.value).to.be.lessThan(todoValueBefore);
return resolve();
});
@@ -224,8 +216,7 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, err => {
if (err) return reject(err);
return User.findOne({ _id: user._id }, (secondErr, updatedUser) => {
if (secondErr) return reject(secondErr);
return User.findOne({ _id: user._id }).then(updatedUser => {
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
return resolve();
});
@@ -238,11 +229,11 @@ describe('cron middleware', () => {
await user.save();
const updatedUser = user.toObject();
updatedUser.nMatched = 0;
updatedUser.matchedCount = 0;
sandbox.spy(cronLib, 'recoverCron');
sandbox.stub(User, 'update')
sandbox.stub(User, 'updateOne')
.withArgs({
_id: user._id,
$or: [
@@ -269,7 +260,7 @@ describe('cron middleware', () => {
it('cronSignature less than an hour ago should error', async () => {
user.lastCron = moment(new Date()).subtract({ days: 2 });
const now = new Date();
await User.update({
await User.updateOne({
_id: user._id,
}, {
$set: {
@@ -291,7 +282,7 @@ describe('cron middleware', () => {
it('cronSignature longer than an hour ago should allow cron', async () => {
user.lastCron = moment(new Date()).subtract({ days: 2 });
const now = new Date();
await User.update({
await User.updateOne({
_id: user._id,
}, {
$set: {

View File

@@ -1358,7 +1358,7 @@ describe('Group Model', () => {
describe('#sendChat', () => {
beforeEach(() => {
sandbox.spy(User, 'update');
sandbox.spy(User, 'updateOne');
sandbox.spy(User, 'updateMany');
});
@@ -1450,7 +1450,7 @@ describe('Group Model', () => {
party.sendChat({ message: 'message' });
expect(User.update).to.not.be.called;
expect(User.updateMany).to.not.be.called;
});
it('skips sending messages to the tavern', () => {
@@ -1458,7 +1458,7 @@ describe('Group Model', () => {
party.sendChat({ message: 'message' });
expect(User.update).to.not.be.called;
expect(User.updateMany).to.not.be.called;
});
});
@@ -1732,7 +1732,7 @@ describe('Group Model', () => {
});
it('updates participting members (not including user)', async () => {
sandbox.spy(User, 'update');
sandbox.spy(User, 'updateMany');
await party.startQuest(nonParticipatingMember);
@@ -1740,7 +1740,7 @@ describe('Group Model', () => {
questLeader._id, participatingMember._id, sleepingParticipatingMember._id,
];
expect(User.update).to.be.calledWith(
expect(User.updateMany).to.be.calledWith(
{ _id: { $in: members } },
{
$set: {
@@ -1753,11 +1753,11 @@ describe('Group Model', () => {
});
it('updates non-user quest leader and decrements quest scroll', async () => {
sandbox.spy(User, 'update');
sandbox.spy(User, 'updateOne');
await party.startQuest(participatingMember);
expect(User.update).to.be.calledWith(
expect(User.updateOne).to.be.calledWith(
{ _id: questLeader._id },
{
$inc: {
@@ -1819,29 +1819,29 @@ describe('Group Model', () => {
};
it('doesn\'t retry successful operations', async () => {
sandbox.stub(User, 'update').returns(successfulMock);
sandbox.stub(User, 'updateOne').returns(successfulMock);
await party.finishQuest(quest);
expect(User.update).to.be.calledThrice;
expect(User.updateOne).to.be.calledThrice;
});
it('stops retrying when a successful update has occurred', async () => {
const updateStub = sandbox.stub(User, 'update');
const updateStub = sandbox.stub(User, 'updateOne');
updateStub.onCall(0).returns(failedMock);
updateStub.returns(successfulMock);
await party.finishQuest(quest);
expect(User.update.callCount).to.equal(4);
expect(User.updateOne.callCount).to.equal(4);
});
it('retries failed updates at most five times per user', async () => {
sandbox.stub(User, 'update').returns(failedMock);
sandbox.stub(User, 'updateOne').returns(failedMock);
await expect(party.finishQuest(quest)).to.eventually.be.rejected;
expect(User.update.callCount).to.eql(15); // for 3 users
expect(User.updateOne.callCount).to.eql(15); // for 3 users
});
});
@@ -2088,17 +2088,17 @@ describe('Group Model', () => {
context('Party quests', () => {
it('updates participating members with rewards', async () => {
sandbox.spy(User, 'update');
sandbox.spy(User, 'updateOne');
await party.finishQuest(quest);
expect(User.update).to.be.calledThrice;
expect(User.update).to.be.calledWithMatch({
expect(User.updateOne).to.be.calledThrice;
expect(User.updateOne).to.be.calledWithMatch({
_id: questLeader._id,
});
expect(User.update).to.be.calledWithMatch({
expect(User.updateOne).to.be.calledWithMatch({
_id: participatingMember._id,
});
expect(User.update).to.be.calledWithMatch({
expect(User.updateOne).to.be.calledWithMatch({
_id: sleepingParticipatingMember._id,
});
});
@@ -2173,11 +2173,11 @@ describe('Group Model', () => {
});
it('updates all users with rewards', async () => {
sandbox.spy(User, 'update');
sandbox.spy(User, 'updateMany');
await party.finishQuest(tavernQuest);
expect(User.update).to.be.calledOnce;
expect(User.update).to.be.calledWithMatch({});
expect(User.updateMany).to.be.calledOnce;
expect(User.updateMany).to.be.calledWithMatch({});
});
it('sets quest completed to the world quest key', async () => {

View File

@@ -103,7 +103,7 @@ describe('NewsPost Model', () => {
beforeEach(async () => {
// Delete all existing posts from the database
await NewsPost.remove();
await NewsPost.deleteMany();
});
afterEach(() => {
@@ -116,7 +116,7 @@ describe('NewsPost Model', () => {
_id: v4(), publishDate: new Date(), published: true,
};
NewsPost.updateLastNewsPost(previousPost);
intervalId = refreshNewsPost(50); // refreshes every 50ms
intervalId = refreshNewsPost(100); // refreshes every 100ms
await sleep(0.1); // wait 100ms to make sure the new post has a more recent publishDate
const newPost = await NewsPost.create({

View File

@@ -221,7 +221,8 @@ describe('Task Model', () => {
it('returns task by alias', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias], user._id,
[taskWithAlias.alias],
user._id,
);
expect(foundTasks[0].text).to.eql(taskWithAlias.text);
@@ -229,7 +230,8 @@ describe('Task Model', () => {
it('returns multiple tasks', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias, secondTask._id], user._id,
[taskWithAlias.alias, secondTask._id],
user._id,
);
expect(foundTasks.length).to.eql(2);
@@ -239,7 +241,8 @@ describe('Task Model', () => {
it('returns a task only once if searched by both id and alias', async () => {
const foundTasks = await Tasks.Task.findMultipleByIdOrAlias(
[taskWithAlias.alias, taskWithAlias._id], user._id,
[taskWithAlias.alias, taskWithAlias._id],
user._id,
);
expect(foundTasks.length).to.eql(1);

View File

@@ -188,7 +188,7 @@ describe('User Model', () => {
it('removes invalid tags when loading the user', async () => {
let user = new User();
await user.save();
await user.update({
await user.updateOne({
$set: {
tags: [
null, // invalid, not an object
@@ -212,7 +212,7 @@ describe('User Model', () => {
it('removes invalid push devices when loading the user', async () => {
let user = new User();
await user.save();
await user.update({
await user.updateOne({
$set: {
pushDevices: [
null, // invalid, not an object
@@ -236,7 +236,7 @@ describe('User Model', () => {
it('removes duplicate push devices when loading the user', async () => {
let user = new User();
await user.save();
await user.update({
await user.updateOne({
$set: {
pushDevices: [
{ type: 'android', regId: '1234' },
@@ -258,7 +258,7 @@ describe('User Model', () => {
it('removes invalid notifications when loading the user', async () => {
let user = new User();
await user.save();
await user.update({
await user.updateOne({
$set: {
notifications: [
null, // invalid, not an object
@@ -284,7 +284,7 @@ describe('User Model', () => {
it('removes multiple NEW_CHAT_MESSAGE for the same group', async () => {
let user = new User();
await user.save();
await user.update({
await user.updateOne({
$set: {
notifications: [
{

View File

@@ -87,7 +87,7 @@ describe('DELETE /challenges/:challengeId', () => {
const testTask = _.find(tasks, task => task.text === taskText);
expect(testTask.challenge.broken).to.eql('CHALLENGE_DELETED');
expect(testTask.challenge.winner).to.be.null;
expect(testTask.challenge.winner).to.be.undefined;
});
});
});

View File

@@ -16,60 +16,7 @@ describe('GET /challenges/:challengeId', () => {
});
});
context('public guild', () => {
let groupLeader;
let group;
let challenge;
let user;
beforeEach(async () => {
user = await generateUser();
const populatedGroup = await createAndPopulateGroup({
groupDetails: { type: 'guild', privacy: 'public' },
});
groupLeader = populatedGroup.groupLeader;
group = populatedGroup.group;
challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
});
it('should return challenge data', async () => {
await challenge.sync();
const chal = await user.get(`/challenges/${challenge._id}`);
expect(chal.memberCount).to.equal(challenge.memberCount);
expect(chal.name).to.equal(challenge.name);
expect(chal._id).to.equal(challenge._id);
expect(chal.leader).to.eql({
_id: groupLeader._id,
id: groupLeader._id,
profile: { name: groupLeader.profile.name },
auth: {
local: {
username: groupLeader.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
expect(chal.group).to.eql({
_id: group._id,
categories: [],
id: group.id,
name: group.name,
summary: group.name,
type: group.type,
privacy: group.privacy,
leader: groupLeader.id,
});
});
});
context('private guild', () => {
context('Group Plan', () => {
let groupLeader;
let challengeLeader;
let group;
@@ -84,14 +31,14 @@ describe('GET /challenges/:challengeId', () => {
const populatedGroup = await createAndPopulateGroup({
groupDetails: { type: 'guild', privacy: 'private' },
members: 2,
upgradeToGroupPlan: true,
});
groupLeader = populatedGroup.groupLeader;
group = populatedGroup.group;
members = populatedGroup.members;
challengeLeader = members[0]; // eslint-disable-line prefer-destructuring
otherMember = members[1]; // eslint-disable-line prefer-destructuring
[challengeLeader, otherMember] = members;
challenge = await generateChallenge(challengeLeader, group);
});

View File

@@ -74,7 +74,7 @@ describe('GET /challenges/:challengeId/export/csv', () => {
});
it('should successfully return when it contains erroneous residue user data', async () => {
await members[0].update({ challenges: [] });
await members[0].updateOne({ challenges: [] });
const res = await members[1].get(`/challenges/${challenge._id}/export/csv`);
const sortedMembers = _.sortBy([members[1], members[2], groupLeader], '_id');
const splitRes = res.split('\n');

View File

@@ -71,42 +71,18 @@ describe('GET /challenges/:challengeId/members', () => {
});
});
it('works with challenges belonging to public guild', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const challenge = await generateChallenge(leader, group);
await leader.post(`/challenges/${challenge._id}/join`);
const res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({
_id: leader._id,
id: leader._id,
profile: { name: leader.profile.name },
auth: {
local: {
username: leader.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
expect(res[0]).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
expect(res[0].profile).to.have.all.keys(['name']);
});
it('populates only some fields', async () => {
const anotherUser = await generateUser({ balance: 3 });
const group = await generateGroup(anotherUser, { type: 'guild', privacy: 'public', name: generateUUID() });
const challenge = await generateChallenge(anotherUser, group);
await anotherUser.post(`/challenges/${challenge._id}/join`);
const group = await generateGroup(user, { type: 'party', privacy: 'private', name: generateUUID() });
const challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
const res = await user.get(`/challenges/${challenge._id}/members`);
expect(res[0]).to.eql({
_id: anotherUser._id,
id: anotherUser._id,
profile: { name: anotherUser.profile.name },
_id: user._id,
id: user._id,
profile: { name: user.profile.name },
auth: {
local: {
username: anotherUser.auth.local.username,
username: user.auth.local.username,
},
},
flags: {

View File

@@ -72,20 +72,6 @@ describe('GET /challenges/:challengeId/members/:memberId', () => {
});
});
it('works with challenges belonging to a public guild', async () => {
const groupLeader = await generateUser({ balance: 4 });
const group = await generateGroup(groupLeader, { type: 'guild', privacy: 'public', name: generateUUID() });
const challenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${challenge._id}/join`);
const taskText = 'Test Text';
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [{ type: 'habit', text: taskText }]);
const memberProgress = await user.get(`/challenges/${challenge._id}/members/${groupLeader._id}`);
expect(memberProgress).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile', 'tasks']);
expect(memberProgress.profile).to.have.all.keys(['name']);
expect(memberProgress.tasks.length).to.equal(1);
});
it('returns the member tasks for the challenges', async () => {
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
const challenge = await generateChallenge(user, group);

View File

@@ -7,117 +7,7 @@ import {
import { TAVERN_ID } from '../../../../../website/common/script/constants';
describe('GET challenges/groups/:groupId', () => {
context('Public Guild', () => {
let publicGuild; let user; let nonMember; let challenge; let
challenge2;
before(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestGuild',
type: 'guild',
privacy: 'public',
},
});
publicGuild = group;
user = groupLeader;
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
await user.post(`/challenges/${challenge._id}/join`);
challenge2 = await generateChallenge(user, group);
await user.post(`/challenges/${challenge2._id}/join`);
});
it('should return group challenges for non member with populated leader', async () => {
const challenges = await nonMember.get(`/challenges/groups/${publicGuild._id}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
expect(foundChallenge1.leader).to.eql({
_id: publicGuild.leader._id,
id: publicGuild.leader._id,
profile: { name: user.profile.name },
auth: {
local: {
username: user.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.exist;
expect(foundChallenge2.leader).to.eql({
_id: publicGuild.leader._id,
id: publicGuild.leader._id,
profile: { name: user.profile.name },
auth: {
local: {
username: user.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
});
it('should return group challenges for member with populated leader', async () => {
const challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.exist;
expect(foundChallenge1.leader).to.eql({
_id: publicGuild.leader._id,
id: publicGuild.leader._id,
profile: { name: user.profile.name },
auth: {
local: {
username: user.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.exist;
expect(foundChallenge2.leader).to.eql({
_id: publicGuild.leader._id,
id: publicGuild.leader._id,
profile: { name: user.profile.name },
auth: {
local: {
username: user.auth.local.username,
},
},
flags: {
verifiedUsername: true,
},
});
});
it('should return newest challenges first', async () => {
let challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
let foundChallengeIndex = _.findIndex(challenges, { _id: challenge2._id });
expect(foundChallengeIndex).to.eql(0);
const newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
foundChallengeIndex = _.findIndex(challenges, { _id: newChallenge._id });
expect(foundChallengeIndex).to.eql(0);
});
});
context('Private Guild', () => {
context('Group Plan', () => {
let privateGuild; let user; let nonMember; let challenge; let
challenge2;
@@ -128,6 +18,7 @@ describe('GET challenges/groups/:groupId', () => {
type: 'guild',
privacy: 'private',
},
upgradeToGroupPlan: true,
});
privateGuild = group;
@@ -186,68 +77,6 @@ describe('GET challenges/groups/:groupId', () => {
});
});
context('official challenge is present', () => {
let publicGuild; let user; let officialChallenge; let unofficialChallenges;
before(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestGuild',
type: 'guild',
privacy: 'public',
},
});
user = groupLeader;
publicGuild = group;
await user.update({
'permissions.challengeAdmin': true,
});
officialChallenge = await generateChallenge(user, group, {
categories: [{
name: 'habitica_official',
slug: 'habitica_official',
}],
});
await user.post(`/challenges/${officialChallenge._id}/join`);
// We add 10 extra challenges to test whether the official challenge
// (the oldest) makes it to the front page.
unofficialChallenges = [];
for (let i = 0; i < 10; i += 1) {
const challenge = await generateChallenge(user, group); // eslint-disable-line
await user.post(`/challenges/${challenge._id}/join`); // eslint-disable-line
unofficialChallenges.push(challenge);
}
});
it('should return official challenges first', async () => {
const challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
const foundChallengeIndex = _.findIndex(challenges, { _id: officialChallenge._id });
expect(foundChallengeIndex).to.eql(0);
});
it('should return newest challenges first, after official ones', async () => {
let challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
unofficialChallenges.forEach((chal, index) => {
const foundChallengeIndex = _.findIndex(challenges, { _id: chal._id });
expect(foundChallengeIndex).to.eql(10 - index);
});
const newChallenge = await generateChallenge(user, publicGuild);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get(`/challenges/groups/${publicGuild._id}`);
const foundChallengeIndex = _.findIndex(challenges, { _id: newChallenge._id });
expect(foundChallengeIndex).to.eql(1);
});
});
context('Party', () => {
let party; let user; let nonMember; let challenge; let
challenge2;
@@ -357,7 +186,7 @@ describe('GET challenges/groups/:groupId', () => {
before(async () => {
user = await generateUser();
await user.update({ balance: 0.5 });
await user.updateOne({ balance: 0.5 });
tavern = await user.get(`/groups/${TAVERN_ID}`);
challenge = await generateChallenge(user, tavern, { prize: 1 });
@@ -401,7 +230,7 @@ describe('GET challenges/groups/:groupId', () => {
});
});
it('should return tavern challenges using ID "habitrpg', async () => {
it('should return tavern challenges using ID "habitrpg"', async () => {
const challenges = await user.get('/challenges/groups/habitrpg');
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
@@ -435,5 +264,58 @@ describe('GET challenges/groups/:groupId', () => {
},
});
});
context('official challenge is present', () => {
let officialChallenge; let unofficialChallenges;
before(async () => {
await user.updateOne({
'permissions.challengeAdmin': true,
balance: 3,
});
officialChallenge = await generateChallenge(user, tavern, {
categories: [{
name: 'habitica_official',
slug: 'habitica_official',
}],
prize: 1,
});
await user.post(`/challenges/${officialChallenge._id}/join`);
// We add 10 extra challenges to test whether the official challenge
// (the oldest) makes it to the front page.
unofficialChallenges = [];
for (let i = 0; i < 10; i += 1) {
const challenge = await generateChallenge(user, tavern, { prize: 1 }); // eslint-disable-line
await user.post(`/challenges/${challenge._id}/join`); // eslint-disable-line
unofficialChallenges.push(challenge);
}
});
it('should return official challenges first', async () => {
const challenges = await user.get('/challenges/groups/habitrpg');
const foundChallengeIndex = _.findIndex(challenges, { _id: officialChallenge._id });
expect(foundChallengeIndex).to.eql(0);
});
it('should return newest challenges first, after official ones', async () => {
let challenges = await user.get('/challenges/groups/habitrpg');
unofficialChallenges.forEach((chal, index) => {
const foundChallengeIndex = _.findIndex(challenges, { _id: chal._id });
expect(foundChallengeIndex).to.eql(10 - index);
});
const newChallenge = await generateChallenge(user, tavern, { prize: 1 });
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/groups/habitrpg');
const foundChallengeIndex = _.findIndex(challenges, { _id: newChallenge._id });
expect(foundChallengeIndex).to.eql(1);
});
});
});
});

View File

@@ -2,39 +2,44 @@ import {
generateUser,
generateChallenge,
createAndPopulateGroup,
resetHabiticaDB,
} from '../../../../helpers/api-integration/v3';
import { TAVERN_ID } from '../../../../../website/common/script/constants';
describe('GET challenges/user', () => {
context('no official challenges', () => {
let user; let member; let nonMember; let challenge; let challenge2;
let publicGuild; let userData; let groupData;
let user; let member; let nonMember; let challenge; let challenge2; let publicChallenge;
let groupPlan; let userData; let groupData; let tavern; let tavernData;
before(async () => {
await resetHabiticaDB();
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
name: 'TestGuild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
members: 1,
upgradeToGroupPlan: true,
});
publicGuild = group;
groupPlan = group;
groupData = {
_id: publicGuild._id,
_id: groupPlan._id,
categories: [],
id: publicGuild._id,
type: publicGuild.type,
privacy: publicGuild.privacy,
name: publicGuild.name,
summary: publicGuild.name,
leader: publicGuild.leader._id,
id: groupPlan._id,
type: groupPlan.type,
privacy: groupPlan.privacy,
name: groupPlan.name,
summary: groupPlan.name,
leader: groupPlan.leader._id,
};
user = groupLeader;
userData = {
_id: publicGuild.leader._id,
id: publicGuild.leader._id,
_id: groupPlan.leader._id,
id: groupPlan.leader._id,
profile: { name: user.profile.name },
auth: {
local: {
@@ -46,17 +51,31 @@ describe('GET challenges/user', () => {
},
};
tavern = await user.get(`/groups/${TAVERN_ID}`);
tavernData = {
_id: TAVERN_ID,
categories: [],
id: TAVERN_ID,
type: tavern.type,
privacy: tavern.privacy,
name: tavern.name,
summary: tavern.name,
leader: tavern.leader._id,
};
member = members[0]; // eslint-disable-line prefer-destructuring
nonMember = await generateUser();
challenge = await generateChallenge(user, group);
challenge2 = await generateChallenge(user, group);
await user.updateOne({ balance: 0.25 });
publicChallenge = await generateChallenge(user, tavern, { prize: 1 });
await nonMember.post(`/challenges/${challenge._id}/join`);
await member.post(`/challenges/${challenge._id}/join`);
});
context('all challenges', () => {
it('should return challenges user has joined', async () => {
const challenges = await nonMember.get('/challenges/user?page=0');
const challenges = await member.get('/challenges/user?page=0');
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.exist;
@@ -64,11 +83,13 @@ describe('GET challenges/user', () => {
expect(foundChallenge.group).to.eql(groupData);
});
it('should not return challenges a non-member has not joined', async () => {
it('should return public challenges', async () => {
const challenges = await nonMember.get('/challenges/user?page=0');
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.not.exist;
const foundPublicChallenge = _.find(challenges, { _id: publicChallenge._id });
expect(foundPublicChallenge).to.exist;
expect(foundPublicChallenge.leader).to.eql(userData);
expect(foundPublicChallenge.group).to.eql(tavernData);
});
it('should return challenges user has created', async () => {
@@ -100,10 +121,10 @@ describe('GET challenges/user', () => {
it('should return newest challenges first', async () => {
let challenges = await user.get('/challenges/user?page=0');
let foundChallengeIndex = _.findIndex(challenges, { _id: challenge2._id });
let foundChallengeIndex = _.findIndex(challenges, { _id: publicChallenge._id });
expect(foundChallengeIndex).to.eql(0);
const newChallenge = await generateChallenge(user, publicGuild);
const newChallenge = await generateChallenge(user, groupPlan);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user?page=0');
@@ -113,52 +134,23 @@ describe('GET challenges/user', () => {
});
it('should not return challenges user doesn\'t have access to', async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestPrivateGuild',
summary: 'summary for TestPrivateGuild',
type: 'guild',
privacy: 'private',
},
});
const privateChallenge = await generateChallenge(groupLeader, group);
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
const challenges = await nonMember.get('/challenges/user?page=0');
const foundChallenge = _.find(challenges, { _id: privateChallenge._id });
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.not.exist;
});
it('should not return challenges user doesn\'t have access to, even with query parameters', async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestPrivateGuild',
summary: 'summary for TestPrivateGuild',
type: 'guild',
privacy: 'private',
},
});
const privateChallenge = await generateChallenge(groupLeader, group, {
categories: [{
name: 'academics',
slug: 'academics',
}],
});
await groupLeader.post(`/challenges/${privateChallenge._id}/join`);
const challenges = await nonMember.get('/challenges/user?page=0&categories=academics&owned=not_owned');
const foundChallenge = _.find(challenges, { _id: privateChallenge._id });
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.not.exist;
});
});
context('my challenges', () => {
it('should return challenges user has joined', async () => {
const challenges = await nonMember.get(`/challenges/user?page=0&member=${true}`);
const challenges = await member.get(`/challenges/user?page=0&member=${true}`);
const foundChallenge = _.find(challenges, { _id: challenge._id });
expect(foundChallenge).to.exist;
@@ -177,6 +169,10 @@ describe('GET challenges/user', () => {
expect(foundChallenge2).to.exist;
expect(foundChallenge2.leader).to.eql(userData);
expect(foundChallenge2.group).to.eql(groupData);
const foundPublicChallenge = _.find(challenges, { _id: publicChallenge._id });
expect(foundPublicChallenge).to.exist;
expect(foundPublicChallenge.leader).to.eql(userData);
expect(foundPublicChallenge.group).to.eql(tavernData);
});
it('should return challenges user has created if filter by owned', async () => {
@@ -190,6 +186,10 @@ describe('GET challenges/user', () => {
expect(foundChallenge2).to.exist;
expect(foundChallenge2.leader).to.eql(userData);
expect(foundChallenge2.group).to.eql(groupData);
const foundPublicChallenge = _.find(challenges, { _id: publicChallenge._id });
expect(foundPublicChallenge).to.exist;
expect(foundPublicChallenge.leader).to.eql(userData);
expect(foundPublicChallenge.group).to.eql(tavernData);
});
it('should not return challenges user has created if filter by not owned', async () => {
@@ -199,38 +199,42 @@ describe('GET challenges/user', () => {
expect(foundChallenge1).to.not.exist;
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.not.exist;
const foundPublicChallenge = _.find(challenges, { _id: publicChallenge._id });
expect(foundPublicChallenge).to.not.exist;
});
it('should not return challenges in user groups', async () => {
const challenges = await member.get(`/challenges/user?page=0&member=${true}`);
const foundChallenge1 = _.find(challenges, { _id: challenge._id });
expect(foundChallenge1).to.not.exist;
const foundChallenge2 = _.find(challenges, { _id: challenge2._id });
expect(foundChallenge2).to.not.exist;
});
it('should not return public challenges', async () => {
const challenges = await member.get(`/challenges/user?page=0&member=${true}`);
const foundPublicChallenge = _.find(challenges, { _id: publicChallenge._id });
expect(foundPublicChallenge).to.not.exist;
});
});
});
context('official challenge is present', () => {
let user; let officialChallenge; let unofficialChallenges; let
publicGuild;
group;
before(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
({ group, groupLeader: user } = await createAndPopulateGroup({
groupDetails: {
name: 'TestGuild',
summary: 'summary for TestGuild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
});
upgradeToGroupPlan: true,
}));
user = groupLeader;
publicGuild = group;
await user.update({
await user.updateOne({
'permissions.challengeAdmin': true,
});
@@ -271,7 +275,7 @@ describe('GET challenges/user', () => {
}
});
const newChallenge = await generateChallenge(user, publicGuild);
const newChallenge = await generateChallenge(user, group);
await user.post(`/challenges/${newChallenge._id}/join`);
challenges = await user.get('/challenges/user?page=0');
@@ -294,16 +298,17 @@ describe('GET challenges/user', () => {
groupDetails: {
name: 'TestGuild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
members: 1,
upgradeToGroupPlan: true,
});
user = groupLeader;
guild = group;
member = members[0]; // eslint-disable-line prefer-destructuring
await user.update({ balance: 20 });
await user.updateOne({ balance: 20 });
for (let i = 0; i < 11; i += 1) {
let challenge = await generateChallenge(user, group); // eslint-disable-line

View File

@@ -0,0 +1,62 @@
import { v4 as generateUUID } from 'uuid';
import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /challenges/:challengeId/flag', () => {
let user;
let challenge;
beforeEach(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'TestParty',
type: 'party',
privacy: 'private',
},
members: 1,
});
user = groupLeader;
challenge = await generateChallenge(user, group);
});
it('returns an error when challenge is not found', async () => {
await expect(user.post(`/challenges/${generateUUID()}/flag`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});
it('flags a challenge', async () => {
const flagResult = await user.post(`/challenges/${challenge._id}/flag`);
expect(flagResult.challenge.flags[user._id]).to.equal(true);
expect(flagResult.challenge.flagCount).to.equal(1);
});
it('flags a challenge with a higher count when from an admin', async () => {
await user.updateOne({ 'contributor.admin': true });
const flagResult = await user.post(`/challenges/${challenge._id}/flag`);
expect(flagResult.challenge.flags[user._id]).to.equal(true);
expect(flagResult.challenge.flagCount).to.equal(5);
});
it('returns an error when user tries to flag a challenge that is already flagged', async () => {
await user.post(`/challenges/${challenge._id}/flag`);
await expect(user.post(`/challenges/${challenge._id}/flag`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('messageChallengeFlagAlreadyReported'),
});
});
});

View File

@@ -0,0 +1,58 @@
import { v4 as generateUUID } from 'uuid';
import {
generateChallenge,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /challenges/:challengeId/clearflags', () => {
let admin;
let nonAdmin;
let challenge;
beforeEach(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
name: 'TestParty',
type: 'party',
privacy: 'private',
},
members: 1,
});
admin = groupLeader;
[nonAdmin] = members;
await admin.updateOne({ 'permissions.moderator': true });
challenge = await generateChallenge(admin, group);
await admin.post(`/challenges/${challenge._id}/flag`);
});
it('returns error when non-admin attempts to clear flags', async () => {
await expect(nonAdmin.post(`/challenges/${generateUUID()}/clearflags`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageGroupChatAdminClearFlagCount'),
});
});
it('returns an error when challenge is not found', async () => {
await expect(admin.post(`/challenges/${generateUUID()}/clearflags`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('challengeNotFound'),
});
});
it('clears flags and sets mod flag to false', async () => {
await nonAdmin.post(`/challenges/${challenge._id}/flag`);
const flagResult = await admin.post(`/challenges/${challenge._id}/clearflags`);
expect(flagResult.challenge.flagCount).to.eql(0);
expect(flagResult.challenge.flags).to.have.property(admin._id, false);
expect(flagResult.challenge.flags).to.have.property(nonAdmin._id, true);
});
});

View File

@@ -42,26 +42,7 @@ describe('POST /challenges', () => {
});
});
it('returns error when creating a challenge in a public guild and you are not a member of it', async () => {
const user = await generateUser();
const { group } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'public',
},
});
await expect(user.post('/challenges', {
group: group._id,
prize: 4,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('mustBeGroupMember'),
});
});
it('return error when creating a challenge with summary with greater than MAX_SUMMARY_SIZE_FOR_CHALLENGES characters', async () => {
it('returns error when creating a challenge with summary with greater than MAX_SUMMARY_SIZE_FOR_CHALLENGES characters', async () => {
const user = await generateUser();
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_CHALLENGES + 1);
const group = createAndPopulateGroup({
@@ -77,7 +58,7 @@ describe('POST /challenges', () => {
});
});
context('Creating a challenge for a valid group', () => {
context('creating a Challenge for a Group Plan', () => {
let groupLeader;
let group;
let groupMember;
@@ -94,9 +75,11 @@ describe('POST /challenges', () => {
challenges: true,
},
},
upgradeToGroupPlan: true,
});
groupLeader = await populatedGroup.groupLeader.sync();
await groupLeader.updateOne({ permissions: {} });
group = populatedGroup.group;
groupMember = populatedGroup.members[0]; // eslint-disable-line prefer-destructuring
});
@@ -194,7 +177,7 @@ describe('POST /challenges', () => {
const oldUserBalance = groupLeader.balance;
const prize = 8;
await group.update({ balance: 0 });
await group.updateOne({ balance: 0 });
await groupLeader.post('/challenges', {
group: group._id,
name: 'Test Challenge',
@@ -219,7 +202,7 @@ describe('POST /challenges', () => {
});
it('sets challenge as official if created by admin and official flag is set', async () => {
await groupLeader.update({
await groupLeader.updateOne({
permissions: {
challengeAdmin: true,
},

View File

@@ -128,10 +128,10 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
const oldBalance = winningUser.balance;
const oldLeaderBalance = (await groupLeader.sync()).balance;
await winningUser.update({
await winningUser.updateOne({
'purchased.plan.customerId': 'group-plan',
});
await group.update({
await group.updateOne({
'leaderOnly.getGems': true,
'purchased.plan.customerId': 123,
});

View File

@@ -18,6 +18,7 @@ describe('PUT /challenges/:challengeId', () => {
privacy: 'private',
},
members: 1,
upgradeToGroupPlan: true,
});
privateGuild = group;

View File

@@ -1,7 +1,6 @@
import { v4 as generateUUID } from 'uuid';
import {
createAndPopulateGroup,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
@@ -10,27 +9,30 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
admin;
before(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'public',
privacy: 'private',
},
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
members: 2,
upgradeToGroupPlan: true,
});
groupWithChat = group;
user = groupLeader;
message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: 'Some message' });
message = message.message;
userThatDidNotCreateChat = await generateUser();
admin = await generateUser({ 'permissions.moderator': true });
userThatDidNotCreateChat = members[0]; // eslint-disable-line prefer-destructuring
admin = members[1]; // eslint-disable-line prefer-destructuring
await admin.updateOne({ permissions: { moderator: true } });
});
context('Chat errors', () => {
it('returns an error is message does not exist', async () => {
it('returns an error if message does not exist', async () => {
const fakeChatId = generateUUID();
await expect(user.del(`/groups/${groupWithChat._id}/chat/${fakeChatId}`)).to.eventually.be.rejected.and.eql({
code: 404,
@@ -56,7 +58,7 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
nextMessage = nextMessage.message;
});
it('allows creator to delete a their message', async () => {
it('allows creator to delete their message', async () => {
await user.del(`/groups/${groupWithChat._id}/chat/${nextMessage.id}`);
const returnedMessages = await user.get(`/groups/${groupWithChat._id}/chat/`);

View File

@@ -1,6 +1,6 @@
import {
generateUser,
generateGroup,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
@@ -11,48 +11,22 @@ describe('GET /groups/:groupId/chat', () => {
user = await generateUser();
});
context('public Guild', () => {
let group;
before(async () => {
const leader = await generateUser({ balance: 2 });
group = await generateGroup(leader, {
name: 'test group',
type: 'guild',
privacy: 'public',
}, {
chat: [
{ text: 'Hello', flags: {}, id: 1 },
{ text: 'Welcome to the Guild', flags: {}, id: 2 },
],
});
});
it('returns Guild chat', async () => {
const chat = await user.get(`/groups/${group._id}/chat`);
expect(chat[0].id).to.eql(group.chat[0].id);
expect(chat[1].id).to.eql(group.chat[1].id);
});
});
context('private Guild', () => {
let group;
before(async () => {
const leader = await generateUser({ balance: 2 });
group = await generateGroup(leader, {
name: 'test group',
type: 'guild',
privacy: 'private',
}, {
({ group } = await createAndPopulateGroup({
groupDetails: {
name: 'test group',
type: 'guild',
privacy: 'private',
},
members: 1,
upgradeToGroupPlan: true,
chat: [
'Hello',
'Welcome to the Guild',
],
});
}));
});
it('returns error if user is not member of requested private group', async () => {

View File

@@ -1,32 +1,42 @@
import { find } from 'lodash';
import find from 'lodash/find';
import moment from 'moment';
import nconf from 'nconf';
import { IncomingWebhook } from '@slack/webhook';
import {
generateUser,
createAndPopulateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
const BASE_URL = nconf.get('BASE_URL');
describe('POST /chat/:chatId/flag', () => {
let user; let admin; let anotherUser; let newUser; let
group;
group; let members; let userToDelete;
const TEST_MESSAGE = 'Test Message';
const USER_AGE_FOR_FLAGGING = 3;
beforeEach(async () => {
user = await generateUser({ balance: 1, 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
admin = await generateUser({ balance: 1, 'permissions.moderator': 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').returns(Promise.resolve());
({ group, groupLeader: user, members } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'private',
},
leaderDetails: {
'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate(),
},
members: 4,
upgradeToGroupPlan: true,
}));
group = await user.post('/groups', {
name: 'Test Guild',
type: 'guild',
privacy: 'public',
[admin, anotherUser, newUser, userToDelete] = members;
await user.updateOne({ permissions: {} });
await admin.updateOne({ permissions: { moderator: true } });
await anotherUser.updateOne({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
await newUser.updateOne({ 'auth.timestamps.created': moment().subtract(1, 'days').toDate() });
await userToDelete.updateOne({
'auth.timestamps.created': moment().subtract(1, 'days').toDate(),
'purchased.plan.dateTerminated': moment().subtract(1, 'minutes').toDate(),
});
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
});
afterEach(() => {
@@ -69,8 +79,8 @@ describe('POST /chat/:chatId/flag', () => {
fallback: 'Flag Message',
color: 'danger',
author_name: `@${anotherUser.auth.local.username} ${anotherUser.profile.name} (${anotherUser.auth.local.email}; ${anotherUser._id})\n${timestamp}`,
title: 'Flag in Test Guild',
title_link: `${BASE_URL}/groups/guild/${group._id}`,
title: 'Flag in Test Guild - (private guild)',
title_link: undefined,
text: TEST_MESSAGE,
footer: `<https://habitrpg.github.io/flag-o-rama/?groupId=${group._id}&chatId=${message.id}|Flag this message.>`,
mrkdwn_in: [
@@ -78,7 +88,7 @@ describe('POST /chat/:chatId/flag', () => {
],
}],
});
/* eslint-ensable camelcase */
/* eslint-enable camelcase */
});
it('Does not increment message flag count and sends different message to moderator Slack when user is new', async () => {
@@ -104,8 +114,8 @@ describe('POST /chat/:chatId/flag', () => {
fallback: 'Flag Message',
color: 'danger',
author_name: `@${newUser.auth.local.username} ${newUser.profile.name} (${newUser.auth.local.email}; ${newUser._id})\n${timestamp}`,
title: 'Flag in Test Guild',
title_link: `${BASE_URL}/groups/guild/${group._id}`,
title: 'Flag in Test Guild - (private guild)',
title_link: undefined,
text: TEST_MESSAGE,
footer: `<https://habitrpg.github.io/flag-o-rama/?groupId=${group._id}&chatId=${message.id}|Flag this message.> ${automatedComment}`,
mrkdwn_in: [
@@ -113,15 +123,12 @@ describe('POST /chat/:chatId/flag', () => {
],
}],
});
/* eslint-ensable camelcase */
/* eslint-enable camelcase */
});
it('Flags a chat when the author\'s account was deleted', async () => {
const deletedUser = await generateUser({
'auth.timestamps.created': new Date('2022-01-01'),
});
const { message } = await deletedUser.post(`/groups/${group._id}/chat`, { message: TEST_MESSAGE });
await deletedUser.del('/user', {
const { message } = await userToDelete.post(`/groups/${group._id}/chat`, { message: TEST_MESSAGE });
await userToDelete.del('/user', {
password: 'password',
});

View File

@@ -6,28 +6,28 @@ import {
describe('POST /chat/:chatId/like', () => {
let user;
let groupWithChat;
const testMessage = 'Test Message';
let anotherUser;
let groupWithChat;
let members;
const testMessage = 'Test Message';
before(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
({ group: groupWithChat, groupLeader: user, members } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
upgradeToGroupPlan: true,
}));
user = groupLeader;
groupWithChat = group;
anotherUser = members[0]; // eslint-disable-line prefer-destructuring
await anotherUser.update({ 'auth.timestamps.created': new Date('2022-01-01') });
[anotherUser] = members;
await anotherUser.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('Returns an error when chat message is not found', async () => {
@@ -39,17 +39,6 @@ describe('POST /chat/:chatId/like', () => {
});
});
it('Returns an error when user tries to like their own message', async () => {
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
await expect(user.post(`/groups/${groupWithChat._id}/chat/${message.message.id}/like`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('messageGroupChatLikeOwnMessage'),
});
});
it('Likes a chat', async () => {
const message = await anotherUser.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
@@ -63,6 +52,19 @@ describe('POST /chat/:chatId/like', () => {
expect(messageToCheck.likes[user._id]).to.equal(true);
});
it('Allows to likes their own chat message', async () => {
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const likeResult = await user.post(`/groups/${groupWithChat._id}/chat/${message.message.id}/like`);
expect(likeResult.likes[user._id]).to.equal(true);
const groupWithChatLikes = await user.get(`/groups/${groupWithChat._id}`);
const messageToCheck = find(groupWithChatLikes.chat, { id: message.message.id });
expect(messageToCheck.likes[user._id]).to.equal(true);
});
it('Unlikes a chat', async () => {
const message = await anotherUser.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });

View File

@@ -1,52 +1,43 @@
import { IncomingWebhook } from '@slack/webhook';
import nconf from 'nconf';
import { v4 as generateUUID } from 'uuid';
import {
createAndPopulateGroup,
generateUser,
translate as t,
sleep,
server,
} from '../../../../helpers/api-integration/v3';
import {
SPAM_MESSAGE_LIMIT,
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
TAVERN_ID,
} from '../../../../../website/server/models/group';
import { CHAT_FLAG_FROM_SHADOW_MUTE, MAX_MESSAGE_LENGTH } from '../../../../../website/common/script/constants';
import { MAX_MESSAGE_LENGTH } from '../../../../../website/common/script/constants';
import * as email from '../../../../../website/server/libs/email';
const BASE_URL = nconf.get('BASE_URL');
describe('POST /chat', () => {
let user; let groupWithChat; let member; let
additionalMember;
const testMessage = 'Test Message';
const testBannedWordMessage = 'TESTPLACEHOLDERSWEARWORDHERE';
const testBannedWordMessage1 = 'TESTPLACEHOLDERSWEARWORDHERE1';
const testSlurMessage = 'message with TESTPLACEHOLDERSLURWORDHERE';
const testSlurMessage1 = 'TESTPLACEHOLDERSLURWORDHERE1';
const bannedWordErrorMessage = t('bannedWordUsed', { swearWordsUsed: testBannedWordMessage });
before(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
members: 2,
upgradeToGroupPlan: true,
});
user = groupLeader;
await user.update({
await user.updateOne({
'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
'auth.timestamps.created': new Date('2022-01-01'),
}); // prevent tests accidentally throwing messageGroupChatSpam
groupWithChat = group;
member = members[0]; // eslint-disable-line prefer-destructuring
additionalMember = members[1]; // eslint-disable-line prefer-destructuring
await member.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await additionalMember.update({ 'auth.timestamps.created': new Date('2022-01-01') });
[member, additionalMember] = members;
await member.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
await additionalMember.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('Returns an error when no message is provided', async () => {
@@ -86,35 +77,15 @@ describe('POST /chat', () => {
describe('mute user', () => {
afterEach(() => {
member.update({ 'flags.chatRevoked': false });
});
it('returns an error when chat privileges are revoked when sending a message to a public guild', async () => {
const userWithChatRevoked = await member.update({ 'flags.chatRevoked': true });
await expect(userWithChatRevoked.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage })).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('chatPrivilegesRevoked'),
});
member.updateOne({ 'flags.chatRevoked': false });
});
it('does not error when chat privileges are revoked when sending a message to a private guild', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
name: 'Private Guild',
type: 'guild',
privacy: 'private',
},
members: 1,
});
const privateGuildMemberWithChatsRevoked = members[0];
await privateGuildMemberWithChatsRevoked.update({
await member.updateOne({
'flags.chatRevoked': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await privateGuildMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
});
@@ -130,7 +101,7 @@ describe('POST /chat', () => {
});
const privatePartyMemberWithChatsRevoked = members[0];
await privatePartyMemberWithChatsRevoked.update({
await privatePartyMemberWithChatsRevoked.updateOne({
'flags.chatRevoked': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
@@ -149,57 +120,15 @@ describe('POST /chat', () => {
afterEach(() => {
sandbox.restore();
member.update({ 'flags.chatShadowMuted': false });
});
it('creates a chat with flagCount already set and notifies mods when sending a message to a public guild', async () => {
const userWithChatShadowMuted = await member.update({ 'flags.chatShadowMuted': true });
const message = await userWithChatShadowMuted.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
// Email sent to mods
await sleep(0.5);
expect(email.sendTxn).to.be.calledOnce;
expect(email.sendTxn.args[0][1]).to.eql('shadow-muted-post-report-to-mods');
// Slack message to mods
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
/* eslint-disable camelcase */
expect(IncomingWebhook.prototype.send).to.be.calledWith({
text: `@${member.auth.local.username} / ${member.profile.name} posted while shadow-muted`,
attachments: [{
fallback: 'Shadow-Muted Message',
color: 'danger',
author_name: `@${member.auth.local.username} ${member.profile.name} (${member.auth.local.email}; ${member._id})`,
title: 'Shadow-Muted Post in Test Guild',
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
text: testMessage,
mrkdwn_in: [
'text',
],
}],
});
/* eslint-enable camelcase */
member.updateOne({ 'flags.chatShadowMuted': false });
});
it('creates a chat with zero flagCount when sending a message to a private guild', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
name: 'Private Guild',
type: 'guild',
privacy: 'private',
},
members: 1,
});
const userWithChatShadowMuted = members[0];
await userWithChatShadowMuted.update({
await member.updateOne({
'flags.chatShadowMuted': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.flagCount).to.eql(0);
@@ -216,7 +145,7 @@ describe('POST /chat', () => {
});
const userWithChatShadowMuted = members[0];
await userWithChatShadowMuted.update({
await userWithChatShadowMuted.updateOne({
'flags.chatShadowMuted': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
@@ -226,100 +155,9 @@ describe('POST /chat', () => {
expect(message.message.id).to.exist;
expect(message.message.flagCount).to.eql(0);
});
it('creates a chat with zero flagCount when non-shadow-muted user sends a message to a public guild', async () => {
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.flagCount).to.eql(0);
});
});
context('banned word', () => {
it('returns an error when chat message contains a banned word in tavern', async () => {
await expect(user.post('/groups/habitrpg/chat', { message: testBannedWordMessage }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: bannedWordErrorMessage,
});
});
it('returns an error when chat message contains a banned word in a public guild', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
name: 'public guild',
type: 'guild',
privacy: 'public',
},
members: 1,
});
await expect(members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: bannedWordErrorMessage,
});
});
it('errors when word is part of a phrase', async () => {
const wordInPhrase = `phrase ${testBannedWordMessage} end`;
await expect(user.post('/groups/habitrpg/chat', { message: wordInPhrase }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: bannedWordErrorMessage,
});
});
it('errors when word is surrounded by non alphabet characters', async () => {
const wordInPhrase = `_!${testBannedWordMessage}@_`;
await expect(user.post('/groups/habitrpg/chat', { message: wordInPhrase }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: bannedWordErrorMessage,
});
});
it('errors when word is typed in mixed case', async () => {
const substrLength = Math.floor(testBannedWordMessage.length / 2);
const chatMessage = testBannedWordMessage.substring(0, substrLength).toLowerCase()
+ testBannedWordMessage.substring(substrLength).toUpperCase();
await expect(user.post('/groups/habitrpg/chat', { message: chatMessage }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('bannedWordUsed', { swearWordsUsed: chatMessage }),
});
});
it('checks error message has all the banned words used, regardless of case', async () => {
const testBannedWords = [
testBannedWordMessage.toUpperCase(),
testBannedWordMessage1.toLowerCase(),
];
const chatMessage = `Mixing ${testBannedWords[0]} and ${testBannedWords[1]} is bad for you.`;
await expect(user.post('/groups/habitrpg/chat', { message: chatMessage }))
.to.eventually.be.rejected
.and.have.property('message')
.that.includes(testBannedWords.join(', '));
});
it('does not error when bad word is suffix of a word', async () => {
const wordAsSuffix = `prefix${testBannedWordMessage}`;
const message = await user.post('/groups/habitrpg/chat', { message: wordAsSuffix });
expect(message.message.id).to.exist;
});
it('does not error when bad word is prefix of a word', async () => {
const wordAsPrefix = `${testBannedWordMessage}suffix`;
const message = await user.post('/groups/habitrpg/chat', { message: wordAsPrefix });
expect(message.message.id).to.exist;
});
it('does not error when sending a chat message containing a banned word to a party', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
@@ -329,26 +167,7 @@ describe('POST /chat', () => {
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
expect(message.message.id).to.exist;
});
it('does not error when sending a chat message containing a banned word to a public guild in which banned words are allowed', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
name: 'public guild',
type: 'guild',
privacy: 'public',
},
members: 1,
});
// Update the bannedWordsAllowed property for the group
group.update({ bannedWordsAllowed: true });
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
await members[0].updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
@@ -356,17 +175,7 @@ describe('POST /chat', () => {
});
it('does not error when sending a chat message containing a banned word to a private guild', async () => {
const { group, members } = await createAndPopulateGroup({
groupDetails: {
name: 'private guild',
type: 'guild',
privacy: 'private',
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testBannedWordMessage });
expect(message.message.id).to.exist;
});
@@ -380,46 +189,7 @@ describe('POST /chat', () => {
afterEach(() => {
sandbox.restore();
user.update({ 'flags.chatRevoked': false });
});
it('errors and revokes privileges when chat message contains a banned slur', async () => {
await expect(user.post(`/groups/${groupWithChat._id}/chat`, { message: testSlurMessage })).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('bannedSlurUsed'),
});
// Email sent to mods
await sleep(0.5);
expect(email.sendTxn).to.be.calledOnce;
expect(email.sendTxn.args[0][1]).to.eql('slur-report-to-mods');
// Slack message to mods
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
/* eslint-disable camelcase */
expect(IncomingWebhook.prototype.send).to.be.calledWith({
text: `${user.profile.name} (${user.id}) tried to post a slur`,
attachments: [{
fallback: 'Slur Message',
color: 'danger',
author_name: `@${user.auth.local.username} ${user.profile.name} (${user.auth.local.email}; ${user._id})`,
title: 'Slur in Test Guild',
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
text: testSlurMessage,
mrkdwn_in: [
'text',
],
}],
});
/* eslint-enable camelcase */
// Chat privileges are revoked
await expect(user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage })).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('chatPrivilegesRevoked'),
});
user.updateOne({ 'flags.chatRevoked': false });
});
it('allows slurs in private groups', async () => {
@@ -431,34 +201,23 @@ describe('POST /chat', () => {
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
await members[0].updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testSlurMessage });
expect(message.message.id).to.exist;
});
it('errors when slur is typed in mixed case', async () => {
const substrLength = Math.floor(testSlurMessage1.length / 2);
const chatMessage = testSlurMessage1.substring(0, substrLength).toLowerCase()
+ testSlurMessage1.substring(substrLength).toUpperCase();
await expect(user.post('/groups/habitrpg/chat', { message: chatMessage }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('bannedSlurUsed'),
});
});
});
it('errors when user account is too young', async () => {
const brandNewUser = await generateUser();
await expect(brandNewUser.post('/groups/habitrpg/chat', { message: 'hi im new' }))
await user.updateOne({ 'auth.timestamps.created': new Date() });
await expect(user.post(`/groups/${groupWithChat._id}/chat`, { message: 'hi im new' }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('chatTemporarilyUnavailable'),
});
await user.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('creates a chat', async () => {
@@ -499,7 +258,7 @@ describe('POST /chat', () => {
it('chat message with mentions - mention link should not count towards 3000 chars limit', async () => {
const memberUsername = 'memberUsername';
await member.update({ 'auth.local.username': memberUsername });
await member.updateOne({ 'auth.local.username': memberUsername });
const messageWithMentions = `hi @${memberUsername} 123456789
123456789 123456789 123456789 123456789 123456789 123456789 89 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345678 END.`;
@@ -519,54 +278,42 @@ describe('POST /chat', () => {
const mount = 'test-mount';
const pet = 'test-pet';
const style = 'test-style';
const userWithStyle = await generateUser({
await user.updateOne({
'items.currentMount': mount,
'items.currentPet': pet,
'preferences.style': style,
'auth.timestamps.created': new Date('2022-01-01'),
});
await userWithStyle.sync();
const message = await userWithStyle.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.userStyles.items.currentMount).to.eql(userWithStyle.items.currentMount);
expect(message.message.userStyles.items.currentPet).to.eql(userWithStyle.items.currentPet);
expect(message.message.userStyles.preferences.style).to.eql(userWithStyle.preferences.style);
expect(message.message.userStyles.preferences.hair).to.eql(userWithStyle.preferences.hair);
expect(message.message.userStyles.preferences.skin).to.eql(userWithStyle.preferences.skin);
expect(message.message.userStyles.preferences.shirt).to.eql(userWithStyle.preferences.shirt);
expect(message.message.userStyles.preferences.chair).to.eql(userWithStyle.preferences.chair);
expect(message.message.userStyles.items.currentMount).to.eql(user.items.currentMount);
expect(message.message.userStyles.items.currentPet).to.eql(user.items.currentPet);
expect(message.message.userStyles.preferences.style).to.eql(user.preferences.style);
expect(message.message.userStyles.preferences.hair).to.eql(user.preferences.hair);
expect(message.message.userStyles.preferences.skin).to.eql(user.preferences.skin);
expect(message.message.userStyles.preferences.shirt).to.eql(user.preferences.shirt);
expect(message.message.userStyles.preferences.chair).to.eql(user.preferences.chair);
expect(message.message.userStyles.preferences.background)
.to.eql(userWithStyle.preferences.background);
.to.eql(user.preferences.background);
});
it('creates equipped to user styles', async () => {
const userWithStyle = await generateUser({
'preferences.costume': false,
'auth.timestamps.created': new Date('2022-01-01'),
});
await userWithStyle.sync();
const message = await userWithStyle.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.userStyles.items.gear.equipped)
.to.eql(userWithStyle.items.gear.equipped);
.to.eql(user.items.gear.equipped);
expect(message.message.userStyles.items.gear.costume).to.not.exist;
});
it('creates costume to user styles', async () => {
const userWithStyle = await generateUser({
'preferences.costume': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
await userWithStyle.sync();
await user.updateOne({ 'preferences.costume': true });
const message = await userWithStyle.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
expect(message.message.id).to.exist;
expect(message.message.userStyles.items.gear.costume).to.eql(userWithStyle.items.gear.costume);
expect(message.message.userStyles.items.gear.costume).to.eql(user.items.gear.costume);
expect(message.message.userStyles.items.gear.equipped).to.not.exist;
});
@@ -576,12 +323,11 @@ describe('POST /chat', () => {
tier: 800,
tokensApplied: true,
};
const backer = await generateUser({
await user.updateOne({
backer: backerInfo,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await backer.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const messageBackerInfo = message.message.backer;
expect(messageBackerInfo.npc).to.equal(backerInfo.npc);
@@ -629,7 +375,7 @@ describe('POST /chat', () => {
context('chat notifications', () => {
beforeEach(() => {
member.update({ newMessages: {}, notifications: [] });
member.updateOne({ newMessages: {}, notifications: [] });
});
it('notifies other users of new messages for a guild', async () => {
@@ -661,43 +407,5 @@ describe('POST /chat', () => {
expect(memberWithNotification.newMessages[`${group._id}`]).to.exist;
expect(memberWithNotification.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === group._id)).to.exist;
});
it('does not notify other users of a new message that is already hidden from shadow-muting', async () => {
await user.update({ 'flags.chatShadowMuted': true });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const memberWithNotification = await member.get('/user');
await user.update({ 'flags.chatShadowMuted': false });
expect(message.message.id).to.exist;
expect(memberWithNotification.newMessages[`${groupWithChat._id}`]).to.not.exist;
expect(memberWithNotification.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupWithChat._id)).to.not.exist;
});
});
context('Spam prevention', () => {
it('Returns an error when the user has been posting too many messages', async () => {
// Post as many messages are needed to reach the spam limit
for (let i = 0; i < SPAM_MESSAGE_LIMIT; i += 1) {
const result = await additionalMember.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage }); // eslint-disable-line no-await-in-loop
expect(result.message.id).to.exist;
}
await expect(additionalMember.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage })).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageGroupChatSpam'),
});
});
it('contributor should not receive spam alert', async () => {
const userSocialite = await member.update({ 'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL });
// Post 1 more message than the spam limit to ensure they do not reach the limit
for (let i = 0; i < SPAM_MESSAGE_LIMIT + 1; i += 1) {
const result = await userSocialite.post(`/groups/${TAVERN_ID}/chat`, { message: testMessage }); // eslint-disable-line no-await-in-loop
expect(result.message.id).to.exist;
}
});
});
});

View File

@@ -12,18 +12,19 @@ describe('POST /groups/:id/chat/seen', () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'public',
privacy: 'private',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
upgradeToGroupPlan: true,
});
guild = group;
guildLeader = groupLeader;
guildMember = members[0]; // eslint-disable-line prefer-destructuring
[guildMember] = members;
guildMessage = await guildLeader.post(`/groups/${guild._id}/chat`, { message: 'Some guild message' });
guildMessage = guildMessage.message;

View File

@@ -2,7 +2,6 @@ import moment from 'moment';
import { v4 as generateUUID } from 'uuid';
import {
createAndPopulateGroup,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import config from '../../../../../config.json';
@@ -13,21 +12,24 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
admin;
before(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'public',
privacy: 'private',
},
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
upgradeToGroupPlan: true,
members: 2,
});
groupWithChat = group;
author = groupLeader;
nonAdmin = await generateUser({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
admin = await generateUser({ 'permissions.moderator': true });
[nonAdmin, admin] = members;
await nonAdmin.updateOne({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
await admin.updateOne({ 'permissions.moderator': true });
message = await author.post(`/groups/${groupWithChat._id}/chat`, { message: 'Some message' });
message = message.message;
@@ -69,7 +71,7 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
members: 2,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
await members[0].updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
let privateMessage = await members[0].post(`/groups/${group._id}/chat`, { message: 'Some message' });
privateMessage = privateMessage.message;
@@ -102,7 +104,7 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
const member = members[0];
// make member that can use skills
await member.update({
await member.updateOne({
'stats.lvl': 100,
'stats.mp': 400,
'stats.class': 'wizard',

View File

@@ -24,7 +24,7 @@ describe('GET /coupons/', () => {
});
it('should return the coupons in CSV format ordered by creation date', async () => {
await user.update({
await user.updateOne({
'permissions.coupons': true,
});

View File

@@ -19,7 +19,7 @@ describe('POST /coupons/generate/:event', () => {
});
it('returns an error if user has no coupons permission', async () => {
await user.update({
await user.updateOne({
'permissions.coupons': false,
});
@@ -47,7 +47,7 @@ describe('POST /coupons/generate/:event', () => {
});
it('should generate coupons', async () => {
await user.update({
await user.updateOne({
'permissions.coupons': true,
});

View File

@@ -24,7 +24,7 @@ describe('POST /debug/quest-progress', () => {
});
it('increases boss quest progress by 1000', async () => {
await user.update({
await user.updateOne({
'party.quest.key': 'whale',
});
@@ -36,7 +36,7 @@ describe('POST /debug/quest-progress', () => {
});
it('increases collection quest progress by 300 items', async () => {
await user.update({
await user.updateOne({
'party.quest.key': 'evilsanta2',
});

View File

@@ -1,6 +1,5 @@
import {
generateUser,
generateGroup,
createAndPopulateGroup,
} from '../../../../helpers/api-integration/v3';
describe('GET /group-plans', () => {
@@ -8,20 +7,15 @@ describe('GET /group-plans', () => {
let groupPlan;
before(async () => {
user = await generateUser({ balance: 4 });
groupPlan = await generateGroup(user,
{
name: 'public guild - is member',
({ group: groupPlan, groupLeader: user } = await createAndPopulateGroup({
groupDetails: {
name: 'group plan - is member',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
{
purchased: {
plan: {
customerId: 'existings',
},
},
});
upgradeToGroupPlan: true,
leaderDetails: { balance: 4 },
}));
});
it('returns group plans for the user', async () => {

View File

@@ -1,70 +1,63 @@
import {
generateUser,
createAndPopulateGroup,
resetHabiticaDB,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
import {
TAVERN_ID,
} from '../../../../../website/server/models/group';
import apiError from '../../../../../website/server/libs/apiError';
describe('GET /groups', () => {
let user;
let userInGuild;
const NUMBER_OF_PUBLIC_GUILDS = 2;
const NUMBER_OF_PUBLIC_GUILDS_USER_IS_LEADER = 2;
const NUMBER_OF_PUBLIC_GUILDS_USER_IS_MEMBER = 1;
const NUMBER_OF_USERS_PRIVATE_GUILDS = 1;
const NUMBER_OF_GROUPS_USER_CAN_VIEW = 5;
const GUILD_PER_PAGE = 30;
let user; let leader; let members;
let secondGroup; let secondLeader;
const NUMBER_OF_USERS_PRIVATE_GUILDS = 2;
const NUMBER_OF_GROUPS_USER_CAN_VIEW = 3;
const categories = [{
slug: 'newCat',
name: 'New Category',
}];
let publicGuildNotMember;
let privateGuildUserIsMemberOf;
before(async () => {
await resetHabiticaDB();
const leader = await generateUser({ balance: 10 });
user = await generateUser({ balance: 4 });
({
group: privateGuildUserIsMemberOf,
groupLeader: leader,
members,
} = await createAndPopulateGroup({
groupDetails: {
name: 'private guild - is member',
type: 'guild',
privacy: 'private',
categories,
},
leaderDetails: {
balance: 10,
},
members: 1,
upgradeToGroupPlan: true,
}));
[user] = members;
await user.updateOne({ balance: 4 });
const publicGuildUserIsMemberOf = await generateGroup(leader, {
name: 'public guild - is member',
type: 'guild',
privacy: 'public',
summary: 'ohayou kombonwa',
description: 'oyasumi',
});
await leader.post(`/groups/${publicGuildUserIsMemberOf._id}/invite`, { uuids: [user._id] });
await user.post(`/groups/${publicGuildUserIsMemberOf._id}/join`);
({ group: secondGroup, groupLeader: secondLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'c++ coders',
type: 'guild',
privacy: 'private',
},
upgradeToGroupPlan: true,
}));
userInGuild = await generateUser({ guilds: [publicGuildUserIsMemberOf._id] });
await secondLeader.post(`/groups/${secondGroup._id}/invite`, { uuids: [user._id] });
await user.post(`/groups/${secondGroup._id}/join`);
publicGuildNotMember = await generateGroup(leader, {
name: 'public guild - is not member',
type: 'guild',
privacy: 'public',
summary: 'Natsume Soseki',
description: 'Kinnosuke no Hondana',
categories,
});
privateGuildUserIsMemberOf = await generateGroup(leader, {
name: 'private guild - is member',
type: 'guild',
privacy: 'private',
categories,
});
await leader.post(`/groups/${privateGuildUserIsMemberOf._id}/invite`, { uuids: [user._id] });
await user.post(`/groups/${privateGuildUserIsMemberOf._id}/join`);
await generateGroup(leader, {
name: 'private guild - is not member',
type: 'guild',
privacy: 'private',
await createAndPopulateGroup({
groupDetails: {
name: 'private guild - is not member',
type: 'guild',
privacy: 'private',
},
upgradeToGroupPlan: true,
});
await generateGroup(leader, {
@@ -98,172 +91,16 @@ describe('GET /groups', () => {
});
});
it('returns only the tavern when tavern passed in as query', async () => {
await expect(user.get('/groups?type=tavern'))
.to.eventually.have.a.lengthOf(1)
.and.to.have.nested.property('[0]')
.and.to.have.property('_id', TAVERN_ID);
});
it('returns only the user\'s party when party passed in as query', async () => {
await expect(user.get('/groups?type=party'))
.to.eventually.have.a.lengthOf(1)
.and.to.have.nested.property('[0]');
});
it('returns all public guilds when publicGuilds passed in as query', async () => {
await expect(user.get('/groups?type=publicGuilds'))
.to.eventually.have.a.lengthOf(NUMBER_OF_PUBLIC_GUILDS);
});
describe('filters', () => {
it('returns public guilds filtered by category', async () => {
const guilds = await user.get(`/groups?type=publicGuilds&categories=${categories[0].slug}`);
expect(guilds[0]._id).to.equal(publicGuildNotMember._id);
});
it('returns private guilds filtered by category', async () => {
const guilds = await user.get(`/groups?type=privateGuilds&categories=${categories[0].slug}`);
expect(guilds[0]._id).to.equal(privateGuildUserIsMemberOf._id);
});
it('filters public guilds by size', async () => {
await generateGroup(user, {
name: 'guild1',
type: 'guild',
privacy: 'public',
memberCount: 1,
});
// @TODO: anyway to set higher memberCount in tests right now?
const guilds = await user.get('/groups?type=publicGuilds&minMemberCount=3');
expect(guilds.length).to.equal(0);
});
it('filters private guilds by size', async () => {
await generateGroup(user, {
name: 'guild1',
type: 'guild',
privacy: 'private',
memberCount: 1,
});
// @TODO: anyway to set higher memberCount in tests right now?
const guilds = await user.get('/groups?type=privateGuilds&minMemberCount=3');
expect(guilds.length).to.equal(0);
});
it('filters public guilds by leader role', async () => {
const guilds = await user.get('/groups?type=publicGuilds&leader=true');
expect(guilds.length).to.equal(NUMBER_OF_PUBLIC_GUILDS_USER_IS_LEADER);
});
it('filters public guilds by member role', async () => {
const guilds = await userInGuild.get('/groups?type=publicGuilds&member=true');
expect(guilds.length).to.equal(1);
expect(guilds[0].name).to.have.string('is member');
});
it('filters public guilds by single-word search term', async () => {
const guilds = await user.get('/groups?type=publicGuilds&search=kom');
expect(guilds.length).to.equal(1);
expect(guilds[0].summary).to.have.string('ohayou kombonwa');
});
it('filters public guilds by single-word search term left and right-padded by spaces', async () => {
const guilds = await user.get('/groups?type=publicGuilds&search=++++ohayou+kombonwa+++++');
expect(guilds.length).to.equal(1);
expect(guilds[0].summary).to.have.string('ohayou kombonwa');
});
it('filters public guilds by two-words search term separated by multiple spaces', async () => {
const guilds = await user.get('/groups?type=publicGuilds&search=kinnosuke+++++hon');
expect(guilds.length).to.equal(1);
expect(guilds[0].description).to.have.string('Kinnosuke');
});
});
describe('public guilds pagination', () => {
it('req.query.paginate must be a boolean string', async () => {
await expect(user.get('/groups?paginate=aString&type=publicGuilds'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'Invalid request parameters.',
});
});
it('req.query.paginate can only be true when req.query.type includes publicGuilds', async () => {
await expect(user.get('/groups?paginate=true&type=notPublicGuilds'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: apiError('guildsOnlyPaginate'),
});
});
it('req.query.page can\'t be negative', async () => {
await expect(user.get('/groups?paginate=true&page=-1&type=publicGuilds'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'Invalid request parameters.',
});
});
it('returns 30 guilds per page ordered by number of members', async () => {
await user.update({ balance: 9000 });
const delay = () => new Promise(resolve => setTimeout(resolve, 40));
const promises = [];
for (let i = 0; i < 60; i += 1) {
promises.push(generateGroup(user, {
name: `public guild ${i} - is member`,
type: 'guild',
privacy: 'public',
}));
await delay(); // eslint-disable-line no-await-in-loop
}
const groups = await Promise.all(promises);
// update group number 32 and not the first to make sure sorting works
await groups[32].update({ name: 'guild with most members', memberCount: 199 });
await groups[33].update({ name: 'guild with less members', memberCount: -100 });
const page0 = await expect(user.get('/groups?type=publicGuilds&paginate=true'))
.to.eventually.have.a.lengthOf(GUILD_PER_PAGE);
expect(page0[0].name).to.equal('guild with most members');
await expect(user.get('/groups?type=publicGuilds&paginate=true&page=1'))
.to.eventually.have.a.lengthOf(GUILD_PER_PAGE);
const page2 = await expect(user.get('/groups?type=publicGuilds&paginate=true&page=2'))
// 1 created now, 4 by other tests, -1 for no more tavern.
.to.eventually.have.a.lengthOf(1 + 4 - 1);
expect(page2[3].name).to.equal('guild with less members');
}).timeout(10000);
});
it('makes sure that the tavern doesn\'t show up when guilds is passed as a query', async () => {
const guilds = await user.get('/groups?type=guilds');
expect(guilds.find(g => g.id === TAVERN_ID)).to.be.undefined;
});
it('makes sure that the tavern doesn\'t show up when publicGuilds is passed as a query', async () => {
const guilds = await user.get('/groups?type=publicGuilds');
expect(guilds.find(g => g.id === TAVERN_ID)).to.be.undefined;
});
it('returns all the user\'s guilds when guilds passed in as query', async () => {
await expect(user.get('/groups?type=guilds'))
.to.eventually.have.a
.lengthOf(NUMBER_OF_PUBLIC_GUILDS_USER_IS_MEMBER + NUMBER_OF_USERS_PRIVATE_GUILDS);
.lengthOf(NUMBER_OF_USERS_PRIVATE_GUILDS);
});
it('returns all private guilds user is a part of when privateGuilds passed in as query', async () => {
@@ -272,21 +109,21 @@ describe('GET /groups', () => {
});
it('returns a list of groups user has access to', async () => {
await expect(user.get('/groups?type=privateGuilds,publicGuilds,party,tavern'))
.to.eventually.have.lengthOf(NUMBER_OF_GROUPS_USER_CAN_VIEW - 1); // -1 for no Tavern.
await expect(user.get('/groups?type=privateGuilds,party'))
.to.eventually.have.lengthOf(NUMBER_OF_GROUPS_USER_CAN_VIEW);
});
it('returns a list of groups user has access to', async () => {
const group = await generateGroup(user, {
name: 'c++ coders',
type: 'guild',
privacy: 'public',
describe('filters', () => {
it('returns private guilds filtered by category', async () => {
const guilds = await user.get(`/groups?type=privateGuilds&categories=${categories[0].slug}`);
expect(guilds[0]._id).to.equal(privateGuildUserIsMemberOf._id);
});
// search for 'c++ coders'
await expect(user.get('/groups?type=publicGuilds&paginate=true&page=0&search=c%2B%2B+coders'))
.to.eventually.have.lengthOf(1)
.and.to.have.nested.property('[0]')
.and.to.have.property('_id', group._id);
it('filters private guilds by size', async () => {
const guilds = await user.get('/groups?type=privateGuilds&minMemberCount=3');
expect(guilds.length).to.equal(0);
});
});
});

View File

@@ -3,6 +3,7 @@ import {
generateUser,
generateGroup,
translate as t,
createAndPopulateGroup,
} from '../../../../helpers/api-integration/v3';
describe('GET /groups/:groupId/invites', () => {
@@ -71,15 +72,16 @@ describe('GET /groups/:groupId/invites', () => {
});
it('returns only first 30 invites by default (req.query.limit not specified)', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const invitesToGenerate = [];
for (let i = 0; i < 31; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate);
await leader.post(`/groups/${group._id}/invite`, { uuids: generatedInvites.map(invite => invite._id) });
const { group, groupLeader: leader } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 31,
upgradeToGroupPlan: true,
});
const res = await leader.get(`/groups/${group._id}/invites`);
expect(res.length).to.equal(30);
@@ -90,8 +92,16 @@ describe('GET /groups/:groupId/invites', () => {
}).timeout(10000);
it('returns an error if req.query.limit is over 60', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const { group, groupLeader: leader } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 1,
upgradeToGroupPlan: true,
});
await expect(leader.get(`/groups/${group._id}/invites?limit=61`)).to.eventually.be.rejected.and.eql({
code: 400,
@@ -101,8 +111,16 @@ describe('GET /groups/:groupId/invites', () => {
});
it('returns an error if req.query.limit is under 1', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const { group, groupLeader: leader } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 1,
upgradeToGroupPlan: true,
});
await expect(leader.get(`/groups/${group._id}/invites?limit=-1`)).to.eventually.be.rejected.and.eql({
code: 400,
@@ -112,8 +130,16 @@ describe('GET /groups/:groupId/invites', () => {
});
it('returns an error if req.query.limit is not an integer', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const { group, groupLeader: leader } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 1,
upgradeToGroupPlan: true,
});
await expect(leader.get(`/groups/${group._id}/invites?limit=1.3`)).to.eventually.be.rejected.and.eql({
code: 400,
@@ -123,15 +149,16 @@ describe('GET /groups/:groupId/invites', () => {
});
it('returns up to 60 invites when req.query.limit is specified', async () => {
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const invitesToGenerate = [];
for (let i = 0; i < 31; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate);
await leader.post(`/groups/${group._id}/invite`, { uuids: generatedInvites.map(invite => invite._id) });
const { group, groupLeader: leader } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 31,
upgradeToGroupPlan: true,
});
let res = await leader.get(`/groups/${group._id}/invites?limit=14`);
expect(res.length).to.equal(14);
@@ -149,17 +176,20 @@ describe('GET /groups/:groupId/invites', () => {
}).timeout(30000);
it('supports using req.query.lastId to get more invites', async function test () {
let group; let invitees;
this.timeout(30000); // @TODO: times out after 8 seconds
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
({ group, groupLeader: user, invitees } = await createAndPopulateGroup({
groupDetails: {
type: 'guild',
privacy: 'private',
name: generateUUID(),
},
leaderDetails: { balance: 4 },
invites: 32,
upgradeToGroupPlan: true,
}));
const invitesToGenerate = [];
for (let i = 0; i < 32; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate); // Group has 32 invites
const expectedIds = generatedInvites.map(generatedInvite => generatedInvite._id);
await user.post(`/groups/${group._id}/invite`, { uuids: expectedIds });
const expectedIds = invitees.map(generatedInvite => generatedInvite._id);
const res = await user.get(`/groups/${group._id}/invites`);
expect(res.length).to.equal(30);

View File

@@ -1,5 +1,6 @@
import { v4 as generateUUID } from 'uuid';
import {
createAndPopulateGroup,
generateUser,
generateGroup,
translate as t,
@@ -75,7 +76,15 @@ describe('GET /groups/:groupId/members', () => {
});
it('req.query.includeAllPublicFields === true works with guilds', async () => {
const group = await generateGroup(user, { type: 'guild', name: generateUUID() });
let group;
({ group, groupLeader: user } = await createAndPopulateGroup({
type: 'guild',
privacy: 'private',
name: generateUUID(),
upgradeToGroupPlan: true,
members: 1,
}));
const [memberRes] = await user.get(`/groups/${group._id}/members?includeAllPublicFields=true`);
expect(memberRes).to.have.all.keys([ // works as: object has all and only these keys
@@ -206,20 +215,20 @@ describe('GET /groups/:groupId/members', () => {
it('supports using req.query.lastId to get more members', async function test () {
this.timeout(30000); // @TODO: times out after 8 seconds
const leader = await generateUser({ balance: 4 });
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
const { group, groupLeader: leader, members: generatedUsers } = await createAndPopulateGroup({
type: 'guild',
privacy: 'private',
name: generateUUID(),
upgradeToGroupPlan: true,
leaderDetails: { balance: 4 },
members: 57,
});
const usersToGenerate = [];
for (let i = 0; i < 57; i += 1) {
usersToGenerate.push(generateUser({ guilds: [group._id] }));
}
// Group has 59 members (1 is the leader)
const generatedUsers = await Promise.all(usersToGenerate);
const expectedIds = [leader._id].concat(generatedUsers.map(generatedUser => generatedUser._id));
const res = await user.get(`/groups/${group._id}/members`);
const res = await leader.get(`/groups/${group._id}/members`);
expect(res.length).to.equal(30);
const res2 = await user.get(`/groups/${group._id}/members?lastId=${res[res.length - 1]._id}`);
const res2 = await leader.get(`/groups/${group._id}/members?lastId=${res[res.length - 1]._id}`);
expect(res2.length).to.equal(28);
const resIds = res.concat(res2).map(member => member._id);

View File

@@ -11,7 +11,6 @@ import {
describe('GET /groups/:id', () => {
const typesOfGroups = {};
typesOfGroups['public guild'] = { type: 'guild', privacy: 'public' };
typesOfGroups['private guild'] = { type: 'guild', privacy: 'private' };
typesOfGroups.party = { type: 'party', privacy: 'private' };
@@ -24,10 +23,11 @@ describe('GET /groups/:id', () => {
const groupData = await createAndPopulateGroup({
members: 30,
groupDetails,
upgradeToGroupPlan: groupDetails.type === 'guild',
});
leader = groupData.groupLeader;
member = groupData.members[0]; // eslint-disable-line prefer-destructuring
[member] = groupData.members;
createdGroup = groupData.group;
});
@@ -49,34 +49,6 @@ describe('GET /groups/:id', () => {
});
});
context('Non-member of a public guild', () => {
let nonMember; let
createdGroup;
before(async () => {
const groupData = await createAndPopulateGroup({
members: 1,
groupDetails: {
name: 'test guild',
type: 'guild',
privacy: 'public',
},
});
createdGroup = groupData.group;
nonMember = await generateUser();
});
it('returns the group object for a non-member', async () => {
const group = await nonMember.get(`/groups/${createdGroup._id}`);
expect(group._id).to.eql(createdGroup._id);
expect(group.name).to.eql(createdGroup.name);
expect(group.type).to.eql(createdGroup.type);
expect(group.privacy).to.eql(createdGroup.privacy);
});
});
context('Non-member of a private guild', () => {
let nonMember; let
createdGroup;
@@ -89,6 +61,7 @@ describe('GET /groups/:id', () => {
type: 'guild',
privacy: 'private',
},
upgradeToGroupPlan: true,
});
createdGroup = groupData.group;
@@ -180,7 +153,7 @@ describe('GET /groups/:id', () => {
it('removes non-existent guild from user\'s guild list', async () => {
const guildId = generateUUID();
await user.update({
await user.updateOne({
guilds: [guildId, generateUUID()],
});
@@ -200,7 +173,7 @@ describe('GET /groups/:id', () => {
it('removes non-existent party from user\'s party object', async () => {
const partyId = generateUUID();
await user.update({
await user.updateOne({
party: { _id: partyId },
});
@@ -218,7 +191,7 @@ describe('GET /groups/:id', () => {
});
context('Flagged messages', () => {
let group;
let group; let members;
const chat1 = {
id: 'chat1',
@@ -268,7 +241,7 @@ describe('GET /groups/:id', () => {
groupDetails: {
name: 'test guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
chat: [
chat1,
chat2,
@@ -277,9 +250,11 @@ describe('GET /groups/:id', () => {
chat5,
],
},
members: 1,
upgradeToGroupPlan: true,
});
group = groupData.group;
({ group, members } = groupData);
await group.addChat([chat1, chat2, chat3, chat4, chat5]);
});
@@ -287,8 +262,8 @@ describe('GET /groups/:id', () => {
context('non-admin', () => {
let nonAdmin;
beforeEach(async () => {
nonAdmin = await generateUser();
beforeEach(() => {
[nonAdmin] = members;
});
it('does not include messages with a flag count of 2 or greater', async () => {
@@ -314,9 +289,8 @@ describe('GET /groups/:id', () => {
let admin;
beforeEach(async () => {
admin = await generateUser({
'permissions.moderator': true,
});
[admin] = members;
await admin.updateOne({ permissions: { moderator: true } });
});
it('includes all messages', async () => {

View File

@@ -2,7 +2,6 @@ import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import { model as Group } from '../../../../../website/server/models/group';
import { MAX_SUMMARY_SIZE_FOR_GUILDS } from '../../../../../website/common/script/constants';
describe('POST /group', () => {
@@ -35,8 +34,8 @@ describe('POST /group', () => {
it('sets the group leader to the user who created the group', async () => {
const group = await user.post('/groups', {
name: 'Test Public Guild',
type: 'guild',
name: 'Test Party',
type: 'party',
});
expect(group.leader).to.eql({
@@ -51,7 +50,7 @@ describe('POST /group', () => {
const name = 'Test Group';
const group = await user.post('/groups', {
name,
type: 'guild',
type: 'party',
});
const updatedGroup = await user.get(`/groups/${group._id}`);
@@ -64,7 +63,7 @@ describe('POST /group', () => {
const summary = 'Test Summary';
const group = await user.post('/groups', {
name,
type: 'guild',
type: 'party',
summary,
});
@@ -78,7 +77,7 @@ describe('POST /group', () => {
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_GUILDS + 1);
await expect(user.post('/groups', {
name,
type: 'guild',
type: 'party',
summary,
})).to.eventually.be.rejected.and.eql({
code: 400,
@@ -88,157 +87,6 @@ describe('POST /group', () => {
});
});
context('Guilds', () => {
it('returns an error when a user with insufficient funds attempts to create a guild', async () => {
await user.update({ balance: 0 });
await expect(
user.post('/groups', {
name: 'Test Public Guild',
type: 'guild',
}),
).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageInsufficientGems'),
});
});
it('adds guild to user\'s list of guilds', async () => {
const guild = await user.post('/groups', {
name: 'some guild',
type: 'guild',
privacy: 'public',
});
const updatedUser = await user.get('/user');
expect(updatedUser.guilds).to.include(guild._id);
});
it('awards the Joined Guild achievement', async () => {
await user.post('/groups', {
name: 'some guild',
type: 'guild',
privacy: 'public',
});
const updatedUser = await user.get('/user');
expect(updatedUser.achievements.joinedGuild).to.eql(true);
});
context('public guild', () => {
it('creates a group', async () => {
const groupName = 'Test Public Guild';
const groupType = 'guild';
const groupPrivacy = 'public';
const publicGuild = await user.post('/groups', {
name: groupName,
type: groupType,
privacy: groupPrivacy,
});
expect(publicGuild._id).to.exist;
expect(publicGuild.name).to.equal(groupName);
expect(publicGuild.type).to.equal(groupType);
expect(publicGuild.memberCount).to.equal(1);
expect(publicGuild.privacy).to.equal(groupPrivacy);
expect(publicGuild.leader).to.eql({
_id: user._id,
profile: {
name: user.profile.name,
},
});
});
it('returns an error when a user with no chat privileges attempts to create a public guild', async () => {
await user.update({ 'flags.chatRevoked': true });
await expect(
user.post('/groups', {
name: 'Test Public Guild',
type: 'guild',
privacy: 'public',
}),
).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('chatPrivilegesRevoked'),
});
});
});
context('private guild', () => {
const groupName = 'Test Private Guild';
const groupType = 'guild';
const groupPrivacy = 'private';
it('creates a group', async () => {
const privateGuild = await user.post('/groups', {
name: groupName,
type: groupType,
privacy: groupPrivacy,
});
expect(privateGuild._id).to.exist;
expect(privateGuild.name).to.equal(groupName);
expect(privateGuild.type).to.equal(groupType);
expect(privateGuild.memberCount).to.equal(1);
expect(privateGuild.privacy).to.equal(groupPrivacy);
expect(privateGuild.leader).to.eql({
_id: user._id,
profile: {
name: user.profile.name,
},
});
});
it('creates a private guild when the user has no chat privileges', async () => {
await user.update({ 'flags.chatRevoked': true });
const privateGuild = await user.post('/groups', {
name: groupName,
type: groupType,
privacy: groupPrivacy,
});
expect(privateGuild._id).to.exist;
});
it('deducts gems from user and adds them to guild bank', async () => {
const privateGuild = await user.post('/groups', {
name: groupName,
type: groupType,
privacy: groupPrivacy,
});
expect(privateGuild.balance).to.eql(1);
const updatedUser = await user.get('/user');
expect(updatedUser.balance).to.eql(user.balance - 1);
});
it('does not deduct the gems from user when guild creation fails', async () => {
const stub = sinon.stub(Group.prototype, 'save').rejects();
const promise = user.post('/groups', {
name: groupName,
type: groupType,
privacy: groupPrivacy,
});
await expect(promise).to.eventually.be.rejected;
const updatedUser = await user.get('/user');
expect(updatedUser.balance).to.eql(user.balance);
stub.restore();
});
});
});
context('Parties', () => {
const partyName = 'Test Party';
const partyType = 'party';
@@ -262,7 +110,7 @@ describe('POST /group', () => {
});
it('creates a party when the user has no chat privileges', async () => {
await user.update({ 'flags.chatRevoked': true });
await user.updateOne({ 'flags.chatRevoked': true });
const party = await user.post('/groups', {
name: partyName,
type: partyType,
@@ -272,7 +120,7 @@ describe('POST /group', () => {
});
it('does not require gems to create a party', async () => {
await user.update({ balance: 0 });
await user.updateOne({ balance: 0 });
const party = await user.post('/groups', {
name: partyName,

View File

@@ -2,7 +2,6 @@ import { v4 as generateUUID } from 'uuid';
import {
generateUser,
createAndPopulateGroup,
checkExistence,
translate as t,
} from '../../../../helpers/api-integration/v3';
@@ -19,81 +18,24 @@ describe('POST /group/:groupId/join', () => {
});
});
context('Joining a public guild', () => {
let user; let joiningUser; let
publicGuild;
beforeEach(async () => {
const { group, groupLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'public',
},
});
publicGuild = group;
user = groupLeader;
joiningUser = await generateUser();
});
it('allows non-invited users to join public guilds', async () => {
const res = await joiningUser.post(`/groups/${publicGuild._id}/join`);
await expect(joiningUser.get('/user')).to.eventually.have.property('guilds').to.include(publicGuild._id);
expect(res.leader._id).to.eql(user._id);
expect(res.leader.profile.name).to.eql(user.profile.name);
});
it('returns an error if user was already a member', async () => {
await joiningUser.post(`/groups/${publicGuild._id}/join`);
await expect(joiningUser.post(`/groups/${publicGuild._id}/join`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('youAreAlreadyInGroup'),
});
});
it('promotes joining member in a public empty guild to leader', async () => {
await user.post(`/groups/${publicGuild._id}/leave`);
await joiningUser.post(`/groups/${publicGuild._id}/join`);
await expect(joiningUser.get(`/groups/${publicGuild._id}`)).to.eventually.have.nested.property('leader._id', joiningUser._id);
});
it('increments memberCount when joining guilds', async () => {
const oldMemberCount = publicGuild.memberCount;
await joiningUser.post(`/groups/${publicGuild._id}/join`);
await expect(joiningUser.get(`/groups/${publicGuild._id}`)).to.eventually.have.property('memberCount', oldMemberCount + 1);
});
it('awards Joined Guild achievement', async () => {
await joiningUser.post(`/groups/${publicGuild._id}/join`);
await expect(joiningUser.get('/user')).to.eventually.have.nested.property('achievements.joinedGuild', true);
});
});
context('Joining a private guild', () => {
let user; let invitedUser; let
guild;
let user;
let invitedUser;
let guild;
let invitees;
beforeEach(async () => {
const { group, groupLeader, invitees } = await createAndPopulateGroup({
({ group: guild, groupLeader: user, invitees } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'private',
},
invites: 1,
});
upgradeToGroupPlan: true,
}));
guild = group;
user = groupLeader;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
[invitedUser] = invitees;
});
it('returns error when user is not invited to private guild', async () => {
@@ -136,7 +78,7 @@ describe('POST /group/:groupId/join', () => {
});
it('does not increment basilist quest count to inviter with basilist when joining a guild', async () => {
await user.update({ 'items.quests.basilist': 1 });
await user.updateOne({ 'items.quests.basilist': 1 });
await invitedUser.post(`/groups/${guild._id}/join`);
@@ -183,7 +125,7 @@ describe('POST /group/:groupId/join', () => {
party = group;
user = groupLeader;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
[invitedUser] = invitees;
});
it('returns error when user is not invited to party', async () => {
@@ -204,7 +146,7 @@ describe('POST /group/:groupId/join', () => {
});
it('Issue #12291: accepting a redundant party invite will let the user stay in the party', async () => {
await invitedUser.update({
await invitedUser.updateOne({
'party._id': party._id,
});
await expect(invitedUser.get('/user')).to.eventually.have.nested.property('party._id', party._id);
@@ -251,56 +193,15 @@ describe('POST /group/:groupId/join', () => {
});
it('increments basilist quest item count to inviter when joining a party', async () => {
await user.update({ 'items.quests.basilist': 1 });
await user.updateOne({ 'items.quests.basilist': 1 });
await invitedUser.post(`/groups/${party._id}/join`);
await expect(user.get('/user')).to.eventually.have.nested.property('items.quests.basilist', 2);
});
it('deletes previous party where the user was the only member', async () => {
const userToInvite = await generateUser();
const oldParty = await userToInvite.post('/groups', { // add user to a party
name: 'Another Test Party',
type: 'party',
});
await expect(checkExistence('groups', oldParty._id)).to.eventually.equal(true);
await user.post(`/groups/${party._id}/invite`, {
uuids: [userToInvite._id],
});
await userToInvite.post(`/groups/${party._id}/join`);
await expect(user.get('/user')).to.eventually.have.nested.property('party._id', party._id);
await expect(checkExistence('groups', oldParty._id)).to.eventually.equal(false);
});
it('does not allow user to leave a party if a quest was active and they were the only member', async () => {
const userToInvite = await generateUser();
const oldParty = await userToInvite.post('/groups', { // add user to a party
name: 'Another Test Party',
type: 'party',
});
await userToInvite.update({
[`items.quests.${PET_QUEST}`]: 1,
});
await userToInvite.post(`/groups/${oldParty._id}/quests/invite/${PET_QUEST}`);
await expect(checkExistence('groups', oldParty._id)).to.eventually.equal(true);
await user.post(`/groups/${party._id}/invite`, {
uuids: [userToInvite._id],
});
await expect(userToInvite.post(`/groups/${party._id}/join`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageCannotLeaveWhileQuesting'),
});
});
it('invites joining member to active quest', async () => {
await user.update({
await user.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
await user.post(`/groups/${party._id}/quests/invite/${PET_QUEST}`);

View File

@@ -5,7 +5,6 @@ import {
generateChallenge,
checkExistence,
createAndPopulateGroup,
sleep,
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
@@ -14,253 +13,187 @@ import payments from '../../../../../website/server/libs/payments/payments';
import calculateSubscriptionTerminationDate from '../../../../../website/server/libs/payments/calculateSubscriptionTerminationDate';
describe('POST /groups/:groupId/leave', () => {
const typesOfGroups = {
'public guild': { type: 'guild', privacy: 'public' },
'private guild': { type: 'guild', privacy: 'private' },
party: { type: 'party', privacy: 'private' },
};
let groupToLeave;
let leader;
let member;
let members;
let memberCount;
each(typesOfGroups, (groupDetails, groupType) => {
context(`Leaving a ${groupType}`, () => {
let groupToLeave;
let leader;
let member;
let memberCount;
context('Leaving a Group Plan', () => {
beforeEach(async () => {
({ group: groupToLeave, groupLeader: leader, members } = await createAndPopulateGroup({
type: 'guild',
privacy: 'private',
members: 1,
upgradeToGroupPlan: true,
}));
[member] = members;
memberCount = groupToLeave.memberCount;
await leader.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('prevents non members from leaving', async () => {
const user = await generateUser();
await expect(user.post(`/groups/${groupToLeave._id}/leave`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('groupNotFound'),
});
});
it('lets user leave', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
const userThatLeftGroup = await member.get('/user');
expect(userThatLeftGroup.guilds).to.be.empty;
expect(userThatLeftGroup.party._id).to.not.exist;
await groupToLeave.sync();
expect(groupToLeave.memberCount).to.equal(memberCount - 1);
});
it('removes new messages for that group from user', async () => {
await leader.post(`/groups/${groupToLeave._id}/chat`, { message: 'Some message' });
await member.sync();
expect(member.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.exist;
expect(member.newMessages[groupToLeave._id]).to.not.be.empty;
await member.post(`/groups/${groupToLeave._id}/leave`);
await member.sync();
expect(member.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.not.exist;
expect(member.newMessages[groupToLeave._id]).to.be.undefined;
});
context('with challenges', () => {
let challenge;
beforeEach(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
groupDetails,
members: 1,
});
challenge = await generateChallenge(leader, groupToLeave);
await member.post(`/challenges/${challenge._id}/join`);
groupToLeave = group;
leader = groupLeader;
member = members[0]; // eslint-disable-line prefer-destructuring
memberCount = group.memberCount;
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('prevents non members from leaving', async () => {
const user = await generateUser();
await expect(user.post(`/groups/${groupToLeave._id}/leave`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('groupNotFound'),
await leader.post(`/tasks/challenge/${challenge._id}`, {
text: 'test habit',
type: 'habit',
});
});
it(`lets user leave a ${groupType}`, async () => {
it('removes all challenge tasks when keep parameter is set to remove', async () => {
await member.post(`/groups/${groupToLeave._id}/leave?keep=remove-all`);
const userWithoutChallengeTasks = await member.get('/user');
expect(userWithoutChallengeTasks.challenges).to.not.include(challenge._id);
expect(userWithoutChallengeTasks.tasksOrder.habits).to.be.empty;
});
it('keeps all challenge tasks when keep parameter is not set', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
const userThatLeftGroup = await member.get('/user');
const userWithChallengeTasks = await member.get('/user');
expect(userThatLeftGroup.guilds).to.be.empty;
expect(userThatLeftGroup.party._id).to.not.exist;
await groupToLeave.sync();
expect(groupToLeave.memberCount).to.equal(memberCount - 1);
expect(userWithChallengeTasks.tasksOrder.habits).to.not.be.empty;
});
it(`sets a new group leader when leader leaves a ${groupType}`, async () => {
await leader.post(`/groups/${groupToLeave._id}/leave`);
it('keeps the user in the challenge when the keepChallenges parameter is set to remain-in-challenges', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`, { keepChallenges: 'remain-in-challenges' });
await groupToLeave.sync();
expect(groupToLeave.memberCount).to.equal(memberCount - 1);
expect(groupToLeave.leader).to.equal(member._id);
const userWithChallengeTasks = await member.get('/user');
expect(userWithChallengeTasks.challenges).to.include(challenge._id);
});
it('removes new messages for that group from user', async () => {
await member.post(`/groups/${groupToLeave._id}/chat`, { message: 'Some message' });
it('drops the user in the challenge when the keepChallenges parameter isn\'t set', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
await sleep(0.5);
const userWithChallengeTasks = await member.get('/user');
await leader.sync();
expect(leader.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.exist;
expect(leader.newMessages[groupToLeave._id]).to.not.be.empty;
await leader.post(`/groups/${groupToLeave._id}/leave`);
await leader.sync();
expect(leader.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.not.exist;
expect(leader.newMessages[groupToLeave._id]).to.be.undefined;
expect(userWithChallengeTasks.challenges).to.not.include(challenge._id);
});
context('with challenges', () => {
let challenge;
beforeEach(async () => {
challenge = await generateChallenge(leader, groupToLeave);
await leader.post(`/challenges/${challenge._id}/join`);
await leader.post(`/tasks/challenge/${challenge._id}`, {
text: 'test habit',
type: 'habit',
});
await sleep(0.5);
});
it('removes all challenge tasks when keep parameter is set to remove', async () => {
await leader.post(`/groups/${groupToLeave._id}/leave?keep=remove-all`);
const userWithoutChallengeTasks = await leader.get('/user');
expect(userWithoutChallengeTasks.challenges).to.not.include(challenge._id);
expect(userWithoutChallengeTasks.tasksOrder.habits).to.be.empty;
});
it('keeps all challenge tasks when keep parameter is not set', async () => {
await leader.post(`/groups/${groupToLeave._id}/leave`);
const userWithChallengeTasks = await leader.get('/user');
// @TODO find elegant way to assert against the task existing
expect(userWithChallengeTasks.tasksOrder.habits).to.not.be.empty;
});
it('keeps the user in the challenge when the keepChallenges parameter is set to remain-in-challenges', async () => {
await leader.post(`/groups/${groupToLeave._id}/leave`, { keepChallenges: 'remain-in-challenges' });
const userWithChallengeTasks = await leader.get('/user');
expect(userWithChallengeTasks.challenges).to.include(challenge._id);
});
it('drops the user in the challenge when the keepChallenges parameter isn\'t set', async () => {
await leader.post(`/groups/${groupToLeave._id}/leave`);
const userWithChallengeTasks = await leader.get('/user');
expect(userWithChallengeTasks.challenges).to.not.include(challenge._id);
});
});
it('prevents quest leader from leaving a groupToLeave');
it('prevents a user from leaving during an active quest');
});
});
context('Leaving a group as the last member', () => {
context('private guild', () => {
let privateGuild;
let leader;
let invitedUser;
context('Leaving a Party', () => {
let invitees;
let invitedUser;
beforeEach(async () => {
const { group, groupLeader, invitees } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Private Guild',
type: 'guild',
},
invites: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
beforeEach(async () => {
({
group: groupToLeave,
groupLeader: leader,
members,
invitees,
} = await createAndPopulateGroup({
type: 'party',
privacy: 'private',
members: 1,
invites: 1,
}));
privateGuild = group;
leader = groupLeader;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
[member] = members;
[invitedUser] = invitees;
memberCount = groupToLeave.memberCount;
await leader.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
await leader.post(`/groups/${group._id}/chat`, { message: 'Some message' });
});
it('removes a group when the last member leaves', async () => {
await leader.post(`/groups/${privateGuild._id}/leave`);
await expect(checkExistence('groups', privateGuild._id)).to.eventually.equal(false);
});
it('removes invitations when the last member leaves', async () => {
await leader.post(`/groups/${privateGuild._id}/leave`);
const userWithoutInvitation = await invitedUser.get('/user');
expect(userWithoutInvitation.invitations.guilds).to.be.empty;
it('prevents non members from leaving', async () => {
const user = await generateUser();
await expect(user.post(`/groups/${groupToLeave._id}/leave`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('groupNotFound'),
});
});
context('public guild', () => {
let publicGuild;
let leader;
let invitedUser;
it('lets user leave', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
beforeEach(async () => {
const { group, groupLeader, invitees } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Public Guild',
type: 'guild',
privacy: 'public',
},
invites: 1,
});
const userThatLeftGroup = await member.get('/user');
publicGuild = group;
leader = groupLeader;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
});
it('keeps the group when the last member leaves', async () => {
await leader.post(`/groups/${publicGuild._id}/leave`);
await expect(checkExistence('groups', publicGuild._id)).to.eventually.equal(true);
});
it('keeps the invitations when the last member leaves a public guild', async () => {
await leader.post(`/groups/${publicGuild._id}/leave`);
const userWithoutInvitation = await invitedUser.get('/user');
expect(userWithoutInvitation.invitations.guilds).to.not.be.empty;
});
it('deletes non existent guild from user when user tries to leave', async () => {
const nonExistentGuildId = generateUUID();
const userWithNonExistentGuild = await generateUser({ guilds: [nonExistentGuildId] });
expect(userWithNonExistentGuild.guilds).to.contain(nonExistentGuildId);
await expect(userWithNonExistentGuild.post(`/groups/${nonExistentGuildId}/leave`))
.to.eventually.be.rejected;
await userWithNonExistentGuild.sync();
expect(userWithNonExistentGuild.guilds).to.not.contain(nonExistentGuildId);
});
expect(userThatLeftGroup.guilds).to.be.empty;
expect(userThatLeftGroup.party._id).to.not.exist;
await groupToLeave.sync();
expect(groupToLeave.memberCount).to.equal(memberCount - 1);
});
context('party', () => {
let party;
let leader;
let invitedUser;
it('sets a new group leader when leader leaves', async () => {
await leader.post(`/groups/${groupToLeave._id}/leave`);
beforeEach(async () => {
const { group, groupLeader, invitees } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Party',
type: 'party',
},
invites: 1,
});
await groupToLeave.sync();
expect(groupToLeave.memberCount).to.equal(memberCount - 1);
expect(groupToLeave.leader).to.equal(member._id);
});
party = group;
leader = groupLeader;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
});
it('removes new messages for that group from user', async () => {
await leader.post(`/groups/${groupToLeave._id}/chat`, { message: 'Some message' });
await member.sync();
it('removes a group when the last member leaves a party', async () => {
await leader.post(`/groups/${party._id}/leave`);
expect(member.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.exist;
expect(member.newMessages[groupToLeave._id]).to.not.be.empty;
await expect(checkExistence('party', party._id)).to.eventually.equal(false);
});
await member.post(`/groups/${groupToLeave._id}/leave`);
await member.sync();
it('removes invitations when the last member leaves a party', async () => {
await leader.post(`/groups/${party._id}/leave`);
expect(member.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupToLeave._id)).to.not.exist;
expect(member.newMessages[groupToLeave._id]).to.be.undefined;
});
const userWithoutInvitation = await invitedUser.get('/user');
it('removes a party when the last member leaves', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
await leader.post(`/groups/${groupToLeave._id}/leave`);
expect(userWithoutInvitation.invitations.parties[0]).to.be.undefined;
});
await expect(checkExistence('party', groupToLeave._id)).to.eventually.equal(false);
});
it('removes invitations when the last member leaves a party', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
await leader.post(`/groups/${groupToLeave._id}/leave`);
const userWithoutInvitation = await invitedUser.get('/user');
expect(userWithoutInvitation.invitations.parties[0]).to.be.undefined;
});
it('deletes non existent party from user when user tries to leave', async () => {
@@ -275,23 +208,71 @@ describe('POST /groups/:groupId/leave', () => {
expect(userWithNonExistentParty.party).to.eql({});
});
context('with challenges', () => {
let challenge;
beforeEach(async () => {
challenge = await generateChallenge(leader, groupToLeave);
await member.post(`/challenges/${challenge._id}/join`);
await leader.post(`/tasks/challenge/${challenge._id}`, {
text: 'test habit',
type: 'habit',
});
});
it('removes all challenge tasks when keep parameter is set to remove', async () => {
await member.post(`/groups/${groupToLeave._id}/leave?keep=remove-all`);
const userWithoutChallengeTasks = await member.get('/user');
expect(userWithoutChallengeTasks.challenges).to.not.include(challenge._id);
expect(userWithoutChallengeTasks.tasksOrder.habits).to.be.empty;
});
it('keeps all challenge tasks when keep parameter is not set', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
const userWithChallengeTasks = await member.get('/user');
expect(userWithChallengeTasks.tasksOrder.habits).to.not.be.empty;
});
it('keeps the user in the challenge when the keepChallenges parameter is set to remain-in-challenges', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`, { keepChallenges: 'remain-in-challenges' });
const userWithChallengeTasks = await member.get('/user');
expect(userWithChallengeTasks.challenges).to.include(challenge._id);
});
it('drops the user in the challenge when the keepChallenges parameter isn\'t set', async () => {
await member.post(`/groups/${groupToLeave._id}/leave`);
const userWithChallengeTasks = await member.get('/user');
expect(userWithChallengeTasks.challenges).to.not.include(challenge._id);
});
});
});
const typesOfGroups = {
'private guild': { type: 'guild', privacy: 'private' },
party: { type: 'party', privacy: 'private' },
};
each(typesOfGroups, (groupDetails, groupType) => {
context(`Leaving a group plan when the group is a ${groupType}`, () => {
if (groupDetails.privacy === 'public') return; // public guilds cannot be group plans
let groupWithPlan;
let leader;
let member;
beforeEach(async () => {
const { group, groupLeader, members } = await createAndPopulateGroup({
({ group: groupWithPlan, groupLeader: leader, members } = await createAndPopulateGroup({
groupDetails,
members: 1,
});
leader = groupLeader;
member = members[0]; // eslint-disable-line prefer-destructuring
groupWithPlan = group;
upgradeToGroupPlan: true,
}));
[member] = members;
const userWithFreePlan = await User.findById(leader._id).exec();
// Create subscription
@@ -321,46 +302,22 @@ describe('POST /groups/:groupId/leave', () => {
await member.sync();
expect(member.purchased.plan.dateTerminated).to.exist;
});
it('preserves the free subscription when leaving a any other group without a plan', async () => {
// Joining a guild without a group plan
const { group: groupWithNoPlan } = await createAndPopulateGroup({
groupDetails: {
name: 'Group Without Plan',
type: 'guild',
privacy: 'public',
},
});
await member.post(`/groups/${groupWithNoPlan._id}/join`);
await member.sync();
expect(member.purchased.plan.planId).to.equal('group_plan_auto');
expect(member.purchased.plan.dateTerminated).to.not.exist;
// Leaving the guild without a group plan
await member.post(`/groups/${groupWithNoPlan._id}/leave`);
await member.sync();
expect(member.purchased.plan.dateTerminated).to.not.exist;
});
});
});
each(typesOfGroups, (groupDetails, groupType) => {
context(`Leaving a group with extraMonths left plan when the group is a ${groupType}`, () => {
if (groupDetails.privacy === 'public') return; // public guilds cannot be group plans
const extraMonths = 12;
let groupWithPlan;
let member;
beforeEach(async () => {
const { group, members } = await createAndPopulateGroup({
({ group: groupWithPlan, members } = await createAndPopulateGroup({
groupDetails,
members: 1,
upgradeToGroupPlan: true,
});
}));
[member] = members;
groupWithPlan = group;
await member.update({
await member.updateOne({
'purchased.plan.extraMonths': extraMonths,
});
});

View File

@@ -5,43 +5,6 @@ import {
} from '../../../../helpers/api-integration/v3';
describe('POST /group/:groupId/reject-invite', () => {
context('Rejecting a public guild invite', () => {
let publicGuild; let
invitedUser;
beforeEach(async () => {
const { group, invitees } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Guild',
type: 'guild',
privacy: 'public',
},
invites: 1,
});
publicGuild = group;
invitedUser = invitees[0]; // eslint-disable-line prefer-destructuring
});
it('returns error when user is not invited', async () => {
const userWithoutInvite = await generateUser();
await expect(userWithoutInvite.post(`/groups/${publicGuild._id}/reject-invite`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('messageGroupRequiresInvite'),
});
});
it('clears invitation from user', async () => {
await invitedUser.post(`/groups/${publicGuild._id}/reject-invite`);
await expect(invitedUser.get('/user'))
.to.eventually.have.nested.property('invitations.guilds')
.to.not.include({ id: publicGuild._id });
});
});
context('Rejecting a private guild invite', () => {
let invitedUser; let
guild;
@@ -54,6 +17,7 @@ describe('POST /group/:groupId/reject-invite', () => {
privacy: 'private',
},
invites: 1,
upgradeToGroupPlan: true,
});
guild = group;

View File

@@ -25,6 +25,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
},
invites: 1,
members: 2,
upgradeToGroupPlan: true,
});
guild = group;
@@ -129,9 +130,11 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
it('sends email to removed user', async () => {
await leader.post(`/groups/${guild._id}/removeMember/${member._id}`);
expect(email.sendTxn).to.be.calledOnce;
expect(email.sendTxn).to.be.calledTwice;
expect(email.sendTxn.args[0][0]._id).to.eql(member._id);
expect(email.sendTxn.args[0][1]).to.eql('kicked-from-guild');
expect(email.sendTxn.args[1][0]._id).to.eql(member._id);
expect(email.sendTxn.args[1][1]).to.eql('group-member-removed');
});
});
@@ -209,7 +212,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
it('removes user from quest when removing user from party after quest starts', async () => {
const petQuest = 'whale';
await partyLeader.update({
await partyLeader.updateOne({
[`items.quests.${petQuest}`]: 1,
});
@@ -231,7 +234,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
it('removes user from quest when removing user from party before quest starts', async () => {
const petQuest = 'whale';
await partyLeader.update({
await partyLeader.updateOne({
[`items.quests.${petQuest}`]: 1,
});
await partyInvitedUser.post(`/groups/${party._id}/join`);
@@ -254,7 +257,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
it('prevents user from being removed if they are the quest owner', async () => {
const petQuest = 'whale';
await partyMember.update({
await partyMember.updateOne({
[`items.quests.${petQuest}`]: 1,
});

View File

@@ -1,25 +1,25 @@
import { v4 as generateUUID } from 'uuid';
import nconf from 'nconf';
import {
createAndPopulateGroup,
generateUser,
generateGroup,
translate as t,
} from '../../../../helpers/api-integration/v3';
const INVITES_LIMIT = 100;
const PARTY_LIMIT_MEMBERS = 29;
const PARTY_LIMIT_MEMBERS = 30;
const MAX_EMAIL_INVITES_BY_USER = 200;
describe('Post /groups/:groupId/invite', () => {
let inviter;
let group;
const groupName = 'Test Public Guild';
const groupName = 'Test Party';
beforeEach(async () => {
inviter = await generateUser({ balance: 4 });
group = await inviter.post('/groups', {
name: groupName,
type: 'guild',
type: 'party',
});
});
@@ -49,7 +49,7 @@ describe('Post /groups/:groupId/invite', () => {
});
it('returns error when recipient has blocked the senders', async () => {
const inviterNoBlocks = await inviter.update({ 'inbox.blocks': [] });
const inviterNoBlocks = await inviter.updateOne({ 'inbox.blocks': [] });
const userWithBlockedInviter = await generateUser({ 'inbox.blocks': [inviter._id] });
await expect(inviterNoBlocks.post(`/groups/${group._id}/invite`, {
usernames: [userWithBlockedInviter.auth.local.lowerCaseUsername],
@@ -64,51 +64,50 @@ describe('Post /groups/:groupId/invite', () => {
it('invites a user to a group by username', async () => {
const userToInvite = await generateUser();
await expect(inviter.post(`/groups/${group._id}/invite`, {
const response = await inviter.post(`/groups/${group._id}/invite`, {
usernames: [userToInvite.auth.local.lowerCaseUsername],
})).to.eventually.deep.equal([{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
}]);
});
expect(response).to.be.an('Array');
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[0]._id).to.be.a('String');
expect(response[0].id).to.eql(group._id);
expect(response[0].name).to.eql(groupName);
expect(response[0].inviter).to.eql(inviter._id);
await expect(userToInvite.get('/user'))
.to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
.to.eventually.have.nested.property('invitations.parties[0].id', group._id);
});
it('invites multiple users to a group by uuid', async () => {
const userToInvite = await generateUser();
const userToInvite2 = await generateUser();
await expect(inviter.post(`/groups/${group._id}/invite`, {
const response = await (inviter.post(`/groups/${group._id}/invite`, {
usernames: [
userToInvite.auth.local.lowerCaseUsername,
userToInvite2.auth.local.lowerCaseUsername,
],
})).to.eventually.deep.equal([
{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
},
{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
},
]);
}));
expect(response).to.be.an('Array');
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[0]._id).to.be.a('String');
expect(response[0].id).to.eql(group._id);
expect(response[0].name).to.eql(groupName);
expect(response[0].inviter).to.eql(inviter._id);
expect(response[1]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[1]._id).to.be.a('String');
expect(response[1].id).to.eql(group._id);
expect(response[1].name).to.eql(groupName);
expect(response[1].inviter).to.eql(inviter._id);
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.parties[0].id', group._id);
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.parties[0].id', group._id);
});
});
describe('user id invites', () => {
it('returns an error when inviter has no chat privileges', async () => {
const inviterMuted = await inviter.update({ 'flags.chatRevoked': true });
const inviterMuted = await inviter.updateOne({ 'flags.chatRevoked': true });
const userToInvite = await generateUser();
await expect(inviterMuted.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
@@ -198,7 +197,7 @@ describe('Post /groups/:groupId/invite', () => {
});
it('returns error when recipient has blocked the senders', async () => {
const inviterNoBlocks = await inviter.update({ 'inbox.blocks': [] });
const inviterNoBlocks = await inviter.updateOne({ 'inbox.blocks': [] });
const userWithBlockedInviter = await generateUser({ 'inbox.blocks': [inviter._id] });
await expect(inviterNoBlocks.post(`/groups/${group._id}/invite`, {
uuids: [userWithBlockedInviter._id],
@@ -213,42 +212,42 @@ describe('Post /groups/:groupId/invite', () => {
it('invites a user to a group by uuid', async () => {
const userToInvite = await generateUser();
await expect(inviter.post(`/groups/${group._id}/invite`, {
const response = await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
})).to.eventually.deep.equal([{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
}]);
});
expect(response).to.be.an('Array');
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[0]._id).to.be.a('String');
expect(response[0].id).to.eql(group._id);
expect(response[0].name).to.eql(groupName);
expect(response[0].inviter).to.eql(inviter._id);
await expect(userToInvite.get('/user'))
.to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
.to.eventually.have.nested.property('invitations.parties[0].id', group._id);
});
it('invites multiple users to a group by uuid', async () => {
const userToInvite = await generateUser();
const userToInvite2 = await generateUser();
await expect(inviter.post(`/groups/${group._id}/invite`, {
const response = await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id, userToInvite2._id],
})).to.eventually.deep.equal([
{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
},
{
id: group._id,
name: groupName,
inviter: inviter._id,
publicGuild: false,
},
]);
});
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
expect(response).to.be.an('Array');
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[0]._id).to.be.a('String');
expect(response[0].id).to.eql(group._id);
expect(response[0].name).to.eql(groupName);
expect(response[0].inviter).to.eql(inviter._id);
expect(response[1]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
expect(response[1]._id).to.be.a('String');
expect(response[1].id).to.eql(group._id);
expect(response[1].name).to.eql(groupName);
expect(response[1].inviter).to.eql(inviter._id);
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.parties[0].id', group._id);
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.parties[0].id', group._id);
});
it('returns an error when inviting multiple users and a user is not found', async () => {
@@ -270,7 +269,7 @@ describe('Post /groups/:groupId/invite', () => {
const testInvite = { name: 'test', email: 'test@habitica.com' };
it('returns an error when inviter has no chat privileges', async () => {
const inviterMuted = await inviter.update({ 'flags.chatRevoked': true });
const inviterMuted = await inviter.updateOne({ 'flags.chatRevoked': true });
await expect(inviterMuted.post(`/groups/${group._id}/invite`, {
emails: [testInvite],
inviter: 'inviter name',
@@ -337,12 +336,8 @@ describe('Post /groups/:groupId/invite', () => {
invitesSent: MAX_EMAIL_INVITES_BY_USER,
balance: 4,
});
const tmpGroup = await inviterWithMax.post('/groups', {
name: groupName,
type: 'guild',
});
await expect(inviterWithMax.post(`/groups/${tmpGroup._id}/invite`, {
await expect(inviterWithMax.post(`/groups/${group._id}/invite`, {
emails: [testInvite],
inviter: 'inviter name',
}))
@@ -418,15 +413,15 @@ describe('Post /groups/:groupId/invite', () => {
});
const invitedUser = await newUser.get('/user');
expect(invitedUser.invitations.guilds[0].id).to.equal(group._id);
expect(invitedUser.invitations.parties[0].id).to.equal(group._id);
expect(invite).to.exist;
});
it('invites marks invite with cancelled plan', async () => {
const cancelledPlanGroup = await generateGroup(inviter, {
type: 'guild',
name: generateUUID(),
});
it('invites user to group with cancelled plan', async () => {
let cancelledPlanGroup;
({ group: cancelledPlanGroup, groupLeader: inviter } = await createAndPopulateGroup({
upgradeToGroupPlan: true,
}));
await cancelledPlanGroup.createCancelledSubscription();
const newUser = await generateUser();
@@ -436,15 +431,15 @@ describe('Post /groups/:groupId/invite', () => {
});
const invitedUser = await newUser.get('/user');
expect(invitedUser.invitations.guilds[0].id).to.equal(cancelledPlanGroup._id);
expect(invitedUser.invitations.guilds[0].cancelledPlan).to.be.true;
expect(invitedUser.invitations.parties[0].id).to.equal(cancelledPlanGroup._id);
expect(invitedUser.invitations.parties[0].cancelledPlan).to.be.true;
expect(invite).to.exist;
});
});
describe('guild invites', () => {
describe('party invites', () => {
it('returns an error when inviter has no chat privileges', async () => {
const inviterMuted = await inviter.update({ 'flags.chatRevoked': true });
const inviterMuted = await inviter.updateOne({ 'flags.chatRevoked': true });
const userToInvite = await generateUser();
await expect(inviterMuted.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
@@ -456,103 +451,13 @@ describe('Post /groups/:groupId/invite', () => {
});
});
it('returns an error when invited user is already invited to the group', async () => {
const userToInvite = await generateUser();
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
});
await expect(inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('userAlreadyInvitedToGroup', { userId: userToInvite._id, username: userToInvite.profile.name }),
});
});
it('returns an error when invited user is already in the group', async () => {
const userToInvite = await generateUser();
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
});
await userToInvite.post(`/groups/${group._id}/join`);
await expect(inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('userAlreadyInGroup', { userId: userToInvite._id, username: userToInvite.profile.name }),
});
});
it('allows 30+ members in a guild', async () => {
const invitesToGenerate = [];
// Generate 30 users to invite (30 + leader = 31 members)
for (let i = 0; i < PARTY_LIMIT_MEMBERS; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate);
// Invite users
expect(await inviter.post(`/groups/${group._id}/invite`, {
uuids: generatedInvites.map(invite => invite._id),
})).to.be.an('array');
}).timeout(10000);
// @TODO: Add this after we are able to mock the group plan route
xit('returns an error when a non-leader invites to a group plan', async () => {
const userToInvite = await generateUser();
const nonGroupLeader = await generateUser();
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [nonGroupLeader._id],
});
await nonGroupLeader.post(`/groups/${group._id}/join`);
await expect(nonGroupLeader.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('onlyGroupLeaderCanInviteToGroupPlan'),
});
});
});
describe('party invites', () => {
let party;
beforeEach(async () => {
party = await inviter.post('/groups', {
name: 'Test Party',
type: 'party',
});
});
it('returns an error when inviter has no chat privileges', async () => {
const inviterMuted = await inviter.update({ 'flags.chatRevoked': true });
const userToInvite = await generateUser();
await expect(inviterMuted.post(`/groups/${party._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('chatPrivilegesRevoked'),
});
});
it('returns an error when invited user has a pending invitation to the party', async () => {
const userToInvite = await generateUser();
await inviter.post(`/groups/${party._id}/invite`, {
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
});
await expect(inviter.post(`/groups/${party._id}/invite`, {
await expect(inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
@@ -565,13 +470,13 @@ describe('Post /groups/:groupId/invite', () => {
it('returns an error when invited user is already in a party of more than 1 member', async () => {
const userToInvite = await generateUser();
const userToInvite2 = await generateUser();
await inviter.post(`/groups/${party._id}/invite`, {
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id, userToInvite2._id],
});
await userToInvite.post(`/groups/${party._id}/join`);
await userToInvite2.post(`/groups/${party._id}/join`);
await userToInvite.post(`/groups/${group._id}/join`);
await userToInvite2.post(`/groups/${group._id}/join`);
await expect(inviter.post(`/groups/${party._id}/invite`, {
await expect(inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
}))
.to.eventually.be.rejected.and.eql({
@@ -581,20 +486,7 @@ describe('Post /groups/:groupId/invite', () => {
});
});
it('allow inviting a user to a party if they are partying solo', async () => {
const userToInvite = await generateUser();
await userToInvite.post('/groups', { // add user to a party
name: 'Another Test Party',
type: 'party',
});
await inviter.post(`/groups/${party._id}/invite`, {
uuids: [userToInvite._id],
});
expect((await userToInvite.get('/user')).invitations.parties[0].id).to.equal(party._id);
});
it('allow inviting a user to 2 different parties', async () => {
it('allows inviting a user to 2 different parties', async () => {
// Create another inviter
const inviter2 = await generateUser();
@@ -608,7 +500,7 @@ describe('Post /groups/:groupId/invite', () => {
});
// Invite to first party
await inviter.post(`/groups/${party._id}/invite`, {
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
});
@@ -621,49 +513,65 @@ describe('Post /groups/:groupId/invite', () => {
const invitedUser = await userToInvite.get('/user');
expect(invitedUser.invitations.parties.length).to.equal(2);
expect(invitedUser.invitations.parties[0].id).to.equal(party._id);
expect(invitedUser.invitations.parties[0].id).to.equal(group._id);
expect(invitedUser.invitations.parties[1].id).to.equal(party2._id);
});
it('allow inviting a user if party id is not associated with a real party', async () => {
it('allows inviting a user if party id is not associated with a real party', async () => {
const userToInvite = await generateUser({
party: { _id: generateUUID() },
});
await inviter.post(`/groups/${party._id}/invite`, {
await inviter.post(`/groups/${group._id}/invite`, {
uuids: [userToInvite._id],
});
expect((await userToInvite.get('/user')).invitations.parties[0].id).to.equal(party._id);
expect((await userToInvite.get('/user')).invitations.parties[0].id).to.equal(group._id);
});
});
describe('party size limits', () => {
let partyLeader;
beforeEach(async () => {
({ group, groupLeader: partyLeader } = await createAndPopulateGroup({
groupDetails: {
name: 'Test Party',
type: 'party',
privacy: 'private',
},
// Generate party with 20 members
members: PARTY_LIMIT_MEMBERS - 10,
}));
});
it('allows 30 members in a party', async () => {
const invitesToGenerate = [];
// Generate 29 users to invite (29 + leader = 30 members)
for (let i = 0; i < PARTY_LIMIT_MEMBERS - 1; i += 1) {
// Generate 10 new invites
for (let i = 1; i < 10; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate);
// Invite users
expect(await inviter.post(`/groups/${party._id}/invite`, {
expect(await partyLeader.post(`/groups/${group._id}/invite`, {
uuids: generatedInvites.map(invite => invite._id),
})).to.be.an('array');
}).timeout(10000);
it('does not allow 30+ members in a party', async () => {
it('does not allow >30 members in a party', async () => {
const invitesToGenerate = [];
// Generate 30 users to invite (30 + leader = 31 members)
for (let i = 0; i < PARTY_LIMIT_MEMBERS; i += 1) {
// Generate 11 invites
for (let i = 1; i < 11; i += 1) {
invitesToGenerate.push(generateUser());
}
const generatedInvites = await Promise.all(invitesToGenerate);
// Invite users
await expect(inviter.post(`/groups/${party._id}/invite`, {
await expect(partyLeader.post(`/groups/${group._id}/invite`, {
uuids: generatedInvites.map(invite => invite._id),
}))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('partyExceedsMembersLimit', { maxMembersParty: PARTY_LIMIT_MEMBERS + 1 }),
message: t('partyExceedsMembersLimit', { maxMembersParty: PARTY_LIMIT_MEMBERS }),
});
}).timeout(10000);
});

View File

@@ -17,9 +17,10 @@ describe('POST /group/:groupId/add-manager', () => {
groupDetails: {
name: groupName,
type: groupType,
privacy: 'public',
privacy: 'private',
},
members: 1,
upgradeToGroupPlan: true,
});
groupToUpdate = group;

View File

@@ -23,10 +23,11 @@ describe('PUT /group', () => {
groupDetails: {
name: groupName,
type: groupType,
privacy: 'public',
privacy: 'private',
categories: groupCategories,
},
members: 1,
upgradeToGroupPlan: true,
});
adminUser = await generateUser({ 'permissions.moderator': true });
groupToUpdate = group;
@@ -106,14 +107,28 @@ describe('PUT /group', () => {
expect(updatedGroup.name).to.equal(groupUpdatedName);
});
it('allows a leader to change leaders', async () => {
const updatedGroup = await leader.put(`/groups/${groupToUpdate._id}`, {
it('does not allow a leader to change leader of active group plan', async () => {
await expect(leader.put(`/groups/${groupToUpdate._id}`, {
name: groupUpdatedName,
leader: nonLeader._id,
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('cannotChangeLeaderWithActiveGroupPlan'),
});
});
it('allows a leader of a party to change leaders', async () => {
const { group: party, groupLeader: partyLeader, members } = await createAndPopulateGroup({
members: 1,
});
const updatedGroup = await partyLeader.put(`/groups/${party._id}`, {
name: groupUpdatedName,
leader: members[0]._id,
});
expect(updatedGroup.leader._id).to.eql(nonLeader._id);
expect(updatedGroup.leader.profile.name).to.eql(nonLeader.profile.name);
expect(updatedGroup.leader._id).to.eql(members[0]._id);
expect(updatedGroup.leader.profile.name).to.eql(members[0].profile.name);
expect(updatedGroup.name).to.equal(groupUpdatedName);
});
@@ -122,15 +137,16 @@ describe('PUT /group', () => {
groupDetails: {
name: 'public guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
upgradeToGroupPlan: true,
});
const updateGroupDetails = {
id: group._id,
name: 'public guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
bannedWordsAllowed: true,
};
@@ -150,9 +166,11 @@ describe('PUT /group', () => {
groupDetails: {
name: 'public guild',
type: 'guild',
privacy: 'public',
privacy: 'private',
},
upgradeToGroupPlan: true,
});
await groupLeader.updateOne({ permissions: {} });
const updateGroupDetails = {
id: group._id,

View File

@@ -9,7 +9,7 @@ describe('GET /heroes/:heroId', () => {
const heroFields = [
'_id', 'id', 'auth', 'balance', 'contributor', 'flags', 'items',
'lastCron', 'party', 'preferences', 'profile', 'purchased', 'secret',
'lastCron', 'party', 'preferences', 'profile', 'purchased', 'secret', 'achievements',
];
before(async () => {

View File

@@ -10,7 +10,7 @@ describe('PUT /heroes/:heroId', () => {
const heroFields = [
'_id', 'auth', 'balance', 'contributor', 'flags', 'items', 'lastCron',
'party', 'preferences', 'profile', 'purchased', 'secret', 'permissions',
'party', 'preferences', 'profile', 'purchased', 'secret', 'permissions', 'achievements',
];
before(async () => {
@@ -251,4 +251,159 @@ describe('PUT /heroes/:heroId', () => {
expect(updatedHero.apiToken).to.not.equal(originalToken);
expect(updatedHero.apiTokenObscured).to.not.exist;
});
it('updates purchased hair customization', async () => {
const hero = await generateUser();
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
purchasedPath: 'purchased.hair.bangs.1',
purchasedVal: true,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.purchased.hair.bangs['1']).to.equal(true);
// test hero values
await hero.sync();
expect(hero.purchased.hair.bangs['1']).to.equal(true);
});
it('updates purchased customization', async () => {
const hero = await generateUser();
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
purchasedPath: 'purchased.background.beach',
purchasedVal: true,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.purchased.background.beach).to.equal(true);
// test hero values
await hero.sync();
expect(hero.purchased.background.beach).to.equal(true);
});
it('updates giving nested achievement', async () => {
const hero = await generateUser();
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.quests.dilatory',
achievementVal: 2,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.quests.dilatory).to.equal(2);
// test hero values
await hero.sync();
expect(hero.achievements.quests.dilatory).to.equal(2);
});
it('updates taking away nested achievement', async () => {
const hero = await generateUser({ 'achievements.quests.dilatory': 3 });
expect(hero.achievements.quests.dilatory).to.equal(3);
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.quests.dilatory',
achievementVal: 0,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.quests.dilatory).to.equal(0);
// test hero values
await hero.sync();
expect(hero.achievements.quests.dilatory).to.equal(0);
});
it('updates giving achievement', async () => {
const hero = await generateUser();
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.partyOn',
achievementVal: true,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.partyOn).to.equal(true);
// test hero values
await hero.sync();
expect(hero.achievements.partyOn).to.equal(true);
});
it('updates taking away achievement', async () => {
const hero = await generateUser({ 'achievements.partyUp': true });
expect(hero.achievements.partyUp).to.equal(true);
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.partyUp',
achievementVal: false,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.partyUp).to.equal(false);
// test hero values
await hero.sync();
expect(hero.achievements.partyUp).to.equal(false);
});
it('updates giving numbered achievement', async () => {
const hero = await generateUser();
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.streak',
achievementVal: 42,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.streak).to.equal(42);
// test hero values
await hero.sync();
expect(hero.achievements.streak).to.equal(42);
});
it('updates setting numbered achievement to 0', async () => {
const hero = await generateUser({ 'achievements.streak': 42 });
expect(hero.achievements.streak).to.equal(42);
const heroRes = await user.put(`/hall/heroes/${hero._id}`, {
achievementPath: 'achievements.streak',
achievementVal: 0,
});
// test response
expect(heroRes).to.have.all.keys(heroFields);
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.achievements.streak).to.equal(0);
// test hero values
await hero.sync();
expect(hero.achievements.streak).to.equal(0);
});
});

View File

@@ -0,0 +1,64 @@
import { v4 as generateUUID } from 'uuid';
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /members/:memberId/clear-flags', () => {
let reporter;
let admin;
let moderator;
beforeEach(async () => {
reporter = await generateUser();
admin = await generateUser({ permissions: { userSupport: true } });
moderator = await generateUser({ permissions: { moderator: true } });
await reporter.post(`/members/${admin._id}/flag`);
});
context('error cases', () => {
it('returns error when memberId is not a UUID', async () => {
await expect(moderator.post('/members/gribbly/clear-flags'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
it('returns error when member with UUID is not found', async () => {
const randomId = generateUUID();
await expect(moderator.post(`/members/${randomId}/clear-flags`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('userWithIDNotFound', { userId: randomId }),
});
});
it('returns error when requesting user is not a moderator', async () => {
await expect(reporter.post(`/members/${admin._id}/clear-flags`))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'Only a moderator may clear reports from a profile.',
});
});
});
context('valid request', () => {
it('removes a single flag from user', async () => {
await expect(moderator.post(`/members/${admin._id}/clear-flags`)).to.eventually.be.ok;
const updatedTarget = await admin.get(`/hall/heroes/${admin._id}`);
expect(updatedTarget.profile.flags).to.eql({});
});
it('removes multiple flags from user', async () => {
await moderator.post(`/members/${admin._id}/flag`);
await expect(moderator.post(`/members/${admin._id}/clear-flags`)).to.eventually.be.ok;
const updatedTarget = await admin.get(`/hall/heroes/${admin._id}`);
expect(updatedTarget.profile.flags).to.eql({});
});
});
});

View File

@@ -0,0 +1,149 @@
import { v4 as generateUUID } from 'uuid';
import moment from 'moment';
import nconf from 'nconf';
import { IncomingWebhook } from '@slack/webhook';
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /members/:memberId/flag', () => {
let reporter;
let target;
beforeEach(async () => {
reporter = await generateUser();
target = await generateUser({
'profile.blurb': 'Naughty Text',
'profile.imageUrl': 'https://evil.com/',
});
});
context('error cases', () => {
it('returns error when memberId is not a UUID', async () => {
await expect(reporter.post('/members/gribbly/flag'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
it('returns error when member with UUID is not found', async () => {
const randomId = generateUUID();
await expect(reporter.post(`/members/${randomId}/flag`))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('userWithIDNotFound', { userId: randomId }),
});
});
it('returns error when non-admin flags same profile twice', async () => {
await reporter.post(`/members/${target._id}/flag`);
await expect(reporter.post(`/members/${target._id}/flag`))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'A profile can not be flagged more than once by the same user.',
});
});
});
context('valid request', () => {
let admin;
const comment = 'this profile is bad';
const source = 'Third Party Script';
beforeEach(async () => {
admin = await generateUser({ 'permissions.userSupport': true });
sandbox.stub(IncomingWebhook.prototype, 'send').returns(Promise.resolve());
});
afterEach(() => {
sandbox.restore();
});
it('adds flags object to target user', async () => {
await reporter.post(`/members/${target._id}/flag`);
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
expect(updatedTarget.profile.flags[reporter._id]).to.have.all.keys([
'timestamp',
]);
expect(moment(updatedTarget.profile.flags[reporter._id].timestamp).toDate()).to.be.a('date');
});
it('allows addition of a comment and source', async () => {
await reporter.post(`/members/${target._id}/flag`, {
comment,
source,
});
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
expect(updatedTarget.profile.flags[reporter._id].comment).to.eql(comment);
expect(updatedTarget.profile.flags[reporter._id].source).to.eql(source);
});
it('allows moderator to flag twice', async () => {
const moderator = await generateUser({ 'permissions.moderator': true });
await moderator.post(`/members/${target._id}/flag`);
await expect(moderator.post(`/members/${target._id}/flag`)).to.eventually.be.ok;
});
it('allows multiple non-moderators to flag individually', async () => {
await admin.post(`/members/${target._id}/flag`);
await reporter.post(`/members/${target._id}/flag`);
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
expect(updatedTarget.profile.flags[admin._id]).to.exist;
expect(updatedTarget.profile.flags[reporter._id]).to.exist;
});
it('sends a flag report to moderation Slack', async () => {
const BASE_URL = nconf.get('BASE_URL');
await reporter.post(`/members/${target._id}/flag`, {
comment,
source,
});
/* eslint-disable camelcase */
expect(IncomingWebhook.prototype.send).to.be.calledWith({
text: `@${reporter.auth.local.username} (${reporter._id}; language: ${reporter.preferences.language}) flagged @${target.auth.local.username}'s profile from ${source} and commented: ${comment}`,
attachments: [{
fallback: 'Flag Profile',
color: 'danger',
title: 'User Profile Report',
title_link: `${BASE_URL}/profile/${target._id}`,
text: `Display Name: ${target.profile.name}\n\nImage URL: ${target.profile.imageUrl}\n\nAbout: ${target.profile.blurb}`,
mrkdwn_in: [
'text',
],
}],
});
/* eslint-enable camelcase */
});
it('excludes empty fields when sending Slack message', async () => {
const BASE_URL = nconf.get('BASE_URL');
await reporter.post(`/members/${admin._id}/flag`, {
comment,
source,
});
/* eslint-disable camelcase */
expect(IncomingWebhook.prototype.send).to.be.calledWith({
text: `@${reporter.auth.local.username} (${reporter._id}; language: ${reporter.preferences.language}) flagged @${admin.auth.local.username}'s profile from ${source} and commented: ${comment}`,
attachments: [{
fallback: 'Flag Profile',
color: 'danger',
title: 'User Profile Report',
title_link: `${BASE_URL}/profile/${admin._id}`,
text: `Display Name: ${admin.profile.name}`,
mrkdwn_in: [
'text',
],
}],
});
/* eslint-enable camelcase */
});
});
});

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