diff --git a/.idea/.idea.ProjectLighthouse/.idea/indexLayout.xml b/.idea/.idea.ProjectLighthouse/.idea/indexLayout.xml index ea6692c6..40fc41c7 100644 --- a/.idea/.idea.ProjectLighthouse/.idea/indexLayout.xml +++ b/.idea/.idea.ProjectLighthouse/.idea/indexLayout.xml @@ -15,6 +15,7 @@ ProjectLighthouse.sln.DotSettings.user README.md create-migration.sh + crowdin.yml docker-compose.yml global.json scripts-and-tools diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3d72edc6..d2da1519 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,9 +17,6 @@ Once you've gotten MySQL running you can run Lighthouse. It will take care of th PS3 is difficult to set up, so I will be going over how to set up RPCS3 instead. A guide will be coming for PS3 closer to release. You can also follow this guide if you want to learn how to modify your EBOOT. -*Note: This requires a patched copy of RPCS3. You can find a working -version [on our GitHub](https://github.com/LBPUnion/rpcs3).* - Start by getting a copy of LittleBigPlanet 1/2 installed. (Check the LittleBigPlanet 1 section, since you'll need to do extra steps for your game to not crash upon entering pod computer). @@ -44,8 +41,8 @@ Now, copy the `EBOOTlocalhost.elf` file to where you got your `EBOOT.elf` file f To launch the game with the patched EBOOT, open up RPCS3, go to File, Boot SELF/ELF, and open up `EBOOTlocalhost.elf`. -Assuming you are running the patched version of RPCS3, you patched the file correctly, the database is migrated, and -Project Lighthouse is running, the game should now connect and you may begin contributing! +Assuming you patched the file correctly, the database is migrated, and +Project Lighthouse is running, the game should now connect, and you may begin contributing! ### LittleBigPlanet 1 diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-ar-SA.resx b/ProjectLighthouse.Localization/BaseLayout.lang-ar-SA.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-ar-SA.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-da-DK.resx b/ProjectLighthouse.Localization/BaseLayout.lang-da-DK.resx new file mode 100644 index 00000000..e73812c8 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-da-DK.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Forside + A button on the header that takes you to the landing page. + + + + Brugere + A button on the header that takes you to the user listing. + + + + Fotos + A button on the header that takes you to a list of user-uploaded photos. + + + + Baner + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Godkendelse + A button on the header that takes you to a list of authentication attempts. + + + + Log ind / Registrer + A button on the header that lets you log in or register. + + + Profil + A quick shortcut on the header to take you to your profile if logged in. + + + Administrationspanel + A header link that takes you to the admin panel if available. + + + Log ud + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-eo-UY.resx b/ProjectLighthouse.Localization/BaseLayout.lang-eo-UY.resx new file mode 100644 index 00000000..68388e30 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-eo-UY.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Hejmo + A button on the header that takes you to the landing page. + + + + Uzantoj + A button on the header that takes you to the user listing. + + + + Fotoj + A button on the header that takes you to a list of user-uploaded photos. + + + + Etaĝoj + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Aŭtentigado + A button on the header that takes you to a list of authentication attempts. + + + + Ensaluto / Registro + A button on the header that lets you log in or register. + + + Profilo + A quick shortcut on the header to take you to your profile if logged in. + + + Panelo de administranto + A header link that takes you to the admin panel if available. + + + Adiaŭi + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-es-MX.resx b/ProjectLighthouse.Localization/BaseLayout.lang-es-MX.resx new file mode 100644 index 00000000..9f37276f --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-es-MX.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Inicio + A button on the header that takes you to the landing page. + + + + Usuarios + A button on the header that takes you to the user listing. + + + + Fotos + A button on the header that takes you to a list of user-uploaded photos. + + + + Niveles + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Autenticación + A button on the header that takes you to a list of authentication attempts. + + + + Iniciar sesión / Registrarse + A button on the header that lets you log in or register. + + + Perfil + A quick shortcut on the header to take you to your profile if logged in. + + + Panel de administración + A header link that takes you to the admin panel if available. + + + Cerrar sesión + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-fil-PH.resx b/ProjectLighthouse.Localization/BaseLayout.lang-fil-PH.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-fil-PH.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-fr-FR.resx b/ProjectLighthouse.Localization/BaseLayout.lang-fr-FR.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-fr-FR.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-ga-IE.resx b/ProjectLighthouse.Localization/BaseLayout.lang-ga-IE.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-ga-IE.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-gd-GB.resx b/ProjectLighthouse.Localization/BaseLayout.lang-gd-GB.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-gd-GB.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-ja-JP.resx b/ProjectLighthouse.Localization/BaseLayout.lang-ja-JP.resx new file mode 100644 index 00000000..fb8efb4d --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-ja-JP.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + ホーム + A button on the header that takes you to the landing page. + + + + ユーザー + A button on the header that takes you to the user listing. + + + + 画像 + A button on the header that takes you to a list of user-uploaded photos. + + + + レベル + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + 認証 + A button on the header that takes you to a list of authentication attempts. + + + + ログイン/サインアップ + A button on the header that lets you log in or register. + + + プロフィール + A quick shortcut on the header to take you to your profile if logged in. + + + 管理者の部屋 + A header link that takes you to the admin panel if available. + + + ログアウト + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-no-NO.resx b/ProjectLighthouse.Localization/BaseLayout.lang-no-NO.resx new file mode 100644 index 00000000..aef7314b --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-no-NO.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Hjem + A button on the header that takes you to the landing page. + + + + Brukere + A button on the header that takes you to the user listing. + + + + Bilder + A button on the header that takes you to a list of user-uploaded photos. + + + + Nivåer + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Godkjenning + A button on the header that takes you to a list of authentication attempts. + + + + Logg inn/Registrer + A button on the header that lets you log in or register. + + + Profil + A quick shortcut on the header to take you to your profile if logged in. + + + Administrasjon + A header link that takes you to the admin panel if available. + + + Logg ut + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-pl-PL.resx b/ProjectLighthouse.Localization/BaseLayout.lang-pl-PL.resx new file mode 100644 index 00000000..9ffde647 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-pl-PL.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Strona Główna + A button on the header that takes you to the landing page. + + + + Gracze + A button on the header that takes you to the user listing. + + + + Zdjęcia + A button on the header that takes you to a list of user-uploaded photos. + + + + Poziomy + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Autoryzacja + A button on the header that takes you to a list of authentication attempts. + + + + Login / Rejestracja + A button on the header that lets you log in or register. + + + Profil + A quick shortcut on the header to take you to your profile if logged in. + + + Panel Administracyjny + A header link that takes you to the admin panel if available. + + + Wyloguj + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-pt-PT.resx b/ProjectLighthouse.Localization/BaseLayout.lang-pt-PT.resx new file mode 100644 index 00000000..c799594c --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-pt-PT.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-ru-RU.resx b/ProjectLighthouse.Localization/BaseLayout.lang-ru-RU.resx new file mode 100644 index 00000000..b8584493 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-ru-RU.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Главная + A button on the header that takes you to the landing page. + + + + Пользователи + A button on the header that takes you to the user listing. + + + + Фотографии + A button on the header that takes you to a list of user-uploaded photos. + + + + Уровни + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Аутентификация + A button on the header that takes you to a list of authentication attempts. + + + + Вход / Регистрация + A button on the header that lets you log in or register. + + + Профиль + A quick shortcut on the header to take you to your profile if logged in. + + + Админпанель + A header link that takes you to the admin panel if available. + + + Выйти + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-sv-SE.resx b/ProjectLighthouse.Localization/BaseLayout.lang-sv-SE.resx new file mode 100644 index 00000000..ee6f8508 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-sv-SE.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Startsida + A button on the header that takes you to the landing page. + + + + Användare + A button on the header that takes you to the user listing. + + + + Foton + A button on the header that takes you to a list of user-uploaded photos. + + + + Banor + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Autentisering + A button on the header that takes you to a list of authentication attempts. + + + + Logga in / Registrera + A button on the header that lets you log in or register. + + + Min Profil + A quick shortcut on the header to take you to your profile if logged in. + + + Administrationspanel + A header link that takes you to the admin panel if available. + + + Logga ut + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.lang-zh-CN.resx b/ProjectLighthouse.Localization/BaseLayout.lang-zh-CN.resx new file mode 100644 index 00000000..92d025f2 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.lang-zh-CN.resx @@ -0,0 +1,66 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + 主页 + A button on the header that takes you to the landing page. + + + + 用户 + A button on the header that takes you to the user listing. + + + + 图片 + A button on the header that takes you to a list of user-uploaded photos. + + + + 追踪 + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/BaseLayout.resx b/ProjectLighthouse.Localization/BaseLayout.resx new file mode 100644 index 00000000..e7b34891 --- /dev/null +++ b/ProjectLighthouse.Localization/BaseLayout.resx @@ -0,0 +1,71 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Home + A button on the header that takes you to the landing page. + + + + Users + A button on the header that takes you to the user listing. + + + + Photos + A button on the header that takes you to a list of user-uploaded photos. + + + + Levels + A button on the header that takes you to a list of user-uploaded levels. Levels are internally referred to as "slots". + + + + Authentication + A button on the header that takes you to a list of authentication attempts. + + + + Login / Register + A button on the header that lets you log in or register. + + + Profile + A quick shortcut on the header to take you to your profile if logged in. + + + Admin Panel + A header link that takes you to the admin panel if available. + + + Log out + A shortcut to log you out of your account. + + + Mod Panel + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ar-SA.resx b/ProjectLighthouse.Localization/General.lang-ar-SA.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-ar-SA.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-da-DK.resx b/ProjectLighthouse.Localization/General.lang-da-DK.resx new file mode 100644 index 00000000..6db48d85 --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-da-DK.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Brugernavn + + + Adgangskode + + + Registrer + + + Glemt adgangskode? + + + Åh nej! + + + Log ind + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-eo-UY.resx b/ProjectLighthouse.Localization/General.lang-eo-UY.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-eo-UY.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-es-MX.resx b/ProjectLighthouse.Localization/General.lang-es-MX.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-es-MX.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-fil-PH.resx b/ProjectLighthouse.Localization/General.lang-fil-PH.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-fil-PH.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-fr-FR.resx b/ProjectLighthouse.Localization/General.lang-fr-FR.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-fr-FR.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ga-IE.resx b/ProjectLighthouse.Localization/General.lang-ga-IE.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-ga-IE.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ja-JP.resx b/ProjectLighthouse.Localization/General.lang-ja-JP.resx new file mode 100644 index 00000000..247008f3 --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-ja-JP.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ユーザーネーム + + + パスワード + + + 登録する + + + パスワードを忘れましたか? + + + おおっと! + + + ログイン + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-no-NO.resx b/ProjectLighthouse.Localization/General.lang-no-NO.resx new file mode 100644 index 00000000..eb66dc58 --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-no-NO.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Brukernavn + + + Passord + + + Registrer + + + Glemt Passord? + + + Ånei! + + + Logg in + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-pl-PL.resx b/ProjectLighthouse.Localization/General.lang-pl-PL.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-pl-PL.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-pt-PT.resx b/ProjectLighthouse.Localization/General.lang-pt-PT.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-pt-PT.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ru-RU.resx b/ProjectLighthouse.Localization/General.lang-ru-RU.resx new file mode 100644 index 00000000..b3c93d7c --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-ru-RU.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-sv-SE.resx b/ProjectLighthouse.Localization/General.lang-sv-SE.resx new file mode 100644 index 00000000..3c2b250f --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-sv-SE.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Användarnamn + + + Lösenord + + + Registrera + + + Glömt lösenordet? + + + Ajdå! + + + Logga in + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-zh-CN.resx b/ProjectLighthouse.Localization/General.lang-zh-CN.resx new file mode 100644 index 00000000..f2ff702f --- /dev/null +++ b/ProjectLighthouse.Localization/General.lang-zh-CN.resx @@ -0,0 +1,38 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 用户名 + + + Password + + + Register + + + 忘记密码? + + + 哎呀! + + + 登入 + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.resx b/ProjectLighthouse.Localization/General.resx new file mode 100644 index 00000000..2e014ac5 --- /dev/null +++ b/ProjectLighthouse.Localization/General.resx @@ -0,0 +1,39 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Username + + + Password + + + Register + + + Forgot Password? + + + Uh oh! + + + Log In + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-ar-SA.resx b/ProjectLighthouse.Localization/LandingPage.lang-ar-SA.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-ar-SA.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-da-DK.resx b/ProjectLighthouse.Localization/LandingPage.lang-da-DK.resx new file mode 100644 index 00000000..160394c2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-da-DK.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Velkommen til {0}! + A greeting on the main page of the website. + + + + Du er i øjeblikket logget ind som {0}. + A greeting on the main page of the website. + + + + Der er ingen brugere online. Hvorfor ikke hoppe på? + A greeting on the main page of the website. + + + + Der er 1 bruger online: + A greeting on the main page of the website. + + + + Der er {0} brugere online: + A greeting on the main page of the website. + + + + Du har {0} godkendelsesforsøg afventende. Klik her for at se dem. + A greeting on the main page of the website. + + + + Seneste Baner + + + + Seneste Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-eo-UY.resx b/ProjectLighthouse.Localization/LandingPage.lang-eo-UY.resx new file mode 100644 index 00000000..17c09a1d --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-eo-UY.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + Vi ensalutinta kiel {0}. + A greeting on the main page of the website. + + + + Ne estas uzantoj enretaj. Kial ne sursalti? + A greeting on the main page of the website. + + + + Estas 1 uzanto enreta: + A greeting on the main page of the website. + + + + Estas {0} uzantoj enretaj: + A greeting on the main page of the website. + + + + Vi havas {0} pritraktatajn aŭtentigajn provojn. Klaku ĉi tie por vidi ilin. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-es-MX.resx b/ProjectLighthouse.Localization/LandingPage.lang-es-MX.resx new file mode 100644 index 00000000..874ee983 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-es-MX.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + Estás conectado actualmente como {0} + A greeting on the main page of the website. + + + + No hay usuarios en línea. ¿Por qué no subirse? + A greeting on the main page of the website. + + + + Hay 1 usuario actualmente en línea: + A greeting on the main page of the website. + + + + Actualmente hay {0} usuarios en línea: + A greeting on the main page of the website. + + + + Tiene {0} intentos de autenticación pendientes. Haga clic aquí para verlos. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-fil-PH.resx b/ProjectLighthouse.Localization/LandingPage.lang-fil-PH.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-fil-PH.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-fr-FR.resx b/ProjectLighthouse.Localization/LandingPage.lang-fr-FR.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-fr-FR.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-ga-IE.resx b/ProjectLighthouse.Localization/LandingPage.lang-ga-IE.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-ga-IE.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-gd-GB.resx b/ProjectLighthouse.Localization/LandingPage.lang-gd-GB.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-gd-GB.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-ja-JP.resx b/ProjectLighthouse.Localization/LandingPage.lang-ja-JP.resx new file mode 100644 index 00000000..3611578d --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-ja-JP.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + {0}へようこそ + A greeting on the main page of the website. + + + + {0}がログインしています + A greeting on the main page of the website. + + + + オンラインユーザーはなし + A greeting on the main page of the website. + + + + 1人のユーザーがオンライン + A greeting on the main page of the website. + + + + {0}人のユーザーがオンライン + A greeting on the main page of the website. + + + + {0} の認証が保留中です。ここをクリックして確認してください。 + A greeting on the main page of the website. + + + + 最新のレベル + + + + 最新のチームピック + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-no-NO.resx b/ProjectLighthouse.Localization/LandingPage.lang-no-NO.resx new file mode 100644 index 00000000..bb049a4d --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-no-NO.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Velkommen til {0} + A greeting on the main page of the website. + + + + Du er logget inn som {0} + A greeting on the main page of the website. + + + + Det er ingen brukere på. Hvorfor ikke hoppe på? + A greeting on the main page of the website. + + + + Det er 1 bruker på for øyeblikket: + A greeting on the main page of the website. + + + + For tiden er {0} brukere pålogget: + A greeting on the main page of the website. + + + + Du har {0} autentiseringsforsøk. Klikk her for å se dem. + A greeting on the main page of the website. + + + + Nyeste nivåer + + + + Siste lag valg + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-pl-PL.resx b/ProjectLighthouse.Localization/LandingPage.lang-pl-PL.resx new file mode 100644 index 00000000..3ec4379d --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-pl-PL.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + Jesteś zalogowany jako {0}. + A greeting on the main page of the website. + + + + Nikt nie jest online. Dlaczego by nie zagrać? + A greeting on the main page of the website. + + + + Jest 1 gracz online: + A greeting on the main page of the website. + + + + Obecnie jest {0} graczy online: + A greeting on the main page of the website. + + + + Masz {0} oczekujących prób autoryzacji. Kliknij tutaj, by je zobaczyć. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-pt-PT.resx b/ProjectLighthouse.Localization/LandingPage.lang-pt-PT.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-pt-PT.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-ru-RU.resx b/ProjectLighthouse.Localization/LandingPage.lang-ru-RU.resx new file mode 100644 index 00000000..0bebca43 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-ru-RU.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + Вы вошли как {0} + A greeting on the main page of the website. + + + + Нет пользователей в сети. Почему бы и не поиграть? + A greeting on the main page of the website. + + + + Сейчас в сети 1 пользователь: + A greeting on the main page of the website. + + + + В настоящее время сейчас {0} онлайн: + A greeting on the main page of the website. + + + + У вас есть {0} попыток аутентификации в ожидании. Нажмите здесь, чтобы просмотреть их. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-sv-SE.resx b/ProjectLighthouse.Localization/LandingPage.lang-sv-SE.resx new file mode 100644 index 00000000..ca1cae9d --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-sv-SE.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Välkommen till {0}! + A greeting on the main page of the website. + + + + Du är inloggad som {0}. + A greeting on the main page of the website. + + + + Ingen är online. Dags att gibba? + A greeting on the main page of the website. + + + + 1 användare är online: + A greeting on the main page of the website. + + + + {0} användare är online: + A greeting on the main page of the website. + + + + {0} autentiseringsförsök väntar. Klicka här för att visa dem. + A greeting on the main page of the website. + + + + Senaste Banor + + + + Senaste Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.lang-zh-CN.resx b/ProjectLighthouse.Localization/LandingPage.lang-zh-CN.resx new file mode 100644 index 00000000..ed7772d2 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.lang-zh-CN.resx @@ -0,0 +1,62 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LandingPage.resx b/ProjectLighthouse.Localization/LandingPage.resx new file mode 100644 index 00000000..287660e3 --- /dev/null +++ b/ProjectLighthouse.Localization/LandingPage.resx @@ -0,0 +1,64 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + + Welcome to {0}! + A greeting on the main page of the website. + + + + You are currently logged in as {0}. + A greeting on the main page of the website. + + + + There are no users online. Why not hop on? + A greeting on the main page of the website. + + + + There is 1 user currently online: + A greeting on the main page of the website. + + + + There are currently {0} users online: + A greeting on the main page of the website. + + + + You have {0} authentication attempts pending. Click here to view them. + A greeting on the main page of the website. + + + + Newest Levels + + + + Latest Team Picks + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LocalizationManager.cs b/ProjectLighthouse.Localization/LocalizationManager.cs new file mode 100644 index 00000000..6c838f17 --- /dev/null +++ b/ProjectLighthouse.Localization/LocalizationManager.cs @@ -0,0 +1,108 @@ +using System.Diagnostics; +using System.Reflection; +using System.Resources; + +namespace LBPUnion.ProjectLighthouse.Localization; + +public static class LocalizationManager +{ + private static readonly string namespaceStr = typeof(LocalizationManager).Namespace ?? ""; + public const string DefaultLang = "en-US"; + + public static string GetLocalizedString(TranslationAreas translationArea, string language, string key) + { + // ASP.NET requires specific names for certain languages (like ja for japanese as opposed to the standard ja-JP) + // We map that value back here. + language = mapLanguageBack(language); + + #if DEBUG + Console.WriteLine($"Attempting to load '{key}' for '{language}'"); + #endif + + string resourceBasename = $"{namespaceStr}.{translationArea.ToString()}"; + + // We don't have an en-US .resx, so if we aren't using en-US then we need to add the appropriate language. + // Otherwise, keep it to the normal .resx file + // e.g. BaseLayout.resx as opposed to BaseLayout.lang-da-DK.resx. + if (language != DefaultLang) resourceBasename += $".lang-{language}"; + + string? localizedString = null; + try + { + ResourceManager resourceManager = new(resourceBasename, + Assembly.GetExecutingAssembly()); + + localizedString = resourceManager.GetString(key); + } + catch + { + // ignored + } + + if (localizedString == null) + { + #if DEBUG + if (Debugger.IsAttached) Debugger.Break(); + #endif + return $"{translationArea.ToString()}.{language}.{key}"; + } + + return localizedString; + } + + // If a language isn't working, it might be because a language is using a different name than what ASP.NET expects. + // You can retrieve the name of the language from the Accept-Language header in an HTTP request. + private static readonly Dictionary languageMappings = new() + { + { + "ja-JP", "ja" + }, + { + "eo-UY", "eo" + }, + }; + + /// + /// Some languages crowdin uses have names that differ from the ones that ASP.NET expects. This function converts the names. + /// + /// The language to convert to ASP.NET names + /// The name of the language that ASP.NET expects. + public static string MapLanguage(string language) + { + foreach ((string? key, string? value) in languageMappings) + { + if (key == language) return value; + } + + return language; + } + + private static string mapLanguageBack(string language) + { + foreach ((string? key, string? value) in languageMappings) + { + if (value == language) return key; + } + + return language; + } + + // This is a bit scuffed, but it will work for what I need it to do. + public static IEnumerable GetAvailableLanguages() + { + string area = TranslationAreas.BaseLayout.ToString(); + + List languages = Assembly.GetExecutingAssembly() + .GetManifestResourceNames() + .Where(r => r.StartsWith($"{namespaceStr}.{area}")) + .Select(r => r.Substring(r.IndexOf(area), r.Length - r.IndexOf(area)).Substring(area.Length + 1)) + .Select(r => r.Replace(".resources", string.Empty)) // Remove .resources + .Select(r => r.Replace("lang-", string.Empty)) // Remove 'lang-' prefix from languages + .Where(r => r != "resources") + .ToList(); + + languages.Add(DefaultLang); + + return languages; + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-ar-SA.resx b/ProjectLighthouse.Localization/LoggedOut.lang-ar-SA.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-ar-SA.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-da-DK.resx b/ProjectLighthouse.Localization/LoggedOut.lang-da-DK.resx new file mode 100644 index 00000000..2c1315cd --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-da-DK.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logget ud + + + Du er blevet logget ud. Du vil blive omdirigeret om 5 sekunder, eller du kan klikke nedenfor for at gøre det manuelt. + + + Omdiriger + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-eo-UY.resx b/ProjectLighthouse.Localization/LoggedOut.lang-eo-UY.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-eo-UY.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-es-MX.resx b/ProjectLighthouse.Localization/LoggedOut.lang-es-MX.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-es-MX.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-fil-PH.resx b/ProjectLighthouse.Localization/LoggedOut.lang-fil-PH.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-fil-PH.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-fr-FR.resx b/ProjectLighthouse.Localization/LoggedOut.lang-fr-FR.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-fr-FR.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-ga-IE.resx b/ProjectLighthouse.Localization/LoggedOut.lang-ga-IE.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-ga-IE.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-ja-JP.resx b/ProjectLighthouse.Localization/LoggedOut.lang-ja-JP.resx new file mode 100644 index 00000000..09810770 --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-ja-JP.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ログアウトしました + + + 正常にログアウトされました。5秒後にリダイレクトされるか、以下をクリックして手動でログアウトできます。 + + + リダイレクト + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-no-NO.resx b/ProjectLighthouse.Localization/LoggedOut.lang-no-NO.resx new file mode 100644 index 00000000..a33eb4e2 --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-no-NO.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logget ut + + + Du har blitt logget ut. Du vil bli omdirigert om 5 sekunder, eller du kan klikke nedenfor for å gjøre det manuelt. + + + Videresend + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-pl-PL.resx b/ProjectLighthouse.Localization/LoggedOut.lang-pl-PL.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-pl-PL.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-pt-PT.resx b/ProjectLighthouse.Localization/LoggedOut.lang-pt-PT.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-pt-PT.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-ru-RU.resx b/ProjectLighthouse.Localization/LoggedOut.lang-ru-RU.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-ru-RU.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-sv-SE.resx b/ProjectLighthouse.Localization/LoggedOut.lang-sv-SE.resx new file mode 100644 index 00000000..50daa5ee --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-sv-SE.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Utloggad + + + Du har loggat ut. Om 5 sekunder kommer du bli omderigerad, eller kan du klicka på knappen under, manuellt. + + + Omdirigera + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.lang-zh-CN.resx b/ProjectLighthouse.Localization/LoggedOut.lang-zh-CN.resx new file mode 100644 index 00000000..9f53122d --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.lang-zh-CN.resx @@ -0,0 +1,29 @@ + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/LoggedOut.resx b/ProjectLighthouse.Localization/LoggedOut.resx new file mode 100644 index 00000000..2d555c7e --- /dev/null +++ b/ProjectLighthouse.Localization/LoggedOut.resx @@ -0,0 +1,30 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logged Out + + + You have been successfully logged out. You will be redirected in 5 seconds, or you may click below to do so manually. + + + Redirect + + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/Program.cs b/ProjectLighthouse.Localization/Program.cs new file mode 100644 index 00000000..a4603129 --- /dev/null +++ b/ProjectLighthouse.Localization/Program.cs @@ -0,0 +1,22 @@ +using System.Reflection; + +namespace LBPUnion.ProjectLighthouse.Localization; + +public static class Program +{ + public static void Main() + { + Console.WriteLine("Resource files loaded:"); + foreach (string resourceFile in Assembly.GetExecutingAssembly().GetManifestResourceNames()) + { + Console.WriteLine(" " + resourceFile); + } + + Console.Write('\n'); + + foreach (string language in LocalizationManager.GetAvailableLanguages()) + { + Console.WriteLine(LocalizationManager.GetLocalizedString(TranslationAreas.BaseLayout, language, "header_home")); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/ProjectLighthouse.Localization.csproj b/ProjectLighthouse.Localization/ProjectLighthouse.Localization.csproj new file mode 100644 index 00000000..57dfbc18 --- /dev/null +++ b/ProjectLighthouse.Localization/ProjectLighthouse.Localization.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + enable + enable + LBPUnion.ProjectLighthouse.Localization + Exe + + + + + ResXFileCodeGenerator + LandingPage.Designer.cs + + + ResXFileCodeGenerator + General.Designer.cs + + + ResXFileCodeGenerator + LoggedOut.Designer.cs + + + + diff --git a/ProjectLighthouse.Localization/StringLists/BaseLayoutStrings.cs b/ProjectLighthouse.Localization/StringLists/BaseLayoutStrings.cs new file mode 100644 index 00000000..52fe7f61 --- /dev/null +++ b/ProjectLighthouse.Localization/StringLists/BaseLayoutStrings.cs @@ -0,0 +1,18 @@ +namespace LBPUnion.ProjectLighthouse.Localization.StringLists; + +public static class BaseLayoutStrings +{ + public static readonly TranslatableString HeaderHome = create("header_home"); + public static readonly TranslatableString HeaderUsers = create("header_users"); + public static readonly TranslatableString HeaderPhotos = create("header_photos"); + public static readonly TranslatableString HeaderSlots = create("header_slots"); + public static readonly TranslatableString HeaderAuthentication = create("header_authentication"); + + public static readonly TranslatableString HeaderLoginRegister = create("header_loginRegister"); + public static readonly TranslatableString HeaderProfile = create("header_profile"); + public static readonly TranslatableString HeaderAdminPanel = create("header_adminPanel"); + public static readonly TranslatableString HeaderModPanel = create("header_modPanel"); + public static readonly TranslatableString HeaderLogout = create("header_logout"); + + private static TranslatableString create(string key) => new(TranslationAreas.BaseLayout, key); +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs b/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs new file mode 100644 index 00000000..db134368 --- /dev/null +++ b/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs @@ -0,0 +1,13 @@ +namespace LBPUnion.ProjectLighthouse.Localization.StringLists; + +public static class GeneralStrings +{ + public static readonly TranslatableString Username = create("username"); + public static readonly TranslatableString Password = create("password"); + public static readonly TranslatableString Register = create("register"); + public static readonly TranslatableString ForgotPassword = create("forgot_password"); + public static readonly TranslatableString Error = create("error"); + public static readonly TranslatableString LogIn = create("log_in"); + + private static TranslatableString create(string key) => new(TranslationAreas.General, key); +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/StringLists/LandingPageStrings.cs b/ProjectLighthouse.Localization/StringLists/LandingPageStrings.cs new file mode 100644 index 00000000..7ec962e8 --- /dev/null +++ b/ProjectLighthouse.Localization/StringLists/LandingPageStrings.cs @@ -0,0 +1,18 @@ +namespace LBPUnion.ProjectLighthouse.Localization.StringLists; + +public static class LandingPageStrings +{ + public static readonly TranslatableString Welcome = create("welcome"); + public static readonly TranslatableString LoggedInAs = create("loggedInAs"); + + public static readonly TranslatableString UsersNone = create("users_none"); + public static readonly TranslatableString UsersSingle = create("users_single"); + public static readonly TranslatableString UsersMultiple = create("users_multiple"); + + public static readonly TranslatableString LatestTeamPicks = create("latest_team_picks"); + public static readonly TranslatableString NewestLevels = create("newest_levels"); + + public static readonly TranslatableString AuthAttemptsPending = create("authAttemptsPending"); + + private static TranslatableString create(string key) => new(TranslationAreas.LandingPage, key); +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/StringLists/LoggedOutStrings.cs b/ProjectLighthouse.Localization/StringLists/LoggedOutStrings.cs new file mode 100644 index 00000000..e8ae3bb9 --- /dev/null +++ b/ProjectLighthouse.Localization/StringLists/LoggedOutStrings.cs @@ -0,0 +1,10 @@ +namespace LBPUnion.ProjectLighthouse.Localization.StringLists; + +public static class LoggedOutStrings +{ + public static readonly TranslatableString LoggedOut = create("logged_out"); + public static readonly TranslatableString LoggedOutInfo = create("logged_out_info"); + public static readonly TranslatableString Redirect = create("redirect"); + + private static TranslatableString create(string key) => new(TranslationAreas.LoggedOut, key); +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/TranslatableString.cs b/ProjectLighthouse.Localization/TranslatableString.cs new file mode 100644 index 00000000..633a5eb4 --- /dev/null +++ b/ProjectLighthouse.Localization/TranslatableString.cs @@ -0,0 +1,27 @@ +namespace LBPUnion.ProjectLighthouse.Localization; + +public class TranslatableString +{ + public TranslatableString(TranslationAreas area, string key) + { + this.Key = key; + this.Area = area; + } + + public string Key { get; init; } + public TranslationAreas Area { get; init; } + + public string Translate(string language) => LocalizationManager.GetLocalizedString(this.Area, language, this.Key); + + public string Translate(string language, params object?[] format) => string.Format(LocalizationManager.GetLocalizedString(this.Area, language, this.Key), format); + + // CS0809 is a warning about obsolete methods overriding non-obsoleted methods. + // That works against what we're trying to do here, so we disable the warning here. + #pragma warning disable CS0809 + [Obsolete("Do not translate by using ToString. Use TranslatableString.Translate().", true)] + public override string ToString() => "NOT TRANSLATED CORRECTLY!"; + #pragma warning restore CS0809 + + [Obsolete("Do not translate by using ToString. Use TranslatableString.Translate().", true)] + public static implicit operator string(TranslatableString _) => "NOT TRANSLATED CORRECTLY!"; +} \ No newline at end of file diff --git a/ProjectLighthouse.Localization/TranslationAreas.cs b/ProjectLighthouse.Localization/TranslationAreas.cs new file mode 100644 index 00000000..ae90be13 --- /dev/null +++ b/ProjectLighthouse.Localization/TranslationAreas.cs @@ -0,0 +1,9 @@ +namespace LBPUnion.ProjectLighthouse.Localization; + +public enum TranslationAreas +{ + BaseLayout, + LandingPage, + General, + LoggedOut, +} \ No newline at end of file diff --git a/ProjectLighthouse.Servers.API/Controllers/UserEndpoints.cs b/ProjectLighthouse.Servers.API/Controllers/UserEndpoints.cs index 30e7d655..b5a8e79e 100644 --- a/ProjectLighthouse.Servers.API/Controllers/UserEndpoints.cs +++ b/ProjectLighthouse.Servers.API/Controllers/UserEndpoints.cs @@ -1,6 +1,7 @@ #nullable enable using LBPUnion.ProjectLighthouse.PlayerData.Profiles; -using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.PlayerData; +using LBPUnion.ProjectLighthouse.Helpers; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -54,4 +55,33 @@ public class UserEndpoints : ApiEndpointController return this.Ok(userStatus); } + + [HttpPost("user/inviteToken")] + public async Task CreateUserInviteToken() + { + if (Configuration.ServerConfiguration.Instance.Authentication.PrivateRegistration || + Configuration.ServerConfiguration.Instance.Authentication.RegistrationEnabled) + { + + string authHeader = this.Request.Headers["Authorization"]; + if (!string.IsNullOrWhiteSpace(authHeader)) + { + string authToken = authHeader.Substring(authHeader.IndexOf(' ') + 1); + + APIKey? apiKey = await this.database.APIKeys.FirstOrDefaultAsync(k => k.Key == authToken); + if (apiKey == null) return this.StatusCode(403, null); + + RegistrationToken token = new(); + token.Created = DateTime.Now; + token.Token = CryptoHelper.GenerateAuthToken(); + + this.database.RegistrationTokens.Add(token); + await this.database.SaveChangesAsync(); + + return Ok(token.Token); + } + + } + return this.NotFound(); + } } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/ClientConfigurationController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/ClientConfigurationController.cs index 7e9dd31d..ad1652c4 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/ClientConfigurationController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/ClientConfigurationController.cs @@ -29,7 +29,7 @@ public class ClientConfigurationController : ControllerBase HostString hostname = this.Request.Host; return this.Ok ( - "ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels false\nAllowModeratedPoppetItems false\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 240.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 60.0\nTIMEOUT_DIVE_IN_TOTAL 300.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\nAllowOnlineCreate true" + + "ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels false\nAllowModeratedPoppetItems false\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 240.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 60.0\nTIMEOUT_DIVE_IN_TOTAL 300.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\nAllowOnlineCreate true\n" + $"TelemetryServer {hostname}\n" + $"CDNHostName {hostname}\n" + $"ShowLevelBoos {ServerConfiguration.Instance.UserGeneratedContentLimits.BooingEnabled.ToString().ToLower()}\n" diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs index 8c7a2eb7..5f5d423c 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs @@ -4,6 +4,7 @@ using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Levels; +using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.PlayerData; using LBPUnion.ProjectLighthouse.PlayerData.Profiles; using LBPUnion.ProjectLighthouse.Serialization; @@ -82,34 +83,67 @@ public class PublishController : ControllerBase GameToken gameToken = userAndToken.Value.Item2; Slot? slot = await this.getSlotFromBody(); - if (slot == null) return this.BadRequest(); + if (slot == null) + { + Logger.Warn("Rejecting level upload, slot is null", LogArea.Publish); + return this.BadRequest(); + } - if (slot.Location == null) return this.BadRequest(); + if (slot.Location == null) + { + Logger.Warn("Rejecting level upload, slot location is null", LogArea.Publish); + return this.BadRequest(); + } - if (slot.Description.Length > 500) return this.BadRequest(); + if (slot.Description.Length > 512) + { + Logger.Warn($"Rejecting level upload, description too long ({slot.Description.Length} characters)", LogArea.Publish); + return this.BadRequest(); + } - if (slot.Name.Length > 64) return this.BadRequest(); + if (slot.Name.Length > 64) + { + Logger.Warn($"Rejecting level upload, title too long ({slot.Name.Length} characters)", LogArea.Publish); + return this.BadRequest(); + } if (slot.Resources.Any(resource => !FileHelper.ResourceExists(resource))) { + Logger.Warn("Rejecting level upload, missing resource(s)", LogArea.Publish); return this.BadRequest(); } LbpFile? rootLevel = LbpFile.FromHash(slot.RootLevel); - if (rootLevel == null) return this.BadRequest(); + if (rootLevel == null) + { + Logger.Warn("Rejecting level upload, unable to find rootLevel", LogArea.Publish); + return this.BadRequest(); + } - if (rootLevel.FileType != LbpFileType.Level) return this.BadRequest(); + if (rootLevel.FileType != LbpFileType.Level) + { + Logger.Warn("Rejecting level upload, rootLevel is not a level", LogArea.Publish); + return this.BadRequest(); + } // Republish logic if (slot.SlotId != 0) { Slot? oldSlot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slot.SlotId); - if (oldSlot == null) return this.NotFound(); + if (oldSlot == null) + { + Logger.Warn("Rejecting level republish, wasn't able to find old slot", LogArea.Publish); + return this.NotFound(); + } if (oldSlot.Location == null) throw new ArgumentNullException(); - if (oldSlot.CreatorId != user.UserId) return this.BadRequest(); + if (oldSlot.CreatorId != user.UserId) + { + Logger.Warn("Rejecting level republish, old level not owned by current user", LogArea.Publish); + return this.BadRequest(); + } oldSlot.Location.X = slot.Location.X; oldSlot.Location.Y = slot.Location.Y; @@ -166,7 +200,8 @@ public class PublishController : ControllerBase if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots) { - return this.StatusCode(403, ""); + Logger.Warn("Rejecting level upload, too many published slots", LogArea.Publish); + return this.BadRequest(); } //TODO: parse location in body @@ -197,6 +232,8 @@ public class PublishController : ControllerBase "New level published!", $"**{user.Username}** just published a new level: [**{slot.Name}**]({ServerConfiguration.Instance.ExternalUrl}/slot/{slot.SlotId})\n{slot.Description}" ); + + Logger.Success($"Successfully published level {slot.Name} (id: {slot.SlotId}) by {user.Username} (id: {user.UserId})", LogArea.Publish); return this.Ok(slot.Serialize(gameToken.GameVersion)); } diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs index d068b1da..5f3defaa 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs @@ -104,12 +104,9 @@ public class UserController : ControllerBase user.Biography = update.Biography; } - foreach (string? resource in new[] - { - update.IconHash, update.YayHash, update.MehHash, update.BooHash, update.PlanetHash, - }) + foreach (string? resource in new[]{update.IconHash, update.YayHash, update.MehHash, update.BooHash, update.PlanetHash,}) { - if (resource != null && !FileHelper.ResourceExists(resource)) return this.BadRequest(); + if (resource != null && !resource.StartsWith('g') && !FileHelper.ResourceExists(resource)) return this.BadRequest(); } if (update.IconHash != null) user.IconHash = update.IconHash; diff --git a/ProjectLighthouse.Servers.Website/Controllers/Debug/RoomVisualizerController.cs b/ProjectLighthouse.Servers.Website/Controllers/Debug/RoomVisualizerController.cs index 7039a9bf..b4772da5 100644 --- a/ProjectLighthouse.Servers.Website/Controllers/Debug/RoomVisualizerController.cs +++ b/ProjectLighthouse.Servers.Website/Controllers/Debug/RoomVisualizerController.cs @@ -46,4 +46,17 @@ public class RoomVisualizerController : ControllerBase return this.Redirect("/debug/roomVisualizer"); #endif } + + [HttpGet("createRoomsWithDuplicatePlayers")] + public async Task CreateRoomsWithDuplicatePlayers() + { + #if !DEBUG + return this.NotFound(); + #else + List users = await this.database.Users.OrderByDescending(_ => EF.Functions.Random()).Take(1).Select(u => u.UserId).ToListAsync(); + RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3); + RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3); + return this.Redirect("/debug/roomVisualizer"); + #endif + } } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Controllers/ResourcesController.cs b/ProjectLighthouse.Servers.Website/Controllers/ResourcesController.cs index 61158233..3edafd84 100644 --- a/ProjectLighthouse.Servers.Website/Controllers/ResourcesController.cs +++ b/ProjectLighthouse.Servers.Website/Controllers/ResourcesController.cs @@ -1,5 +1,4 @@ using LBPUnion.ProjectLighthouse.Files; -using LBPUnion.ProjectLighthouse.Helpers; using Microsoft.AspNetCore.Mvc; using IOFile = System.IO.File; diff --git a/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml new file mode 100644 index 00000000..67a541cf --- /dev/null +++ b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml @@ -0,0 +1,56 @@ +@page "/admin/keys" + +@using LBPUnion.ProjectLighthouse.PlayerData +@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminAPIKeyPageModel +@{ + Layout = "Layouts/BaseLayout"; + Model.Title = "API Keys"; +} + +@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery +@{ + var token = Antiforgery.GetAndStoreTokens(HttpContext).RequestToken; +} + + + +

