Compare commits

...

41 Commits

Author SHA1 Message Date
Phillip Thelen
c46bc2b0e5 Disable Amplitude on client for dev environment 2024-01-22 13:48:48 +01: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
451 changed files with 10717 additions and 18171 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

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

@@ -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

@@ -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

@@ -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

@@ -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));
}

4270
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "5.13.0",
"version": "5.16.1",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.22.10",
@@ -24,8 +24,8 @@
"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",
@@ -36,11 +36,9 @@
"gulp-babel": "^8.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-nodemon": "^2.5.0",
"nodemon": "^2.0.20",
"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": "^9.0.2",
@@ -50,10 +48,11 @@
"method-override": "^3.0.0",
"moment": "^2.29.4",
"moment-recur": "^1.0.7",
"mongoose": "^5.13.20",
"mongoose": "^7.6.3",
"morgan": "^1.10.0",
"nconf": "^0.12.1",
"node-gcm": "^1.0.5",
"nodemon": "^2.0.20",
"on-headers": "^1.0.2",
"passport": "^0.5.3",
"passport-facebook": "^3.0.0",
@@ -64,7 +63,6 @@
"ps-tree": "^1.0.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",
@@ -74,7 +72,6 @@
"useragent": "^2.1.9",
"uuid": "^9.0.0",
"validator": "^13.11.0",
"vinyl-buffer": "^1.0.1",
"winston": "^3.10.0",
"winston-loggly-bulk": "^3.3.0",
"xml2js": "^0.6.2"
@@ -106,7 +103,7 @@
"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"
},

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

@@ -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

@@ -1382,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');
});
});
});
@@ -1599,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,7 +229,7 @@ describe('cron middleware', () => {
await user.save();
const updatedUser = user.toObject();
updatedUser.nMatched = 0;
updatedUser.matchedCount = 0;
sandbox.spy(cronLib, 'recoverCron');
@@ -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;
});
});

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

@@ -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