There are @Model.KeyCount API keys registered.

+@if (Model.KeyCount == 0) +{ +

To create one, you can use the "Create API key" command in the admin panel.

+} + +
+ @foreach (APIKey key in Model.APIKeys) + { +
+
+
+ Created at: @key.Created.ToString() +
+ +

@key.Description

+
+
+ } +
diff --git a/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml.cs new file mode 100644 index 00000000..1b44968f --- /dev/null +++ b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminAPIKeyPage.cshtml.cs @@ -0,0 +1,43 @@ +using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts; +using LBPUnion.ProjectLighthouse.PlayerData; +using LBPUnion.ProjectLighthouse.PlayerData.Profiles; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin +{ + public class AdminAPIKeyPageModel : BaseLayout + { + public List APIKeys = new(); + public int KeyCount; + + public AdminAPIKeyPageModel(Database database) : base(database) + { } + + public async Task OnGet() + { + User? user = this.Database.UserFromWebRequest(this.Request); + if (user == null) return this.Redirect("~/login"); + if (!user.IsAdmin) return this.NotFound(); + + this.APIKeys = await this.Database.APIKeys.OrderByDescending(k => k.Id).ToListAsync(); + this.KeyCount = this.APIKeys.Count; + + return this.Page(); + } + + public async Task OnPost(string keyID) + { + User? user = this.Database.UserFromWebRequest(this.Request); + if (user == null || !user.IsAdmin) return this.NotFound(); + + APIKey? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyID)); + if (apiKey == null) return this.NotFound(); + this.Database.APIKeys.Remove(apiKey); + await this.Database.SaveChangesAsync(); + + return this.Page(); + } + + } +} diff --git a/ProjectLighthouse.Servers.Website/Pages/Admin/AdminPanelPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminPanelPage.cshtml.cs index 32a294f1..7451803d 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Admin/AdminPanelPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/Admin/AdminPanelPage.cshtml.cs @@ -15,7 +15,7 @@ public class AdminPanelPage : BaseLayout { public List Commands = MaintenanceHelper.Commands; public AdminPanelPage(Database database) : base(database) - {} + { } public List Statistics = new(); @@ -30,6 +30,8 @@ public class AdminPanelPage : BaseLayout this.Statistics.Add(new AdminPanelStatistic("Users", await StatisticsHelper.UserCount(), "/admin/users")); this.Statistics.Add(new AdminPanelStatistic("Slots", await StatisticsHelper.SlotCount())); this.Statistics.Add(new AdminPanelStatistic("Photos", await StatisticsHelper.PhotoCount())); + this.Statistics.Add(new AdminPanelStatistic("Reports", await StatisticsHelper.ReportCount(), "/admin/reports/0")); + this.Statistics.Add(new AdminPanelStatistic("API Keys", await StatisticsHelper.APIKeyCount(), "/admin/keys")); if (!string.IsNullOrEmpty(command)) { diff --git a/ProjectLighthouse.Servers.Website/Pages/Admin/ReportsPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/Admin/ReportsPage.cshtml index ecbe7ac8..05f5c788 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Admin/ReportsPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Admin/ReportsPage.cshtml @@ -11,7 +11,7 @@
- +
diff --git a/ProjectLighthouse.Servers.Website/Pages/Debug/RoomVisualizerPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/Debug/RoomVisualizerPage.cshtml index 9845e193..f8b81b74 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Debug/RoomVisualizerPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Debug/RoomVisualizerPage.cshtml @@ -44,6 +44,10 @@
Create Fake Room
+ +
Create Rooms With Duplicate Players
+
+
Nuke all rooms
diff --git a/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml index c881ae1e..60dbddf0 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml @@ -3,6 +3,7 @@ @using LBPUnion.ProjectLighthouse.Extensions @using LBPUnion.ProjectLighthouse.PlayerData.Profiles @using LBPUnion.ProjectLighthouse.Levels +@using LBPUnion.ProjectLighthouse.Localization.StringLists @model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LandingPage @{ @@ -10,22 +11,22 @@ Model.ShowTitleInPage = false; bool isMobile = this.Request.IsMobile(); } -

Welcome to @ServerConfiguration.Instance.Customization.ServerName!

+

@Model.Translate(LandingPageStrings.Welcome, ServerConfiguration.Instance.Customization.ServerName)

@if (Model.User != null) { -

You are currently logged in as @Model.User.Username.

- if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.AuthenticationAttemptsCount > 0) +

@Model.Translate(LandingPageStrings.LoggedInAs, Model.User.Username)

+ if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.PendingAuthAttempts > 0) {

- You have @Model.AuthenticationAttemptsCount authentication attempts pending. Click here to view them. + @Model.Translate(LandingPageStrings.AuthAttemptsPending, Model.PendingAuthAttempts)

} } @if (Model.PlayersOnlineCount == 1) { -

There is 1 user currently online:

+

@Model.Translate(LandingPageStrings.UsersSingle)

@foreach (User user in Model.PlayersOnline) { @user.Username @@ -34,11 +35,11 @@ else if (Model.PlayersOnlineCount == 0) { -

There are no users online. Why not hop on?

+

@Model.Translate(LandingPageStrings.UsersNone)

} else { -

There are currently @Model.PlayersOnlineCount users online:

+

@Model.Translate(LandingPageStrings.UsersMultiple, Model.PlayersOnlineCount)

@foreach (User user in Model.PlayersOnline) { @user.Username @@ -50,7 +51,7 @@ else
-

Latest Team Picks

+

@Model.Translate(LandingPageStrings.LatestTeamPicks)

@foreach (Slot slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@ @@ -67,7 +68,7 @@ else }
-

Newest Levels

+

@Model.Translate(LandingPageStrings.NewestLevels)

@foreach (Slot slot in Model.NewestLevels!) @* Can't reach a point where this is null *@ diff --git a/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml.cs index 20b13dbc..fecee91b 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/LandingPage.cshtml.cs @@ -15,7 +15,7 @@ public class LandingPage : BaseLayout public LandingPage(Database database) : base(database) {} - public int AuthenticationAttemptsCount; + public int PendingAuthAttempts; public List PlayersOnline = new(); public int PlayersOnlineCount; @@ -32,7 +32,7 @@ public class LandingPage : BaseLayout this.PlayersOnlineCount = await StatisticsHelper.RecentMatches(); if (user != null) - this.AuthenticationAttemptsCount = await this.Database.AuthenticationAttempts.Include + this.PendingAuthAttempts = await this.Database.AuthenticationAttempts.Include (a => a.GameToken) .CountAsync(a => a.GameToken.UserId == user.UserId); diff --git a/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml b/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml index d01032fb..d6da5335 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml @@ -1,31 +1,32 @@ @using LBPUnion.ProjectLighthouse.Configuration @using LBPUnion.ProjectLighthouse.Extensions @using LBPUnion.ProjectLighthouse.Helpers +@using LBPUnion.ProjectLighthouse.Localization.StringLists @using LBPUnion.ProjectLighthouse.Types @model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts.BaseLayout @{ if (Model!.User == null) { - Model.NavigationItemsRight.Add(new PageNavigationItem("Login / Register", "/login", "sign in")); + Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderLoginRegister, "/login", "sign in")); } else { if (ServerConfiguration.Instance.Authentication.UseExternalAuth) { - Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key")); + Model.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderAuthentication, "/authentication", "key")); } - Model.NavigationItemsRight.Add(new PageNavigationItem("Profile", "/user/" + Model.User.UserId, "user alternate")); + Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderProfile, "/user/" + Model.User.UserId, "user alternate")); @if (Model.User.IsAdmin) { - Model.NavigationItemsRight.Add(new PageNavigationItem("Admin Panel", "/admin", "cogs")); + Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderAdminPanel, "/admin", "cogs")); } - else if(Model.User.IsModerator) + else if (Model.User.IsModerator) { - Model.NavigationItemsRight.Add(new PageNavigationItem("Mod Panel", "/moderation", "user shield")); + Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderModPanel, "/moderation", "user shield")); } - Model.NavigationItemsRight.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last + Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderLogout, "/logout", "user alternate slash")); // should always be last } Model.IsMobile = Model.Request.IsMobile(); @@ -99,7 +100,7 @@ @if (!Model.IsMobile) { - @navigationItem.Name + @Model.Translate(navigationItem.Name) } } @@ -114,7 +115,7 @@ @if (!Model.IsMobile) { - @navigationItem.Name + @Model.Translate(navigationItem.Name) } } diff --git a/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml.cs index 991692da..3537e4cb 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/Layouts/BaseLayout.cshtml.cs @@ -1,22 +1,21 @@ #nullable enable +using System; +using System.Collections.Generic; +using LBPUnion.ProjectLighthouse.Configuration; +using LBPUnion.ProjectLighthouse.Localization; +using LBPUnion.ProjectLighthouse.Localization.StringLists; using LBPUnion.ProjectLighthouse.PlayerData.Profiles; using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.RazorPages; namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts; public class BaseLayout : PageModel { - public readonly Database Database; - public readonly List NavigationItems = new() - { - new PageNavigationItem("Home", "/", "home"), - new PageNavigationItem("Users", "/users/0", "user friends"), - new PageNavigationItem("Photos", "/photos/0", "camera"), - new PageNavigationItem("Levels", "/slots/0", "certificate"), - }; + public readonly List NavigationItems = new(); public readonly List NavigationItemsRight = new(); public string Description = string.Empty; @@ -31,6 +30,11 @@ public class BaseLayout : PageModel public BaseLayout(Database database) { this.Database = database; + + this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderHome, "/", "home")); + this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderUsers, "/users/0", "user friends")); + this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderPhotos, "/photos/0", "camera")); + this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "certificate")); } public new User? User { @@ -41,4 +45,17 @@ public class BaseLayout : PageModel } set => this.user = value; } + + private string getLanguage() + { + if (ServerStatics.IsUnitTesting) return "en-US"; + + IRequestCultureFeature? requestCulture = Request.HttpContext.Features.Get(); + + if (requestCulture == null) return LocalizationManager.DefaultLang; + return requestCulture.RequestCulture.UICulture.Name; + } + + public string Translate(TranslatableString translatableString) => translatableString.Translate(this.getLanguage()); + public string Translate(TranslatableString translatableString, params object?[] format) => translatableString.Translate(this.getLanguage(), format); } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml index 9dd0dfa0..cedbbdc7 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml @@ -1,21 +1,27 @@ @page "/login" @using LBPUnion.ProjectLighthouse.Configuration +@using LBPUnion.ProjectLighthouse.Localization.StringLists @model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LoginForm @{ Layout = "Layouts/BaseLayout"; - Model.Title = "Log in"; + Model.Title = Model.Translate(GeneralStrings.LogIn); } @@ -24,7 +30,7 @@ {
- Uh oh! + @Model.Translate(GeneralStrings.Error)

@Model.Error

@@ -32,19 +38,20 @@
@Html.AntiForgeryToken() +
- +
- +
- +
- +
@@ -54,15 +61,23 @@ { @await Html.PartialAsync("Partials/CaptchaPartial") } - - - @if (ServerConfiguration.Instance.Authentication.RegistrationEnabled) - { - + + +
+
- - Register + @Model.Translate(GeneralStrings.ForgotPassword)
- } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs index 6b316ad6..9d766bb5 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs @@ -22,7 +22,7 @@ public class LoginForm : BaseLayout public string? Error { get; private set; } [UsedImplicitly] - public async Task OnPost(string username, string password) + public async Task OnPost(string username, string password, string redirect) { if (string.IsNullOrWhiteSpace(username)) { @@ -105,9 +105,19 @@ public class LoginForm : BaseLayout if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired"); if (ServerConfiguration.Instance.Mail.MailEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail"); - return this.RedirectToPage(nameof(LandingPage)); + if (string.IsNullOrWhiteSpace(redirect)) + { + return this.RedirectToPage(nameof(LandingPage)); + } + return this.Redirect(redirect); } [UsedImplicitly] - public IActionResult OnGet() => this.Page(); + public IActionResult OnGet() + { + if (this.Database.UserFromWebRequest(this.Request) != null) + return this.RedirectToPage(nameof(LandingPage)); + + return this.Page(); + } } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/LogoutPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/LogoutPage.cshtml index 62f902c1..8854bcb0 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LogoutPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/LogoutPage.cshtml @@ -1,10 +1,16 @@ @page "/logout" +@using LBPUnion.ProjectLighthouse.Localization.StringLists @model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LogoutPage @{ Layout = "Layouts/BaseLayout"; - Model.Title = "Logged out"; + Model.Title = Model.Translate(LoggedOutStrings.LoggedOut); } -

You have been successfully logged out. You will be redirected in 5 seconds, or you may click here to do so manually.

+

@Model.Translate(LoggedOutStrings.LoggedOutInfo)

+ + + @Model.Translate(LoggedOutStrings.Redirect) + + \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/Partials/CaptchaPartial.cshtml b/ProjectLighthouse.Servers.Website/Pages/Partials/CaptchaPartial.cshtml index d54cebce..3a202ba9 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Partials/CaptchaPartial.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Partials/CaptchaPartial.cshtml @@ -1,6 +1,17 @@ @using LBPUnion.ProjectLighthouse.Configuration @if (ServerConfiguration.Instance.Captcha.CaptchaEnabled) { -
- + @switch (ServerConfiguration.Instance.Captcha.Type) + { + case CaptchaType.HCaptcha: +
+ + break; + case CaptchaType.ReCaptcha: +
+ + break; + default: + throw new ArgumentOutOfRangeException(); + } } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/Partials/CommentsPartial.cshtml b/ProjectLighthouse.Servers.Website/Pages/Partials/CommentsPartial.cshtml index e771e409..c1b9b962 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Partials/CommentsPartial.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Partials/CommentsPartial.cshtml @@ -1,4 +1,5 @@ @using System.Web +@using System.IO @using LBPUnion.ProjectLighthouse.PlayerData.Profiles

Comments

@@ -47,7 +48,14 @@ int rating = comment.ThumbsUp - comment.ThumbsDown;
-
+ @{ + string style = ""; + if (Model.User?.UserId == comment.PosterUserId) + { + style = "visibility: hidden"; + } + } +
diff --git a/ProjectLighthouse.Servers.Website/Pages/Partials/SlotCardPartial.cshtml b/ProjectLighthouse.Servers.Website/Pages/Partials/SlotCardPartial.cshtml index 8a1766fb..d43ddcd3 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Partials/SlotCardPartial.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Partials/SlotCardPartial.cshtml @@ -37,7 +37,9 @@ }
- + +
@if (!mini) @@ -80,7 +82,7 @@ @if (Model.GameVersion == GameVersion.LittleBigPlanet1) { - @Model.RatingLBP1 + @(Math.Round(Model.RatingLBP1 * 10) / 10) }

diff --git a/ProjectLighthouse.Servers.Website/Pages/PasswordResetPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/PasswordResetPage.cshtml.cs index 6f744979..70c1bfb3 100644 --- a/ProjectLighthouse.Servers.Website/Pages/PasswordResetPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/PasswordResetPage.cshtml.cs @@ -4,7 +4,6 @@ using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.PlayerData.Profiles; using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts; -using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages; @@ -19,8 +18,21 @@ public class PasswordResetPage : BaseLayout [UsedImplicitly] public async Task OnPost(string password, string confirmPassword) { - User? user = this.Database.UserFromWebRequest(this.Request); - if (user == null) return this.Redirect("~/login"); + User? user; + if (Request.Query.ContainsKey("token")) + { + user = await this.Database.UserFromPasswordResetToken(Request.Query["token"][0]); + if (user == null) + { + this.Error = "This password reset link either is invalid or has expired. Please try again."; + return this.Page(); + } + } + else + { + user = this.Database.UserFromWebRequest(this.Request); + if (user == null) return this.Redirect("~/login"); + } if (string.IsNullOrWhiteSpace(password)) { @@ -48,6 +60,8 @@ public class PasswordResetPage : BaseLayout [UsedImplicitly] public IActionResult OnGet() { + if (this.Request.Query.ContainsKey("token")) return this.Page(); + User? user = this.Database.UserFromWebRequest(this.Request); if (user == null) return this.Redirect("~/login"); diff --git a/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml b/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml new file mode 100644 index 00000000..22d590c2 --- /dev/null +++ b/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml @@ -0,0 +1,34 @@ +@page "/passwordResetRequest" +@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.PasswordResetRequestForm + +@{ + Layout = "Layouts/BaseLayout"; + Model.Title = "Password Reset"; +} + +@if (!string.IsNullOrWhiteSpace(Model.Error)) +{ +

+
+ Uh oh! +
+

@Model.Error

+
+} + +@if (!string.IsNullOrWhiteSpace(Model.Status)) +{ +
+
+ Success! +
+

@Model.Status

+
+} + +
+ @Html.AntiForgeryToken() + +

+ +
\ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml.cs new file mode 100644 index 00000000..e77e26d9 --- /dev/null +++ b/ProjectLighthouse.Servers.Website/Pages/PasswordResetRequestForm.cshtml.cs @@ -0,0 +1,67 @@ +using JetBrains.Annotations; +using LBPUnion.ProjectLighthouse.Configuration; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.PlayerData; +using LBPUnion.ProjectLighthouse.PlayerData.Profiles; +using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages; + +public class PasswordResetRequestForm : BaseLayout +{ + + public string? Error { get; private set; } + + public string? Status { get; private set; } + + public PasswordResetRequestForm(Database database) : base(database) + { } + + [UsedImplicitly] + public async Task OnPost(string username) + { + + if (!ServerConfiguration.Instance.Mail.MailEnabled) + { + this.Error = "Email is not configured on this server, so password resets cannot be issued. Please contact your instance administrator for more details."; + return this.Page(); + } + + if (string.IsNullOrWhiteSpace(username)) + { + this.Error = "The username field is required."; + return this.Page(); + } + + User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); + + if (user == null) + { + this.Error = "User does not exist."; + return this.Page(); + } + + PasswordResetToken token = new() + { + Created = DateTime.Now, + UserId = user.UserId, + ResetToken = CryptoHelper.GenerateAuthToken(), + }; + + string messageBody = $"Hello, {user.Username}.\n\n" + + "A request to reset your account's password was issued. If this wasn't you, this can probably be ignored.\n\n" + + $"If this was you, your {ServerConfiguration.Instance.Customization.ServerName} password can be reset at the following link:\n" + + $"{ServerConfiguration.Instance.ExternalUrl}/passwordReset?token={token.ResetToken}"; + + SMTPHelper.SendEmail(user.EmailAddress, $"Project Lighthouse Password Reset Request for {user.Username}", messageBody); + + this.Database.PasswordResetTokens.Add(token); + await this.Database.SaveChangesAsync(); + + this.Status = $"Password reset email sent to {CensorHelper.MaskEmail(user.EmailAddress)}."; + return this.Page(); + } + public void OnGet() => this.Page(); +} \ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/PhotosPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/PhotosPage.cshtml index bbcf2cd3..1d532362 100644 --- a/ProjectLighthouse.Servers.Website/Pages/PhotosPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/PhotosPage.cshtml @@ -12,7 +12,7 @@
- +
diff --git a/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml.cs index fa49b753..4bbe3efb 100644 --- a/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml.cs @@ -15,7 +15,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages; public class RegisterForm : BaseLayout { public RegisterForm(Database database) : base(database) - {} + { } public string? Error { get; private set; } @@ -23,7 +23,22 @@ public class RegisterForm : BaseLayout [SuppressMessage("ReSharper", "SpecifyStringComparison")] public async Task OnPost(string username, string password, string confirmPassword, string emailAddress) { - if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound(); + if (ServerConfiguration.Instance.Authentication.PrivateRegistration) + { + if (this.Request.Query.ContainsKey("token")) + { + if (!this.Database.IsRegistrationTokenValid(this.Request.Query["token"])) + return this.StatusCode(403, "Invalid Token"); + } + else + { + return this.NotFound(); + } + } + else if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) + { + return this.NotFound(); + } if (string.IsNullOrWhiteSpace(username)) { @@ -68,6 +83,11 @@ public class RegisterForm : BaseLayout return this.Page(); } + if (this.Request.Query.ContainsKey("token")) + { + await Database.RemoveRegistrationToken(this.Request.Query["token"]); + } + User user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress); WebToken webToken = new() @@ -91,7 +111,22 @@ public class RegisterForm : BaseLayout public IActionResult OnGet() { this.Error = string.Empty; - if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound(); + if (ServerConfiguration.Instance.Authentication.PrivateRegistration) + { + if (this.Request.Query.ContainsKey("token")) + { + if (!this.Database.IsRegistrationTokenValid(this.Request.Query["token"])) + return this.StatusCode(403, "Invalid Token"); + } + else + { + return this.NotFound(); + } + } + else if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) + { + return this.NotFound(); + } return this.Page(); } diff --git a/ProjectLighthouse.Servers.Website/Pages/SlotsPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/SlotsPage.cshtml index e92606c6..4d736f29 100644 --- a/ProjectLighthouse.Servers.Website/Pages/SlotsPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/SlotsPage.cshtml @@ -12,7 +12,7 @@
- +
diff --git a/ProjectLighthouse.Servers.Website/Pages/UsersPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/UsersPage.cshtml index 32195a8f..f59d9874 100644 --- a/ProjectLighthouse.Servers.Website/Pages/UsersPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/UsersPage.cshtml @@ -13,7 +13,7 @@
- +
diff --git a/ProjectLighthouse.Servers.Website/ProjectLighthouse.Servers.Website.csproj b/ProjectLighthouse.Servers.Website/ProjectLighthouse.Servers.Website.csproj index be32d8ff..ffd6416c 100644 --- a/ProjectLighthouse.Servers.Website/ProjectLighthouse.Servers.Website.csproj +++ b/ProjectLighthouse.Servers.Website/ProjectLighthouse.Servers.Website.csproj @@ -9,6 +9,7 @@ + @@ -32,7 +33,7 @@ - + diff --git a/ProjectLighthouse.Servers.Website/Startup/WebsiteStartup.cs b/ProjectLighthouse.Servers.Website/Startup/WebsiteStartup.cs index 97b813cc..f1f80025 100644 --- a/ProjectLighthouse.Servers.Website/Startup/WebsiteStartup.cs +++ b/ProjectLighthouse.Servers.Website/Startup/WebsiteStartup.cs @@ -1,5 +1,8 @@ +using System.Globalization; +using LBPUnion.ProjectLighthouse.Localization; using LBPUnion.ProjectLighthouse.Middlewares; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Localization; #if !DEBUG using Microsoft.Extensions.Hosting.Internal; @@ -38,6 +41,16 @@ public class WebsiteStartup } ); + services.Configure(config => + { + List languages = LocalizationManager.GetAvailableLanguages().Select(l => new CultureInfo(LocalizationManager.MapLanguage(l))).ToList(); + + config.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US")); + + config.SupportedCultures = languages; + config.SupportedUICultures = languages; + }); + #if DEBUG services.AddSingleton(); #else @@ -63,6 +76,8 @@ public class WebsiteStartup ServeUnknownFileTypes = true, }); + app.UseRequestLocalization(); + app.UseEndpoints(endpoints => endpoints.MapControllers()); app.UseEndpoints(endpoints => endpoints.MapRazorPages()); } diff --git a/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj index e81607d6..a1a4cfad 100644 --- a/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj +++ b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj @@ -9,8 +9,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj index 0ac93a3d..be7ef808 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj +++ b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj @@ -9,14 +9,14 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ProjectLighthouse.Tests.WebsiteTests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/Tests/AuthenticationTests.cs index 35a20bb4..af4c9af2 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests.WebsiteTests/Tests/AuthenticationTests.cs @@ -78,7 +78,7 @@ public class AuthenticationTests : LighthouseWebTest [DatabaseFact] public async Task ShouldLoginWithInjectedCookie() { - const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/p[1]/b"; + const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/p[1]"; await using Database database = new(); Random random = new(); @@ -96,10 +96,10 @@ public class AuthenticationTests : LighthouseWebTest INavigation navigation = this.Driver.Navigate(); navigation.GoToUrl(this.BaseAddress + "/"); + Assert.DoesNotContain(user.Username, this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text); this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken)); - Assert.Throws(() => this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath))); navigation.Refresh(); - Assert.True(this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text == user.Username); + Assert.Contains(user.Username, this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text); await database.RemoveUser(user); } diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index fd62a0a9..7b85a6a0 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -14,8 +14,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index b2f58bdc..4f163398 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -20,6 +20,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Servers", "Servers", "{1DE7 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source Code", "Source Code", "{7805B410-9260-4907-A7C6-D739369B2F25}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Localization", "ProjectLighthouse.Localization\ProjectLighthouse.Localization.csproj", "{18B76DAC-5DCB-44EA-B74D-0B4554BB161C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {FA9AEA06-D6B5-4E68-8370-DB9188108635}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA9AEA06-D6B5-4E68-8370-DB9188108635}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA9AEA06-D6B5-4E68-8370-DB9188108635}.Release|Any CPU.Build.0 = Release|Any CPU + {18B76DAC-5DCB-44EA-B74D-0B4554BB161C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18B76DAC-5DCB-44EA-B74D-0B4554BB161C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18B76DAC-5DCB-44EA-B74D-0B4554BB161C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18B76DAC-5DCB-44EA-B74D-0B4554BB161C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980} @@ -61,5 +67,6 @@ Global {FA9AEA06-D6B5-4E68-8370-DB9188108635} = {1DE7A758-1F4F-4BA5-BE1C-74F9D0AB9EA3} {1DE7A758-1F4F-4BA5-BE1C-74F9D0AB9EA3} = {7805B410-9260-4907-A7C6-D739369B2F25} {C6CFD4AD-47ED-4C86-B0C4-A4216D82E0DC} = {7805B410-9260-4907-A7C6-D739369B2F25} + {18B76DAC-5DCB-44EA-B74D-0B4554BB161C} = {7805B410-9260-4907-A7C6-D739369B2F25} EndGlobalSection EndGlobal diff --git a/ProjectLighthouse/Administration/Maintenance/Commands/CreateAPIKeyCommand.cs b/ProjectLighthouse/Administration/Maintenance/Commands/CreateAPIKeyCommand.cs new file mode 100644 index 00000000..0b5faf9b --- /dev/null +++ b/ProjectLighthouse/Administration/Maintenance/Commands/CreateAPIKeyCommand.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.PlayerData; +using LBPUnion.ProjectLighthouse.Helpers; + +namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands +{ + public class CreateAPIKeyCommand : ICommand + { + public string Name() => "Create API Key"; + public string[] Aliases() => new[] { "createAPIKey", }; + public string Arguments() => ""; + public int RequiredArgs() => 1; + + public async Task Run(string[] args, Logger logger) + { + APIKey key = new(); + key.Description = args[0]; + if (string.IsNullOrWhiteSpace(key.Description)) + { + key.Description = ""; + } + key.Key = CryptoHelper.GenerateAuthToken(); + key.Created = DateTime.Now; + Database database = new(); + await database.APIKeys.AddAsync(key); + await database.SaveChangesAsync(); + logger.LogSuccess($"The API key has been created (id: {key.Id}), however for security the token will only be shown once.", LogArea.Command); + logger.LogInfo($"Key: {key.Key}", LogArea.Command); + } + } +} + diff --git a/ProjectLighthouse/Configuration/CaptchaType.cs b/ProjectLighthouse/Configuration/CaptchaType.cs new file mode 100644 index 00000000..564d99c9 --- /dev/null +++ b/ProjectLighthouse/Configuration/CaptchaType.cs @@ -0,0 +1,16 @@ +namespace LBPUnion.ProjectLighthouse.Configuration; + +/// +/// The service to be used for presenting captchas to the user. +/// +public enum CaptchaType +{ + /// + /// A privacy-first captcha. https://www.hcaptcha.com/ + /// + HCaptcha, + /// + /// A captcha service by Google. https://developers.google.com/recaptcha/ + /// + ReCaptcha, +} \ No newline at end of file diff --git a/ProjectLighthouse/Configuration/ConfigurationCategories/AuthenticationConfiguration.cs b/ProjectLighthouse/Configuration/ConfigurationCategories/AuthenticationConfiguration.cs index c1f75473..d716a7d9 100644 --- a/ProjectLighthouse/Configuration/ConfigurationCategories/AuthenticationConfiguration.cs +++ b/ProjectLighthouse/Configuration/ConfigurationCategories/AuthenticationConfiguration.cs @@ -8,5 +8,6 @@ public class AuthenticationConfiguration public bool BlockDeniedUsers { get; set; } public bool RegistrationEnabled { get; set; } = true; + public bool PrivateRegistration { get; set; } = false; public bool UseExternalAuth { get; set; } } \ No newline at end of file diff --git a/ProjectLighthouse/Configuration/ConfigurationCategories/CaptchaConfiguration.cs b/ProjectLighthouse/Configuration/ConfigurationCategories/CaptchaConfiguration.cs index fad16ae6..fd4ea31d 100644 --- a/ProjectLighthouse/Configuration/ConfigurationCategories/CaptchaConfiguration.cs +++ b/ProjectLighthouse/Configuration/ConfigurationCategories/CaptchaConfiguration.cs @@ -2,11 +2,10 @@ namespace LBPUnion.ProjectLighthouse.Configuration.ConfigurationCategories; public class CaptchaConfiguration { - // TODO: support recaptcha, not just hcaptcha - // use an enum to define which captcha services can be used? - // LBPUnion.ProjectLighthouse.Types.Settings.CaptchaService public bool CaptchaEnabled { get; set; } + public CaptchaType Type { get; set; } = CaptchaType.HCaptcha; + public string SiteKey { get; set; } = ""; public string Secret { get; set; } = ""; diff --git a/ProjectLighthouse/Configuration/ServerConfiguration.cs b/ProjectLighthouse/Configuration/ServerConfiguration.cs index bd3ce250..30c5ee41 100644 --- a/ProjectLighthouse/Configuration/ServerConfiguration.cs +++ b/ProjectLighthouse/Configuration/ServerConfiguration.cs @@ -23,7 +23,7 @@ public class ServerConfiguration // You can use an ObsoleteAttribute instead. Make sure you set it to error, though. // // Thanks for listening~ - public const int CurrentConfigVersion = 5; + public const int CurrentConfigVersion = 7; #region Meta @@ -42,7 +42,7 @@ public class ServerConfiguration private static FileSystemWatcher fileWatcher; // ReSharper disable once NotNullMemberIsNotInitialized - #pragma warning disable CS8618 +#pragma warning disable CS8618 static ServerConfiguration() { if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own @@ -54,7 +54,7 @@ public class ServerConfiguration // If a valid YML configuration is available! if (File.Exists(ConfigFileName) && (tempConfig = fromFile(ConfigFileName)) != null) { -// Instance = JsonSerializer.Deserialize(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName)); + // Instance = JsonSerializer.Deserialize(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName)); Instance = tempConfig; if (Instance.ConfigVersion < CurrentConfigVersion) @@ -114,7 +114,7 @@ public class ServerConfiguration fileWatcher.EnableRaisingEvents = true; // begin watching } } - #pragma warning restore CS8618 +#pragma warning restore CS8618 private static void onConfigChanged(object sender, FileSystemEventArgs e) { @@ -178,11 +178,11 @@ public class ServerConfiguration public string ExternalUrl { get; set; } = "http://localhost:10060"; public bool ConfigReloading { get; set; } public string EulaText { get; set; } = ""; - #if !DEBUG +#if !DEBUG public string AnnounceText { get; set; } = "You are now logged in as %user."; - #else +#else public string AnnounceText { get; set; } = "You are now logged in as %user (id: %id)."; - #endif +#endif public bool CheckForUnsafeFiles { get; set; } = true; public FilterMode UserInputFilterMode { get; set; } = FilterMode.None; diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 5cd437be..12fbe302 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -47,6 +47,9 @@ public class Database : DbContext public DbSet EmailVerificationTokens { get; set; } public DbSet EmailSetTokens { get; set; } public DbSet Cases { get; set; } + public DbSet PasswordResetTokens { get; set; } + public DbSet RegistrationTokens { get; set; } + public DbSet APIKeys { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(ServerConfiguration.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); @@ -357,6 +360,49 @@ public class Database : DbContext return this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken); } + public async Task UserFromPasswordResetToken(string resetToken) + { + + PasswordResetToken? token = await this.PasswordResetTokens.FirstOrDefaultAsync(token => token.ResetToken == resetToken); + if (token == null) + { + return null; + } + + if (token.Created < DateTime.Now.AddHours(-1)) // if token is expired + { + this.PasswordResetTokens.Remove(token); + return null; + } + return await this.Users.FirstOrDefaultAsync(user => user.UserId == token.UserId); + } + + public bool IsRegistrationTokenValid(string tokenString) + { + RegistrationToken? token = this.RegistrationTokens.FirstOrDefault(t => t.Token == tokenString); + + if (token == null) return false; + + if (token.Created < DateTime.Now.AddDays(-7)) // if token is expired + { + this.RegistrationTokens.Remove(token); + return false; + } + + return true; + } + + public async Task RemoveRegistrationToken(string tokenString) + { + RegistrationToken? token = await this.RegistrationTokens.FirstOrDefaultAsync(t => t.Token == tokenString); + + if (token == null) return; + + this.RegistrationTokens.Remove(token); + + await this.SaveChangesAsync(); + } + #endregion public async Task PhotoFromSubject(PhotoSubject subject) diff --git a/ProjectLighthouse/Extensions/RequestExtensions.cs b/ProjectLighthouse/Extensions/RequestExtensions.cs index d375246c..c922945d 100644 --- a/ProjectLighthouse/Extensions/RequestExtensions.cs +++ b/ProjectLighthouse/Extensions/RequestExtensions.cs @@ -15,7 +15,21 @@ namespace LBPUnion.ProjectLighthouse.Extensions; public static class RequestExtensions { - + static RequestExtensions() + { + Uri captchaUri = ServerConfiguration.Instance.Captcha.Type switch + { + CaptchaType.HCaptcha => new Uri("https://hcaptcha.com"), + CaptchaType.ReCaptcha => new Uri("https://www.google.com/recaptcha/api/"), + _ => throw new ArgumentOutOfRangeException(), + }; + + client = new HttpClient + { + BaseAddress = captchaUri, + }; + } + #region Mobile Checking // yoinked and adapted from https://stackoverflow.com/a/68641796 @@ -32,10 +46,7 @@ public static class RequestExtensions #region Captcha - private static readonly HttpClient client = new() - { - BaseAddress = new Uri("https://hcaptcha.com"), - }; + private static readonly HttpClient client; [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")] private static async Task verifyCaptcha(string token) @@ -48,7 +59,7 @@ public static class RequestExtensions new("response", token), }; - HttpResponseMessage response = await client.PostAsync("/siteverify", new FormUrlEncodedContent(payload)); + HttpResponseMessage response = await client.PostAsync("siteverify", new FormUrlEncodedContent(payload)); response.EnsureSuccessStatusCode(); @@ -63,7 +74,14 @@ public static class RequestExtensions { if (ServerConfiguration.Instance.Captcha.CaptchaEnabled) { - bool gotCaptcha = request.Form.TryGetValue("h-captcha-response", out StringValues values); + string keyName = ServerConfiguration.Instance.Captcha.Type switch + { + CaptchaType.HCaptcha => "h-captcha-response", + CaptchaType.ReCaptcha => "g-recaptcha-response", + _ => throw new ArgumentOutOfRangeException(), + }; + + bool gotCaptcha = request.Form.TryGetValue(keyName, out StringValues values); if (!gotCaptcha) return false; if (!await verifyCaptcha(values[0])) return false; diff --git a/ProjectLighthouse/Helpers/CensorHelper.cs b/ProjectLighthouse/Helpers/CensorHelper.cs index 85d3db91..ae5bc821 100644 --- a/ProjectLighthouse/Helpers/CensorHelper.cs +++ b/ProjectLighthouse/Helpers/CensorHelper.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Text; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Types; @@ -94,4 +95,23 @@ public static class CensorHelper return sb.ToString(); } + + public static string MaskEmail(string email) + { + if (string.IsNullOrEmpty(email) || !email.Contains('@')) return email; + + string[] emailArr = email.Split('@'); + string domainExt = Path.GetExtension(email); + + string maskedEmail = string.Format("{0}****{1}@{2}****{3}{4}", + emailArr[0][0], + emailArr[0].Substring(emailArr[0].Length - 1), + emailArr[1][0], + emailArr[1] + .Substring(emailArr[1].Length - domainExt.Length - 1, + 1), + domainExt); + + return maskedEmail; + } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/LocalizationHelper.cs b/ProjectLighthouse/Helpers/LocalizationHelper.cs new file mode 100644 index 00000000..e22f91d8 --- /dev/null +++ b/ProjectLighthouse/Helpers/LocalizationHelper.cs @@ -0,0 +1,4 @@ +namespace LBPUnion.ProjectLighthouse.Helpers; + +public static class LocalizationHelper +{} \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/MatchHelper.cs b/ProjectLighthouse/Helpers/MatchHelper.cs index aa7d5908..45519705 100644 --- a/ProjectLighthouse/Helpers/MatchHelper.cs +++ b/ProjectLighthouse/Helpers/MatchHelper.cs @@ -36,6 +36,8 @@ public static class MatchHelper return recentlyDivedIn.Contains(otherUserId); } + public static bool ClearUserRecentDiveIns(int userId) => UserRecentlyDivedIn.Remove(userId); + // This is the function used to show people how laughably awful LBP's protocol is. Beware. public static IMatchCommand? Deserialize(string data) { diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs index d060f007..2ec0dba0 100644 --- a/ProjectLighthouse/Helpers/StatisticsHelper.cs +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -28,4 +28,6 @@ public static class StatisticsHelper public static async Task ReportCount() => await database.Reports.CountAsync(); public static async Task CaseCount() => await database.Cases.CountAsync(); #endregion + + public static async Task APIKeyCount() => await database.APIKeys.CountAsync(); } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/LogArea.cs b/ProjectLighthouse/Logging/LogArea.cs index f83c0d76..3a8a6ad6 100644 --- a/ProjectLighthouse/Logging/LogArea.cs +++ b/ProjectLighthouse/Logging/LogArea.cs @@ -21,4 +21,5 @@ public enum LogArea Redis, Command, Admin, + Publish, } \ No newline at end of file diff --git a/ProjectLighthouse/Match/Rooms/Room.cs b/ProjectLighthouse/Match/Rooms/Room.cs index 46c4d5d7..fdaf720e 100644 --- a/ProjectLighthouse/Match/Rooms/Room.cs +++ b/ProjectLighthouse/Match/Rooms/Room.cs @@ -43,7 +43,18 @@ public class Room public bool IsLookingForPlayers => this.State == RoomState.PlayingLevel || this.State == RoomState.DivingInWaiting; [JsonIgnore] - public int HostId => this.PlayerIds[0]; + public int HostId { + get { + try + { + return this.PlayerIds[0]; + } + catch + { + return -1; + } + } + } #nullable enable public override bool Equals(object? obj) diff --git a/ProjectLighthouse/Match/Rooms/RoomHelper.cs b/ProjectLighthouse/Match/Rooms/RoomHelper.cs index 33f1959c..8726c216 100644 --- a/ProjectLighthouse/Match/Rooms/RoomHelper.cs +++ b/ProjectLighthouse/Match/Rooms/RoomHelper.cs @@ -1,5 +1,7 @@ #nullable enable +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; @@ -46,10 +48,10 @@ public class RoomHelper return null; } - IEnumerable rooms = Rooms; + Random random = new(); + IEnumerable rooms = Rooms.OrderBy(_ => random.Next()); rooms = rooms.OrderBy(r => r.IsLookingForPlayers); - rooms = rooms.Where(r => r.RoomVersion == roomVersion).ToList(); if (platform != null) rooms = rooms.Where(r => r.RoomPlatform == platform).ToList(); @@ -136,6 +138,12 @@ public class RoomHelper return response; } + if (user != null) + { + MatchHelper.ClearUserRecentDiveIns(user.UserId); + Logger.Info($"Cleared {user.Username} (id: {user.UserId})'s recent dive-ins", LogArea.Match); + } + return null; } @@ -194,49 +202,94 @@ public class RoomHelper [SuppressMessage("ReSharper", "InvertIf")] public static void CleanupRooms(int? hostId = null, Room? newRoom = null, Database? database = null) { + #if DEBUG + Stopwatch stopwatch = new(); + stopwatch.Start(); + #endif lock(RoomLock) { - int roomCountBeforeCleanup = Rooms.Count(); + StorableList rooms = Rooms; // cache rooms so we dont gen a new one every time + List roomsToUpdate = new(); + + #if DEBUG + Logger.Debug($"Cleaning up rooms... (took {stopwatch.ElapsedMilliseconds}ms to get lock on {nameof(RoomLock)})", LogArea.Match); + #endif + int roomCountBeforeCleanup = rooms.Count(); // Remove offline players from rooms - foreach (Room room in Rooms) + foreach (Room room in rooms) { List players = room.GetPlayers(database ?? new Database()); - List playersToRemove = players.Where(player => player.Status.StatusType == StatusType.Offline).Select(player => player.UserId).ToList(); foreach (int player in playersToRemove) room.PlayerIds.Remove(player); + + roomsToUpdate.Add(room); + } + + // DO NOT REMOVE ROOMS BEFORE THIS POINT! + // this will cause the room to be added back to the database + foreach (Room room in roomsToUpdate) + { + rooms.Update(room); } // Delete old rooms based on host if (hostId != null) + { try { - Rooms.RemoveAll(r => r.HostId == hostId); + rooms.RemoveAll(r => r.PlayerIds.Contains((int)hostId)); } catch { // TODO: detect the room that failed and remove it } + } - // Remove players in this new room from other rooms + // Remove rooms containing players in this new room if (newRoom != null) - foreach (Room room in Rooms) - { - if (room == newRoom) continue; - - foreach (int newRoomPlayer in newRoom.PlayerIds) room.PlayerIds.RemoveAll(p => p == newRoomPlayer); - } - - Rooms.RemoveAll(r => r.PlayerIds.Count == 0); // Remove empty rooms - Rooms.RemoveAll(r => r.PlayerIds.Count > 4); // Remove obviously bogus rooms - - int roomCountAfterCleanup = Rooms.Count(); - - if (roomCountBeforeCleanup != roomCountAfterCleanup) { - Logger.Debug($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", - LogArea.Match); + foreach (Room room in rooms.Where(room => room != newRoom)) + { + foreach (int newRoomPlayer in newRoom.PlayerIds) + { + if (room.PlayerIds.Contains(newRoomPlayer)) rooms.Remove(room); + } + } + } + + rooms.RemoveAll(r => r.PlayerIds.Count == 0); // Remove empty rooms + rooms.RemoveAll(r => r.HostId == -1); // Remove rooms with broken hosts + rooms.RemoveAll(r => r.PlayerIds.Count > 4); // Remove obviously bogus rooms + + int roomCountAfterCleanup = rooms.Count(); + + // Log the amount of rooms cleaned up. + // If we didnt clean any rooms, it's not useful to log in a + // production environment but it's still quite useful for debugging. + // + // So, we handle that case here: + int roomsCleanedUp = roomCountBeforeCleanup - roomCountAfterCleanup; + string logText = $"Cleaned up {roomsCleanedUp} rooms."; + + if (roomsCleanedUp == 0) + { + Logger.Debug(logText, LogArea.Match); + } + else + { + Logger.Info(logText, LogArea.Match); + } + + logText = $"Updated {roomsToUpdate.Count} rooms."; + if (roomsToUpdate.Count == 0) + { + Logger.Debug(logText, LogArea.Match); + } + else + { + Logger.Info(logText, LogArea.Match); } } } diff --git a/ProjectLighthouse/Migrations/20220624210701_AddedPasswordResetTokens.cs b/ProjectLighthouse/Migrations/20220624210701_AddedPasswordResetTokens.cs new file mode 100644 index 00000000..35a27a01 --- /dev/null +++ b/ProjectLighthouse/Migrations/20220624210701_AddedPasswordResetTokens.cs @@ -0,0 +1,41 @@ +using System; +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20220624210701_AddedPasswordResetTokens")] + public partial class AddedPasswordResetTokens : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PasswordResetTokens", + columns: table => new + { + TokenId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "int", nullable: false), + ResetToken = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Created = table.Column(type: "datetime(6)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PasswordResetTokens", x => x.TokenId); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PasswordResetTokens"); + } + } +} diff --git a/ProjectLighthouse/Migrations/20220715222906_UserInvite.cs b/ProjectLighthouse/Migrations/20220715222906_UserInvite.cs new file mode 100644 index 00000000..98312088 --- /dev/null +++ b/ProjectLighthouse/Migrations/20220715222906_UserInvite.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Infrastructure; +using LBPUnion.ProjectLighthouse; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20220715222906_UserInvite")] + public partial class UserInvite : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "APIKeys", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Description = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Key = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Created = table.Column(type: "datetime(6)", nullable: false), + Enabled = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_APIKeys", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "RegistrationTokens", + columns: table => new + { + TokenId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Token = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Created = table.Column(type: "datetime(6)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RegistrationTokens", x => x.TokenId); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "APIKeys"); + + migrationBuilder.DropTable( + name: "RegistrationTokens"); + } + } +} diff --git a/ProjectLighthouse/Migrations/20220716234844_RemovedAPIKeyEnabled.cs b/ProjectLighthouse/Migrations/20220716234844_RemovedAPIKeyEnabled.cs new file mode 100644 index 00000000..fc3f2ee1 --- /dev/null +++ b/ProjectLighthouse/Migrations/20220716234844_RemovedAPIKeyEnabled.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore.Infrastructure; +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20220716234844_RemovedAPIKeyEnabled")] + public partial class RemovedAPIKeyEnabled : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Enabled", + table: "APIKeys"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Enabled", + table: "APIKeys", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + } + } +} diff --git a/ProjectLighthouse/PlayerData/APIKey.cs b/ProjectLighthouse/PlayerData/APIKey.cs new file mode 100644 index 00000000..156d8766 --- /dev/null +++ b/ProjectLighthouse/PlayerData/APIKey.cs @@ -0,0 +1,19 @@ + +using System; +using System.ComponentModel.DataAnnotations; + +namespace LBPUnion.ProjectLighthouse.PlayerData +{ + public class APIKey + { + [Key] + public int Id { get; set; } + + public string Description { get; set; } + + public string Key { get; set; } + + public DateTime Created { get; set; } + } +} + diff --git a/ProjectLighthouse/PlayerData/PasswordResetToken.cs b/ProjectLighthouse/PlayerData/PasswordResetToken.cs new file mode 100644 index 00000000..9b07cead --- /dev/null +++ b/ProjectLighthouse/PlayerData/PasswordResetToken.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace LBPUnion.ProjectLighthouse.PlayerData; + +public class PasswordResetToken +{ + // ReSharper disable once UnusedMember.Global + [Key] + public int TokenId { get; set; } + + public int UserId { get; set; } + + public string ResetToken { get; set; } + + public DateTime Created { get; set; } +} \ No newline at end of file diff --git a/ProjectLighthouse/PlayerData/RegistrationToken.cs b/ProjectLighthouse/PlayerData/RegistrationToken.cs new file mode 100644 index 00000000..6e0bd7f6 --- /dev/null +++ b/ProjectLighthouse/PlayerData/RegistrationToken.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace LBPUnion.ProjectLighthouse.PlayerData +{ + public class RegistrationToken + { + [Key] + public int TokenId { get; set; } + + public string Token { get; set; } + + public DateTime Created { get; set; } + } +} + diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 78fcd468..94563456 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -12,19 +12,19 @@ - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - + + @@ -50,6 +50,10 @@ + + + + diff --git a/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs b/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs index 83004d75..7bde9ec0 100644 --- a/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs +++ b/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs @@ -16,7 +16,7 @@ namespace ProjectLighthouse.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("ProductVersion", "6.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("LBPUnion.ProjectLighthouse.Administration.CompletedMigration", b => @@ -363,6 +363,26 @@ namespace ProjectLighthouse.Migrations b.ToTable("VisitedLevels"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.APIKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("APIKeys"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.AuthenticationAttempt", b => { b.Property("AuthenticationAttemptId") @@ -422,6 +442,26 @@ namespace ProjectLighthouse.Migrations b.ToTable("GameTokens"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.PasswordResetToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("ResetToken") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("TokenId"); + + b.ToTable("PasswordResetTokens"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.Photo", b => { b.Property("PhotoId") @@ -715,6 +755,23 @@ namespace ProjectLighthouse.Migrations b.ToTable("Reactions"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.RegistrationToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("RegistrationTokens"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.PlayerData.Reviews.RatedReview", b => { b.Property("RatedReviewId") diff --git a/ProjectLighthouse/StaticFiles/assets/slotCardBackground.png b/ProjectLighthouse/StaticFiles/assets/slotCardBackground.png new file mode 100644 index 00000000..9d0174cb Binary files /dev/null and b/ProjectLighthouse/StaticFiles/assets/slotCardBackground.png differ diff --git a/ProjectLighthouse/StaticFiles/assets/slotCardOverlay.png b/ProjectLighthouse/StaticFiles/assets/slotCardOverlay.png index f1a6adb0..a2f1f3e2 100644 Binary files a/ProjectLighthouse/StaticFiles/assets/slotCardOverlay.png and b/ProjectLighthouse/StaticFiles/assets/slotCardOverlay.png differ diff --git a/ProjectLighthouse/StorableLists/RedisStorableList.cs b/ProjectLighthouse/StorableLists/RedisStorableList.cs index c6938f28..7bbc4c10 100644 --- a/ProjectLighthouse/StorableLists/RedisStorableList.cs +++ b/ProjectLighthouse/StorableLists/RedisStorableList.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Redis.OM.Searching; @@ -17,15 +18,15 @@ public class RedisStorableList : StorableList this.redisNormalCollection.Insert(item); } - public override Task RemoveAsync(T item) => this.redisNormalCollection.Delete(item); + public override Task RemoveAsync(T item) => this.redisNormalCollection.DeleteAsync(item); public override void Remove(T item) { - this.redisNormalCollection.DeleteSync(item); + this.redisNormalCollection.Delete(item); } - public override Task UpdateAsync(T item) => this.redisNormalCollection.Update(item); + public override Task UpdateAsync(T item) => this.redisNormalCollection.UpdateAsync(item); public override void Update(T item) { - this.redisNormalCollection.UpdateSync(item); + this.redisNormalCollection.Update(item); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/PageNavigationItem.cs b/ProjectLighthouse/Types/PageNavigationItem.cs index 11068c0a..c7ad4c5d 100644 --- a/ProjectLighthouse/Types/PageNavigationItem.cs +++ b/ProjectLighthouse/Types/PageNavigationItem.cs @@ -1,16 +1,18 @@ +using LBPUnion.ProjectLighthouse.Localization; + #nullable enable namespace LBPUnion.ProjectLighthouse.Types; public class PageNavigationItem { - public PageNavigationItem(string name, string url, string? icon = null) + public PageNavigationItem(TranslatableString name, string url, string? icon = null) { this.Name = name; this.Url = url; this.Icon = icon; } - public string Name { get; set; } + public TranslatableString Name { get; set; } public string Url { get; set; } public string? Icon { get; set; } } \ No newline at end of file diff --git a/README.md b/README.md index 903e3baf..a91d5d3d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ environment until release**. This is because we have not entirely nailed security down yet, and **your instance WILL get attacked** as a result. It's happened before, and it'll happen again. -Simply put, **Project Lighthouse is not ready for the general public yet**. +Simply put, **Project Lighthouse is not ready for the public yet**. In addition, we're not responsible if someone hacks your machine and wipes your database, so make frequent backups, and be sure to report any vulnerabilities. Thank you in advance. @@ -61,12 +61,12 @@ information. ## Compatibility across games and platforms -| Game | Console (PS3/Vita/PSP) | Emulator (RPCS3/Vita3k/PPSSPP) | Next-Gen (PS4/PS5/Vita) | -|----------|-------------------------------------|--------------------------------------------------------------|-------------------------| -| LBP1 | Compatible | Compatible with patched RPCS3 build | No next-gen equivalent | -| LBP2 | Compatible | Compatible with patched RPCS3 build | No next-gen equivalent | -| LBP3 | Mostly compatible, frequent crashes | Mostly compatible with patched RPCS3 build, frequent crashes | Incompatible | -| LBP Vita | Compatible | Incompatible, marked as "Intro" on Vita3k | No next-gen equivalent | -| LBP PSP | Potentially compatible | Incompatible, PSN not supported on PPSSPP | Potentially Compatible | +| Game | Console (PS3/Vita/PSP) | Emulator (RPCS3/Vita3k/PPSSPP) | Next-Gen (PS4/PS5/Adrenaline) | +|----------|------------------------|-------------------------------------------|-------------------------------| +| LBP1 | Compatible | Compatible | No next-gen equivalent | +| LBP2 | Compatible | Compatible | No next-gen equivalent | +| LBP3 | Mostly compatible | Mostly compatible | Incompatible | +| LBP Vita | Compatible | Incompatible, PSN not supported on Vita3k | No next-gen equivalent | +| LBP PSP | Potentially compatible | Incompatible, PSN not supported on PPSSPP | Potentially Compatible | Project Lighthouse is mostly a work in progress, so this chart is subject to change at any point. diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..2e6c5d14 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,6 @@ +preserve_hierarchy: true +files: + - source: /ProjectLighthouse.Localization/*.resx + translation: /ProjectLighthouse.Localization/%file_name%.lang-%locale%.%file_extension% + ignore: + - /ProjectLighthouse.Localization/%file_name%.*.%file_extension%