@@ -186,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 });
@@ -269,7 +269,7 @@ describe('GET challenges/groups/:groupId', () => {
let officialChallenge; let unofficialChallenges;
before(async () => {
await user.update({
await user.updateOne({
'permissions.challengeAdmin': true,
balance: 3,
});

View File

@@ -68,7 +68,7 @@ describe('GET challenges/user', () => {
challenge = await generateChallenge(user, group);
challenge2 = await generateChallenge(user, group);
await user.update({ balance: 0.25 });
await user.updateOne({ balance: 0.25 });
publicChallenge = await generateChallenge(user, tavern, { prize: 1 });
await member.post(`/challenges/${challenge._id}/join`);
@@ -234,7 +234,7 @@ describe('GET challenges/user', () => {
upgradeToGroupPlan: true,
}));
await user.update({
await user.updateOne({
'permissions.challengeAdmin': true,
});
@@ -308,7 +308,7 @@ describe('GET challenges/user', () => {
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

@@ -41,7 +41,7 @@ describe('POST /challenges/:challengeId/flag', () => {
});
it('flags a challenge with a higher count when from an admin', async () => {
await user.update({ 'contributor.admin': true });
await user.updateOne({ 'contributor.admin': true });
const flagResult = await user.post(`/challenges/${challenge._id}/flag`);

View File

@@ -23,7 +23,7 @@ describe('POST /challenges/:challengeId/clearflags', () => {
admin = groupLeader;
[nonAdmin] = members;
await admin.update({ 'permissions.moderator': true });
await admin.updateOne({ 'permissions.moderator': true });
challenge = await generateChallenge(admin, group);
await admin.post(`/challenges/${challenge._id}/flag`);

View File

@@ -79,7 +79,7 @@ describe('POST /challenges', () => {
});
groupLeader = await populatedGroup.groupLeader.sync();
await groupLeader.update({ permissions: {} });
await groupLeader.updateOne({ permissions: {} });
group = populatedGroup.group;
groupMember = populatedGroup.members[0]; // eslint-disable-line prefer-destructuring
});
@@ -177,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',
@@ -202,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

@@ -28,7 +28,7 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
message = message.message;
userThatDidNotCreateChat = members[0]; // eslint-disable-line prefer-destructuring
admin = members[1]; // eslint-disable-line prefer-destructuring
await admin.update({ permissions: { moderator: true } });
await admin.updateOne({ permissions: { moderator: true } });
});
context('Chat errors', () => {

View File

@@ -27,11 +27,11 @@ describe('POST /chat/:chatId/flag', () => {
}));
[admin, anotherUser, newUser, userToDelete] = members;
await user.update({ permissions: {} });
await admin.update({ permissions: { moderator: true } });
await anotherUser.update({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
await newUser.update({ 'auth.timestamps.created': moment().subtract(1, 'days').toDate() });
await userToDelete.update({
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(),
});

View File

@@ -27,7 +27,7 @@ describe('POST /chat/:chatId/like', () => {
}));
[anotherUser] = members;
await anotherUser.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await anotherUser.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('Returns an error when chat message is not found', async () => {

View File

@@ -30,14 +30,14 @@ describe('POST /chat', () => {
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, additionalMember] = members;
await member.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await additionalMember.update({ 'auth.timestamps.created': new Date('2022-01-01') });
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 () => {
@@ -77,11 +77,11 @@ describe('POST /chat', () => {
describe('mute user', () => {
afterEach(() => {
member.update({ 'flags.chatRevoked': false });
member.updateOne({ 'flags.chatRevoked': false });
});
it('does not error when chat privileges are revoked when sending a message to a private guild', async () => {
await member.update({
await member.updateOne({
'flags.chatRevoked': true,
});
@@ -101,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'),
});
@@ -120,11 +120,11 @@ describe('POST /chat', () => {
afterEach(() => {
sandbox.restore();
member.update({ 'flags.chatShadowMuted': false });
member.updateOne({ 'flags.chatShadowMuted': false });
});
it('creates a chat with zero flagCount when sending a message to a private guild', async () => {
await member.update({
await member.updateOne({
'flags.chatShadowMuted': true,
});
@@ -145,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'),
});
@@ -167,7 +167,7 @@ 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: testBannedWordMessage });
@@ -189,7 +189,7 @@ describe('POST /chat', () => {
afterEach(() => {
sandbox.restore();
user.update({ 'flags.chatRevoked': false });
user.updateOne({ 'flags.chatRevoked': false });
});
it('allows slurs in private groups', async () => {
@@ -201,7 +201,7 @@ 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 });
@@ -210,14 +210,14 @@ describe('POST /chat', () => {
});
it('errors when user account is too young', async () => {
await user.update({ 'auth.timestamps.created': new Date() });
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.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await user.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('creates a chat', async () => {
@@ -258,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.`;
@@ -278,7 +278,7 @@ describe('POST /chat', () => {
const mount = 'test-mount';
const pet = 'test-pet';
const style = 'test-style';
await user.update({
await user.updateOne({
'items.currentMount': mount,
'items.currentPet': pet,
'preferences.style': style,
@@ -308,7 +308,7 @@ describe('POST /chat', () => {
});
it('creates costume to user styles', async () => {
await user.update({ 'preferences.costume': true });
await user.updateOne({ 'preferences.costume': true });
const message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
@@ -323,7 +323,7 @@ describe('POST /chat', () => {
tier: 800,
tokensApplied: true,
};
await user.update({
await user.updateOne({
backer: backerInfo,
});
@@ -375,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 () => {

View File

@@ -28,8 +28,8 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
groupWithChat = group;
author = groupLeader;
[nonAdmin, admin] = members;
await nonAdmin.update({ 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate() });
await admin.update({ 'permissions.moderator': true });
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;
@@ -71,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;
@@ -104,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

@@ -37,7 +37,7 @@ describe('GET /groups', () => {
upgradeToGroupPlan: true,
}));
[user] = members;
await user.update({ balance: 4 });
await user.updateOne({ balance: 4 });
({ group: secondGroup, groupLeader: secondLeader } = await createAndPopulateGroup({
groupDetails: {

View File

@@ -153,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()],
});
@@ -173,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 },
});
@@ -290,7 +290,7 @@ describe('GET /groups/:id', () => {
beforeEach(async () => {
[admin] = members;
await admin.update({ permissions: { moderator: true } });
await admin.updateOne({ permissions: { moderator: true } });
});
it('includes all messages', async () => {

View File

@@ -110,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,
@@ -120,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

@@ -78,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`);
@@ -146,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);
@@ -193,7 +193,7 @@ 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`);
@@ -201,7 +201,7 @@ describe('POST /group/:groupId/join', () => {
});
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

@@ -30,7 +30,7 @@ describe('POST /groups/:groupId/leave', () => {
[member] = members;
memberCount = groupToLeave.memberCount;
await leader.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await leader.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('prevents non members from leaving', async () => {
@@ -135,7 +135,7 @@ describe('POST /groups/:groupId/leave', () => {
[member] = members;
[invitedUser] = invitees;
memberCount = groupToLeave.memberCount;
await leader.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await leader.updateOne({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('prevents non members from leaving', async () => {
@@ -317,7 +317,7 @@ describe('POST /groups/:groupId/leave', () => {
upgradeToGroupPlan: true,
}));
[member] = members;
await member.update({
await member.updateOne({
'purchased.plan.extraMonths': extraMonths,
});
});

View File

@@ -212,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,
});
@@ -234,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`);
@@ -257,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

@@ -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],
@@ -107,7 +107,7 @@ describe('Post /groups/:groupId/invite', () => {
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],
@@ -197,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],
@@ -269,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',
@@ -439,7 +439,7 @@ describe('Post /groups/:groupId/invite', () => {
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],

View File

@@ -170,7 +170,7 @@ describe('PUT /group', () => {
},
upgradeToGroupPlan: true,
});
await groupLeader.update({ permissions: {} });
await groupLeader.updateOne({ permissions: {} });
const updateGroupDetails = {
id: group._id,

View File

@@ -69,8 +69,6 @@ describe('POST /members/:memberId/flag', () => {
await reporter.post(`/members/${target._id}/flag`);
const updatedTarget = await admin.get(`/hall/heroes/${target._id}`);
expect(updatedTarget.profile.flags[reporter._id]).to.have.all.keys([
'comment',
'source',
'timestamp',
]);
expect(moment(updatedTarget.profile.flags[reporter._id].timestamp).toDate()).to.be.a('date');

View File

@@ -181,7 +181,8 @@ describe('POST /members/transfer-gems', () => {
const updatedSender = await userToSendMessage.get('/user');
const sendersMessageInReceiversInbox = findMessage(
updatedReceiver.inbox.messages, userToSendMessage._id,
updatedReceiver.inbox.messages,
userToSendMessage._id,
);
const sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);
@@ -212,7 +213,8 @@ describe('POST /members/transfer-gems', () => {
const updatedSender = await userToSendMessage.get('/user');
const sendersMessageInReceiversInbox = findMessage(
updatedReceiver.inbox.messages, userToSendMessage._id,
updatedReceiver.inbox.messages,
userToSendMessage._id,
);
const sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);
@@ -233,10 +235,10 @@ describe('POST /members/transfer-gems', () => {
});
it('sends transfer gems message in each participant\'s language', async () => {
await receiver.update({
await receiver.updateOne({
'preferences.language': 'es',
});
await userToSendMessage.update({
await userToSendMessage.updateOne({
'preferences.language': 'cs',
});
await userToSendMessage.post('/members/transfer-gems', {
@@ -248,7 +250,8 @@ describe('POST /members/transfer-gems', () => {
const updatedSender = await userToSendMessage.get('/user');
const sendersMessageInReceiversInbox = findMessage(
updatedReceiver.inbox.messages, userToSendMessage._id,
updatedReceiver.inbox.messages,
userToSendMessage._id,
);
const sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);

View File

@@ -27,7 +27,7 @@ describe('POST /notifications/:notificationId/read', () => {
const id = generateUUID();
const id2 = generateUUID();
await user.update({
await user.updateOne({
notifications: [{
id,
type: 'DROPS_ENABLED',

View File

@@ -27,7 +27,7 @@ describe('POST /notifications/:notificationId/see', () => {
const id = generateUUID();
const id2 = generateUUID();
await user.update({
await user.updateOne({
notifications: [{
id,
type: 'DROPS_ENABLED',

View File

@@ -30,7 +30,7 @@ describe('POST /notifications/read', () => {
const id2 = generateUUID();
const id3 = generateUUID();
await user.update({
await user.updateOne({
notifications: [{
id,
type: 'DROPS_ENABLED',

View File

@@ -30,7 +30,7 @@ describe('POST /notifications/see', () => {
const id2 = generateUUID();
const id3 = generateUUID();
await user.update({
await user.updateOne({
notifications: [{
id,
type: 'DROPS_ENABLED',

View File

@@ -25,7 +25,7 @@ describe('Prevent multiple notifications', () => {
for (let i = 0; i < 4; i += 1) {
for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex += 1) {
await partyMembers[memberIndex].update({ 'auth.timestamps.created': new Date('2022-01-01') }); // eslint-disable-line no-await-in-loop
await partyMembers[memberIndex].updateOne({ 'auth.timestamps.created': new Date('2022-01-01') }); // eslint-disable-line no-await-in-loop
multipleChatMessages.push(
partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}` }),
);

View File

@@ -26,7 +26,7 @@ describe('POST /groups/:groupId/quests/accept', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
});

View File

@@ -23,7 +23,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
});
@@ -93,7 +93,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
context('successfully force starting a quest', () => {
it('allows quest leader to force start quest', async () => {
const questLeader = partyMembers[0];
await questLeader.update({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.updateOne({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
await questLeader.post(`/groups/${questingGroup._id}/quests/force-start`);
@@ -105,7 +105,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
it('allows group leader to force start quest', async () => {
const questLeader = partyMembers[0];
await questLeader.update({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.updateOne({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
await leader.post(`/groups/${questingGroup._id}/quests/force-start`);
@@ -177,7 +177,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
const notInPartyUser = await generateUser();
await questingGroup.update({
await questingGroup.updateOne({
[`quest.members.${notInPartyUser._id}`]: true,
});
await questingGroup.sync();
@@ -217,7 +217,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
await questingGroup.update({
await questingGroup.updateOne({
[`quest.members.${partyMemberThatRejects._id}`]: false,
[`quest.members.${partyMemberThatIgnores._id}`]: null,
});
@@ -236,7 +236,7 @@ describe('POST /groups/:groupId/quests/force-start', () => {
it('allows group leader to force start quest and verifies chat', async () => {
const questLeader = partyMembers[0];
await questLeader.update({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.updateOne({ [`items.quests.${PET_QUEST}`]: 1 });
await questLeader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
await leader.post(`/groups/${questingGroup._id}/quests/force-start`);

View File

@@ -87,8 +87,8 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
const leaderUpdate = {};
leaderUpdate[`items.quests.${PET_QUEST}`] = 1;
await leader.update(leaderUpdate);
await questingGroup.update({ 'quest.key': QUEST_IN_PROGRESS });
await leader.updateOne(leaderUpdate);
await questingGroup.updateOne({ 'quest.key': QUEST_IN_PROGRESS });
await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({
code: 401,
@@ -104,8 +104,8 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
memberUpdate[`items.quests.${PET_QUEST}`] = 1;
await Promise.all([
leader.update(memberUpdate),
member.update(memberUpdate),
leader.updateOne(memberUpdate),
member.updateOne(memberUpdate),
]);
});
@@ -202,7 +202,7 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
leaderUpdate[`items.quests.${LEVELED_QUEST}`] = 1;
leaderUpdate['stats.lvl'] = LEVELED_QUEST_REQ - 1;
await leader.update(leaderUpdate);
await leader.updateOne(leaderUpdate);
await leader.post(`/groups/${questingGroup._id}/quests/invite/${LEVELED_QUEST}`);
});

View File

@@ -24,7 +24,7 @@ describe('POST /groups/:groupId/quests/abort', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
user = await generateUser();

View File

@@ -24,7 +24,7 @@ describe('POST /groups/:groupId/quests/cancel', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
user = await generateUser();

View File

@@ -23,7 +23,7 @@ describe('POST /groups/:groupId/quests/leave', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
user = await generateUser();

View File

@@ -25,7 +25,7 @@ describe('POST /groups/:groupId/quests/reject', () => {
leader = groupLeader;
partyMembers = members;
await leader.update({
await leader.updateOne({
[`items.quests.${PET_QUEST}`]: 1,
});
user = await generateUser();

View File

@@ -27,7 +27,7 @@ describe('GET /shops/market', () => {
});
it('can purchase anything returned from the shops object using the /user/purchase route', async () => {
await user.update({
await user.updateOne({
balance: 99999999,
'stats.gp': 99999999,
});

View File

@@ -39,7 +39,7 @@ describe('GET /shops/time-travelers', () => {
});
it('returns active shop notes and imageName if user has trinkets', async () => {
await user.update({
await user.updateOne({
'purchased.plan.consecutive.trinkets': 1,
});
@@ -57,7 +57,7 @@ describe('GET /shops/time-travelers', () => {
});
it('does not return mystery sets that are already owned', async () => {
await user.update({
await user.updateOne({
'items.gear.owned': {
head_mystery_201606: true, // eslint-disable-line camelcase
armor_mystery_201606: true, // eslint-disable-line camelcase
@@ -72,7 +72,7 @@ describe('GET /shops/time-travelers', () => {
});
it('does not return pets and mounts that user already owns', async () => {
await user.update({
await user.updateOne({
'items.mounts': {
'MantisShrimp-Base': true,
},

View File

@@ -86,7 +86,7 @@ describe('DELETE /tasks/:id', () => {
it('does not send task activity webhooks if task is not user owned', async () => {
const uuid = generateUUID();
await user.update({
await user.updateOne({
balance: 10,
});
const guild = await generateGroup(user);

View File

@@ -154,7 +154,7 @@ describe('GET /tasks/user', () => {
xit('returns dailies with isDue for the date specified and will add CDS offset if time is not supplied and assumes timezones', async () => {
const timezoneOffset = 420;
await user.update({
await user.updateOne({
'preferences.dayStart': 0,
'preferences.timezoneOffset': timezoneOffset,
});
@@ -181,7 +181,7 @@ describe('GET /tasks/user', () => {
xit('returns dailies with isDue for the date specified and will add CDS offset if time is not supplied and assumes timezones', async () => {
const timezoneOffset = 240;
await user.update({
await user.updateOne({
'preferences.dayStart': 0,
'preferences.timezoneOffset': timezoneOffset,
});
@@ -208,7 +208,7 @@ describe('GET /tasks/user', () => {
xit('returns dailies with isDue for the date specified and will add CDS offset if time is not supplied and assumes timezones', async () => {
const timezoneOffset = 540;
await user.update({
await user.updateOne({
'preferences.dayStart': 0,
'preferences.timezoneOffset': timezoneOffset,
});

View File

@@ -106,7 +106,7 @@ describe('POST /tasks/:id/score/:direction', () => {
const initialLvl = user.stats.lvl;
await user.update({
await user.updateOne({
'stats.exp': 3000,
});
const task = await user.post('/tasks/user', {

View File

@@ -104,7 +104,6 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
id: challenge._id,
shortName: challenge.shortName,
broken: 'CHALLENGE_DELETED',
winner: null,
});
});
});

View File

@@ -200,7 +200,7 @@ describe('PUT /tasks/:id', () => {
it('does not send task activity webhooks if task is not user owned', async () => {
const uuid = generateUUID();
await user.update({
await user.updateOne({
balance: 10,
});
const guild = await generateGroup(user);

View File

@@ -48,6 +48,7 @@ describe('DELETE /user', () => {
});
it('deletes the user', async () => {
await expect(checkExistence('users', user._id)).to.eventually.eql(true);
await user.del('/user', {
password,
});
@@ -157,11 +158,12 @@ describe('DELETE /user', () => {
});
it('deletes the user with a legacy sha1 password', async () => {
await expect(checkExistence('users', user._id)).to.eventually.eql(true);
const textPassword = 'mySecretPassword';
const salt = sha1MakeSalt();
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,
@@ -211,6 +213,7 @@ describe('DELETE /user', () => {
});
it('deletes a Google user', async () => {
await expect(checkExistence('users', user._id)).to.eventually.eql(true);
await user.del('/user', {
password: DELETE_CONFIRMATION,
});
@@ -230,6 +233,7 @@ describe('DELETE /user', () => {
});
it('deletes a Apple user', async () => {
await expect(checkExistence('users', user._id)).to.eventually.eql(true);
await user.del('/user', {
password: DELETE_CONFIRMATION,
});

View File

@@ -17,7 +17,7 @@ describe('GET /user/anonymized', () => {
text: 'Clark Kent',
},
});
await user.update({
await user.updateOne({
newMessages: ['some', 'new', 'messages'],
'profile.name': 'profile',
'purchased.plan': 'purchased plan',

View File

@@ -52,7 +52,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
// For this test put seasonal items at the end so they stay out of the way
testPinnedItemsOrder = testPinnedItemsOrder.concat(officialPinnedItemPaths);
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
@@ -96,7 +96,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
'potion',
];
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
@@ -138,7 +138,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
'potion',
];
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
@@ -171,7 +171,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
// add item to pinned
officialPinnedItems.push({ type: 'armoire', path: 'armoire' });
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
@@ -201,7 +201,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
'potion',
];
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});
@@ -225,7 +225,7 @@ describe('POST /user/move-pinned-item/:path/move/to/:position', () => {
'potion',
];
await user.update({
await user.updateOne({
pinnedItems: testPinnedItems,
pinnedItemsOrder: testPinnedItemsOrder,
});

View File

@@ -18,7 +18,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if spell does not exist', async () => {
await user.update({ 'stats.class': 'rogue' });
await user.updateOne({ 'stats.class': 'rogue' });
const spellId = 'invalidSpell';
await expect(user.post(`/user/class/cast/${spellId}`))
.to.eventually.be.rejected.and.eql({
@@ -39,7 +39,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if spell.mana > user.mana', async () => {
await user.update({ 'stats.class': 'rogue' });
await user.updateOne({ 'stats.class': 'rogue' });
await expect(user.post('/user/class/cast/backStab'))
.to.eventually.be.rejected.and.eql({
code: 401,
@@ -58,7 +58,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if use Healing Light spell with full health', async () => {
await user.update({
await user.updateOne({
'stats.class': 'healer',
'stats.lvl': 11,
'stats.hp': 50,
@@ -73,7 +73,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if spell.lvl > user.level', async () => {
await user.update({ 'stats.mp': 200, 'stats.class': 'wizard' });
await user.updateOne({ 'stats.mp': 200, 'stats.class': 'wizard' });
await expect(user.post('/user/class/cast/earth'))
.to.eventually.be.rejected.and.eql({
code: 401,
@@ -101,7 +101,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if targetId is required but missing', async () => {
await user.update({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await user.updateOne({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await expect(user.post('/user/class/cast/pickPocket'))
.to.eventually.be.rejected.and.eql({
code: 400,
@@ -111,7 +111,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if targeted task doesn\'t exist', async () => {
await user.update({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await user.updateOne({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await expect(user.post(`/user/class/cast/pickPocket?targetId=${generateUUID()}`))
.to.eventually.be.rejected.and.eql({
code: 404,
@@ -127,7 +127,7 @@ describe('POST /user/class/cast/:spellId', () => {
await groupLeader.post(`/tasks/challenge/${challenge._id}`, [
{ type: 'habit', text: 'task text' },
]);
await groupLeader.update({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await groupLeader.updateOne({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await sleep(0.5);
await groupLeader.sync();
await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${groupLeader.tasksOrder.habits[0]}`))
@@ -146,7 +146,7 @@ describe('POST /user/class/cast/:spellId', () => {
type: 'todo',
});
await groupLeader.post(`/tasks/${groupTask._id}/assign`, [groupLeader._id]);
await groupLeader.update({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await groupLeader.updateOne({ 'stats.class': 'rogue', 'stats.lvl': 11 });
await sleep(0.5);
await groupLeader.sync();
@@ -159,7 +159,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('Issue #12361: returns an error if stealth has already been cast', async () => {
await user.update({
await user.updateOne({
'stats.class': 'rogue',
'stats.lvl': 15,
'stats.mp': 400,
@@ -180,7 +180,7 @@ describe('POST /user/class/cast/:spellId', () => {
groupDetails: { type: 'party', privacy: 'private' },
members: 1,
});
await groupLeader.update({ 'items.special.snowball': 3 });
await groupLeader.updateOne({ 'items.special.snowball': 3 });
const target = generateUUID();
await expect(groupLeader.post(`/user/class/cast/snowball?targetId=${target}`))
@@ -192,7 +192,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('returns an error if party does not exists', async () => {
await user.update({ 'items.special.snowball': 3 });
await user.updateOne({ 'items.special.snowball': 3 });
await expect(user.post(`/user/class/cast/snowball?targetId=${generateUUID()}`))
.to.eventually.be.rejected.and.eql({
@@ -207,7 +207,7 @@ describe('POST /user/class/cast/:spellId', () => {
groupDetails: { type: 'party', privacy: 'private' },
members: 1,
});
await groupLeader.update({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 13 });
await groupLeader.updateOne({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 13 });
await groupLeader.post('/user/class/cast/earth');
await sleep(1);
@@ -224,11 +224,11 @@ describe('POST /user/class/cast/:spellId', () => {
});
let promises = [];
promises.push(group.groupLeader.update({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 20 }));
promises.push(group.members[0].update({ 'stats.mp': 0, 'stats.class': 'warrior', 'stats.lvl': 20 }));
promises.push(group.members[1].update({ 'stats.mp': 0, 'stats.class': 'wizard', 'stats.lvl': 20 }));
promises.push(group.members[2].update({ 'stats.mp': 0, 'stats.class': 'rogue', 'stats.lvl': 20 }));
promises.push(group.members[3].update({ 'stats.mp': 0, 'stats.class': 'healer', 'stats.lvl': 20 }));
promises.push(group.groupLeader.updateOne({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 20 }));
promises.push(group.members[0].updateOne({ 'stats.mp': 0, 'stats.class': 'warrior', 'stats.lvl': 20 }));
promises.push(group.members[1].updateOne({ 'stats.mp': 0, 'stats.class': 'wizard', 'stats.lvl': 20 }));
promises.push(group.members[2].updateOne({ 'stats.mp': 0, 'stats.class': 'rogue', 'stats.lvl': 20 }));
promises.push(group.members[3].updateOne({ 'stats.mp': 0, 'stats.class': 'healer', 'stats.lvl': 20 }));
await Promise.all(promises);
await group.groupLeader.post('/user/class/cast/mpheal');
@@ -252,7 +252,7 @@ describe('POST /user/class/cast/:spellId', () => {
members: 1,
});
await groupLeader.update({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 13 });
await groupLeader.updateOne({ 'stats.mp': 200, 'stats.class': 'wizard', 'stats.lvl': 13 });
await groupLeader.post('/user/class/cast/earth', { quantity: 2 });
await sleep(1);
@@ -275,7 +275,7 @@ describe('POST /user/class/cast/:spellId', () => {
text: 'todo group',
type: 'todo',
});
await user.update({ 'stats.class': 'healer', 'stats.mp': 200, 'stats.lvl': 15 });
await user.updateOne({ 'stats.class': 'healer', 'stats.mp': 200, 'stats.lvl': 15 });
await user.post(`/tasks/${groupTask._id}/assign`, [user._id]);
await user.put('/user', {
'preferences.tasks.mirrorGroupTasks': [guild._id],
@@ -305,7 +305,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
const leader = party.groupLeader;
const recipient = party.members[0];
await leader.update({ 'stats.gp': 10 });
await leader.updateOne({ 'stats.gp': 10 });
await leader.post(`/user/class/cast/birthday?targetId=${recipient._id}`);
await leader.sync();
await recipient.sync();
@@ -314,14 +314,14 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('only increases user\'s achievement one if target == caster', async () => {
await user.update({ 'stats.gp': 10 });
await user.updateOne({ 'stats.gp': 10 });
await user.post(`/user/class/cast/birthday?targetId=${user._id}`);
await user.sync();
expect(user.achievements.birthday).to.equal(1);
});
it('passes correct target to spell when targetType === \'task\'', async () => {
await user.update({ 'stats.class': 'wizard', 'stats.lvl': 11 });
await user.updateOne({ 'stats.class': 'wizard', 'stats.lvl': 11 });
const task = await user.post('/tasks/user', {
text: 'test habit',
@@ -334,7 +334,7 @@ describe('POST /user/class/cast/:spellId', () => {
});
it('passes correct target to spell when targetType === \'self\'', async () => {
await user.update({ 'stats.class': 'wizard', 'stats.lvl': 14, 'stats.mp': 50 });
await user.updateOne({ 'stats.class': 'wizard', 'stats.lvl': 14, 'stats.mp': 50 });
const result = await user.post('/user/class/cast/frost');

View File

@@ -24,7 +24,7 @@ describe('POST /user/custom-day-start', () => {
it('sets lastCron to the current time to prevent an unexpected cron', async () => {
const oldCron = moment().subtract(7, 'hours');
await user.update({ lastCron: oldCron });
await user.updateOne({ lastCron: oldCron });
await user.post(endpoint, { dayStart: 1 });
await user.sync();

View File

@@ -14,7 +14,7 @@ describe('POST /user/equip/:type/:key', () => {
// More tests in common code unit tests
it('equip an item', async () => {
await user.update({
await user.updateOne({
'items.gear.owned': {
weapon_warrior_0: true,
weapon_warrior_1: true,

View File

@@ -19,7 +19,7 @@ describe('POST /user/feed/:pet/:food', () => {
// More tests in common code unit tests
it('does not enjoy the food', async () => {
await user.update({
await user.updateOne({
'items.pets.Wolf-Base': 5,
'items.food.Milk': 2,
});
@@ -42,7 +42,7 @@ describe('POST /user/feed/:pet/:food', () => {
});
it('bulk feeding pet with non-preferred food', async () => {
await user.update({
await user.updateOne({
'items.pets.Wolf-Base': 5,
'items.food.Milk': 3,
});
@@ -85,7 +85,7 @@ describe('POST /user/feed/:pet/:food', () => {
},
});
await user.update({
await user.updateOne({
'items.pets.Wolf-Base': 49,
'items.food.Milk': 2,
});
@@ -113,7 +113,7 @@ describe('POST /user/feed/:pet/:food', () => {
},
});
await user.update({
await user.updateOne({
'items.pets.Wolf-Base': 47,
'items.food.Milk': 3,
});

View File

@@ -16,7 +16,7 @@ describe('POST /user/hatch/:egg/:hatchingPotion', () => {
// More tests in common code unit tests
it('hatch a new pet', async () => {
await user.update({
await user.updateOne({
'items.eggs.Wolf': 1,
'items.hatchingPotions.Base': 1,
});
@@ -54,7 +54,7 @@ describe('POST /user/hatch/:egg/:hatchingPotion', () => {
},
});
await user.update({
await user.updateOne({
'items.eggs.Wolf': 1,
'items.hatchingPotions.Base': 1,
});

View File

@@ -12,7 +12,7 @@ describe('POST /user/mark-pms-read', () => {
// More tests in common code unit tests
it('marks user\'s private messages as read', async () => {
await user.update({
await user.updateOne({
'inbox.newMessages': 1,
});
await user.post('/user/mark-pms-read');

View File

@@ -35,7 +35,7 @@ describe('POST /user/purchase/:type/:key', () => {
it('can convert gold to gems if subscribed', async () => {
const oldBalance = user.balance;
await user.update({
await user.updateOne({
'purchased.plan.customerId': 'group-plan',
'stats.gp': 1000,
});
@@ -53,14 +53,14 @@ describe('POST /user/purchase/:type/:key', () => {
},
upgradeToGroupPlan: true,
});
await group.update({
await group.updateOne({
'leaderOnly.getGems': true,
'purchased.plan.customerId': 123,
});
await groupLeader.sync();
const oldBalance = groupLeader.balance;
await groupLeader.update({
await groupLeader.updateOne({
'purchased.plan.customerId': 'group-plan',
'stats.gp': 1000,
});
@@ -80,13 +80,13 @@ describe('POST /user/purchase/:type/:key', () => {
members: 1,
upgradeToGroupPlan: true,
});
await group.update({
await group.updateOne({
'leaderOnly.getGems': true,
'purchased.plan.customerId': 123,
});
const oldBalance = members[0].balance;
await members[0].update({
await members[0].updateOne({
'purchased.plan.customerId': 'group-plan',
'stats.gp': 1000,
});
@@ -111,7 +111,7 @@ describe('POST /user/purchase/:type/:key', () => {
it('can convert gold to gems if subscribed', async () => {
const oldBalance = user.balance;
await user.update({
await user.updateOne({
'purchased.plan.customerId': 'group-plan',
'stats.gp': 1000,
});

View File

@@ -23,7 +23,7 @@ describe('POST /user/read-card/:cardType', () => {
// More tests in common code unit tests
it('reads a card', async () => {
await user.update({
await user.updateOne({
'items.special.greetingReceived': [true],
'flags.cardReceived': true,
notifications: [{

View File

@@ -24,7 +24,7 @@ describe('POST /user/rebirth', () => {
// More tests in common code unit tests
it('resets user\'s tasks', async () => {
await user.update({
await user.updateOne({
balance: 1.5,
});

View File

@@ -47,7 +47,7 @@ describe('POST /user/release-both', () => {
// More tests in common code unit tests
it('grants triad bingo with gems', async () => {
await user.update();
await user.updateOne();
const response = await user.post('/user/release-both');
await user.sync();

View File

@@ -36,7 +36,7 @@ describe('POST /user/release-mounts', () => {
// More tests in common code unit tests
it('releases mounts', async () => {
await user.update({
await user.updateOne({
balance: 1,
});

View File

@@ -36,7 +36,7 @@ describe('POST /user/release-pets', () => {
// More tests in common code unit tests
it('releases pets', async () => {
await user.update({
await user.updateOne({
balance: 1,
});

View File

@@ -24,7 +24,7 @@ describe('POST /user/reroll', () => {
// More tests in common code unit tests
it('resets user\'s tasks', async () => {
await user.update({
await user.updateOne({
balance: 2,
});

View File

@@ -24,7 +24,7 @@ describe('POST /user/revive', () => {
// More tests in common code unit tests
it('decreases a stat', async () => {
await user.update({
await user.updateOne({
'stats.str': 2,
'stats.hp': 0,
});

View File

@@ -25,7 +25,7 @@ describe('POST /user/sell/:type/:key', () => {
});
it('sells an item', async () => {
await user.update({
await user.updateOne({
items: {
eggs: {
Wolf: 1,

View File

@@ -26,7 +26,7 @@ describe('POST /user/unlock', () => {
// More tests in common code unit tests
it('reduces a user\'s balance', async () => {
await user.update({
await user.updateOne({
balance: usersStartingGems,
});
const response = await user.post(`/user/unlock?path=${unlockPath}`);
@@ -37,7 +37,7 @@ describe('POST /user/unlock', () => {
});
it('does not reduce a user\'s balance twice', async () => {
await user.update({
await user.updateOne({
balance: usersStartingGems,
});
const response = await user.post(`/user/unlock?path=${unlockGearSetPath}`);

View File

@@ -94,14 +94,6 @@ describe('PUT /user', () => {
message: t('bannedSlurUsedInProfile'),
});
await expect(user.put('/user', {
'profile.name': 'TESTPLACEHOLDERSWEARWORDHERE',
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('bannedWordUsedInProfile'),
});
await expect(user.put('/user', {
'profile.name': 'namecontainsnewline\n',
})).to.eventually.be.rejected.and.eql({
@@ -116,7 +108,7 @@ describe('PUT /user', () => {
_id: '1234', publishDate: new Date(), title: 'Title', published: true,
});
await user.update({
await user.updateOne({
'flags.lastNewStuffRead': '123',
});
@@ -198,7 +190,7 @@ describe('PUT /user', () => {
it(`updates user with ${type} that is a default`, async () => {
const dbUpdate = {};
dbUpdate[`purchased.${type}.${item}`] = true;
await user.update(dbUpdate);
await user.updateOne(dbUpdate);
// Sanity checks to make sure user is not already equipped with item
expect(get(user.preferences, type)).to.not.eql(item);
@@ -220,7 +212,7 @@ describe('PUT /user', () => {
});
it('can set beard to default', async () => {
await user.update({
await user.updateOne({
'purchased.hair.beard': 3,
'preferences.hair.beard': 3,
});
@@ -233,7 +225,7 @@ describe('PUT /user', () => {
});
it('can set mustache to default', async () => {
await user.update({
await user.updateOne({
'purchased.hair.mustache': 2,
'preferences.hair.mustache': 2,
});
@@ -272,7 +264,7 @@ describe('PUT /user', () => {
it(`updates user with ${type} user does own`, async () => {
const dbUpdate = {};
dbUpdate[`purchased.${type}.${item}`] = true;
await user.update(dbUpdate);
await user.updateOne(dbUpdate);
// Sanity check to make sure user is not already equipped with item
expect(get(user.preferences, type)).to.not.eql(item);

View File

@@ -22,7 +22,7 @@ describe('DELETE social registration', () => {
context('Google', () => {
it('fails if user does not have an alternative registration method', async () => {
await user.update({
await user.updateOne({
'auth.google.id': 'some-google-id',
'auth.local': { ok: true },
});
@@ -34,7 +34,7 @@ describe('DELETE social registration', () => {
});
it('succeeds if user has a local registration', async () => {
await user.update({
await user.updateOne({
'auth.google.id': 'some-google-id',
});
@@ -47,7 +47,7 @@ describe('DELETE social registration', () => {
context('Apple', () => {
it('fails if user does not have an alternative registration method', async () => {
await user.update({
await user.updateOne({
'auth.apple.id': 'some-apple-id',
'auth.local': { ok: true },
});
@@ -59,7 +59,7 @@ describe('DELETE social registration', () => {
});
it('succeeds if user has a local registration', async () => {
await user.update({
await user.updateOne({
'auth.apple.id': 'some-apple-id',
});

View File

@@ -44,7 +44,7 @@ xdescribe('GET /user/auth/local/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().subtract({ minutes: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -69,7 +69,7 @@ xdescribe('GET /user/auth/local/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
auth: 'not an object with valid fields',
});
@@ -84,7 +84,7 @@ xdescribe('GET /user/auth/local/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': 'invalid',
});
@@ -101,7 +101,7 @@ xdescribe('GET /user/auth/local/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});

View File

@@ -59,7 +59,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().subtract({ minutes: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -111,7 +111,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': 'invalid',
});
@@ -133,7 +133,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -153,7 +153,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -174,7 +174,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -196,7 +196,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -218,7 +218,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});
@@ -245,7 +245,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
const salt = sha1MakeSalt();
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,
@@ -260,7 +260,7 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
userId: user._id,
expiresAt: moment().add({ days: 1 }),
}));
await user.update({
await user.updateOne({
'auth.local.passwordResetCode': code,
});

View File

@@ -37,7 +37,7 @@ describe('POST /user/auth/local/login', () => {
});
it('user is blocked', async () => {
await user.update({ 'auth.blocked': 1 });
await user.updateOne({ 'auth.blocked': 1 });
await expect(api.post(endpoint, {
username: user.auth.local.username,
password,
@@ -84,7 +84,7 @@ describe('POST /user/auth/local/login', () => {
const salt = sha1MakeSalt();
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,

View File

@@ -497,7 +497,7 @@ describe('POST /user/auth/local/register', () => {
});
});
it('succeeds', async () => {
await user.update({ 'auth.facebook.id': 'some-fb-id', 'auth.local': { ok: true } });
await user.updateOne({ 'auth.facebook.id': 'some-fb-id', 'auth.local': { ok: true } });
await user.post('/user/auth/local/register', {
username,
email,
@@ -531,7 +531,7 @@ describe('POST /user/auth/local/register', () => {
});
});
it('succeeds', async () => {
await user.update({ 'auth.google.id': 'some-google-id', 'auth.local': { ok: true } });
await user.updateOne({ 'auth.google.id': 'some-google-id', 'auth.local': { ok: true } });
await user.post('/user/auth/local/register', {
username,
email,
@@ -565,7 +565,7 @@ describe('POST /user/auth/local/register', () => {
});
});
it('succeeds', async () => {
await user.update({ 'auth.apple.id': 'some-apple-id', 'auth.local': { ok: true } });
await user.updateOne({ 'auth.apple.id': 'some-apple-id', 'auth.local': { ok: true } });
await user.post('/user/auth/local/register', {
username,
email,

View File

@@ -27,7 +27,7 @@ describe('POST /user/reset-password', async () => {
it('resets password for social users', async () => {
const email = `${user.auth.local.username}+google@example.com`;
await user.update({ 'auth.google.emails': [{ value: email }] });
await user.updateOne({ 'auth.google.emails': [{ value: email }] });
await user.sync();
const previousPassword = user.auth.local.passwordResetCode;
const response = await user.post(endpoint, {

View File

@@ -80,7 +80,7 @@ describe('PUT /user/auth/update-email', () => {
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
const myNewEmail = 'my-new-random-email@example.net';
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,
@@ -115,7 +115,7 @@ describe('PUT /user/auth/update-email', () => {
beforeEach(async () => {
socialUser = await generateUser();
await socialUser.update({ 'auth.local': { ok: true } });
await socialUser.updateOne({ 'auth.local': { ok: true } });
});
it('does not change email if user.auth.local.email does not exist for this user', async () => {

View File

@@ -128,7 +128,7 @@ describe('PUT /user/auth/update-password', async () => {
const salt = sha1MakeSalt();
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,

View File

@@ -67,7 +67,7 @@ describe('PUT /user/auth/update-username', async () => {
const salt = sha1MakeSalt();
const sha1HashedPassword = sha1EncryptPassword(textPassword, salt);
await user.update({
await user.updateOne({
'auth.local.hashed_password': sha1HashedPassword,
'auth.local.passwordHashMethod': 'sha1',
'auth.local.salt': salt,

View File

@@ -30,7 +30,7 @@ describe('POST /user/buy/:key', () => {
});
it('buys a potion', async () => {
await user.update({
await user.updateOne({
'stats.gp': 400,
'stats.hp': 40,
});
@@ -45,7 +45,7 @@ describe('POST /user/buy/:key', () => {
});
it('returns an error if user tries to buy a potion with full health', async () => {
await user.update({
await user.updateOne({
'stats.gp': 40,
'stats.hp': 50,
});
@@ -72,7 +72,7 @@ describe('POST /user/buy/:key', () => {
const item = content.special[key];
const stub = sinon.stub(item, 'canOwn').returns(true);
await user.update({ 'stats.gp': 250 });
await user.updateOne({ 'stats.gp': 250 });
const res = await user.post(`/user/buy/${key}`);
await user.sync();
@@ -88,7 +88,7 @@ describe('POST /user/buy/:key', () => {
});
it('allows for bulk purchases', async () => {
await user.update({
await user.updateOne({
'stats.gp': 400,
'stats.hp': 20,
});

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