diff options
Diffstat (limited to 'lib')
39 files changed, 534 insertions, 154 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index b500c7a5fd1..4903006e066 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -661,6 +661,8 @@ return array( 'OC\\AppFramework\\Utility\\ControllerMethodReflector' => $baseDir . '/lib/private/AppFramework/Utility/ControllerMethodReflector.php', 'OC\\AppFramework\\Utility\\SimpleContainer' => $baseDir . '/lib/private/AppFramework/Utility/SimpleContainer.php', 'OC\\AppFramework\\Utility\\TimeFactory' => $baseDir . '/lib/private/AppFramework/Utility/TimeFactory.php', + 'OC\\AppScriptDependency' => $baseDir . '/lib/private/AppScriptDependency.php', + 'OC\\AppScriptSort' => $baseDir . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => $baseDir . '/lib/private/App/AppManager.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => $baseDir . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => $baseDir . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 022cde29569..c522da4dcef 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -690,6 +690,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\AppFramework\\Utility\\ControllerMethodReflector' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/ControllerMethodReflector.php', 'OC\\AppFramework\\Utility\\SimpleContainer' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/SimpleContainer.php', 'OC\\AppFramework\\Utility\\TimeFactory' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/TimeFactory.php', + 'OC\\AppScriptDependency' => __DIR__ . '/../../..' . '/lib/private/AppScriptDependency.php', + 'OC\\AppScriptSort' => __DIR__ . '/../../..' . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => __DIR__ . '/../../..' . '/lib/private/App/AppManager.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', diff --git a/lib/l10n/cs.js b/lib/l10n/cs.js index 514c87abf4e..98d63d0d5c1 100644 --- a/lib/l10n/cs.js +++ b/lib/l10n/cs.js @@ -87,7 +87,7 @@ OC.L10N.register( "Empty filename is not allowed" : "Je třeba vyplnit název souboru", "App \"%s\" cannot be installed because appinfo file cannot be read." : "Aplikace „%s“ nemůže být nainstalována protože soubor appinfo nelze přečíst.", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Aplikaci „%s“ nelze nainstalovat, protože není kompatibilní s touto verzí serveru.", - "__language_name__" : "čeština", + "__language_name__" : "Čeština", "This is an automatically sent email, please do not reply." : "Toto je automaticky odesílaný e-mail, neodpovídejte na něj.", "Help" : "Nápověda", "Apps" : "Aplikace", diff --git a/lib/l10n/cs.json b/lib/l10n/cs.json index 56fa0b2a74c..dbfbb2af3d9 100644 --- a/lib/l10n/cs.json +++ b/lib/l10n/cs.json @@ -85,7 +85,7 @@ "Empty filename is not allowed" : "Je třeba vyplnit název souboru", "App \"%s\" cannot be installed because appinfo file cannot be read." : "Aplikace „%s“ nemůže být nainstalována protože soubor appinfo nelze přečíst.", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Aplikaci „%s“ nelze nainstalovat, protože není kompatibilní s touto verzí serveru.", - "__language_name__" : "čeština", + "__language_name__" : "Čeština", "This is an automatically sent email, please do not reply." : "Toto je automaticky odesílaný e-mail, neodpovídejte na něj.", "Help" : "Nápověda", "Apps" : "Aplikace", diff --git a/lib/l10n/es.js b/lib/l10n/es.js index ad321a6d2a6..d02834e19c6 100644 --- a/lib/l10n/es.js +++ b/lib/l10n/es.js @@ -3,15 +3,15 @@ OC.L10N.register( { "Cannot write into \"config\" directory!" : "No se puede escribir en la carpeta \"config\"!", "This can usually be fixed by giving the webserver write access to the config directory." : "Se podría solucionar esto dándole al servidor permisos de escritura del directorio de configuración.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Pero, si prefieres mantener el archivo config.php con permisos solo de lectura, establece la opción \"config_is_read_only\" a true en él.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Pero, si prefieres mantener el archivo config.php como solo de lectura, establece la opción \"config_is_read_only\" a true en él.", "See %s" : "Ver %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la app %1$s no se han reemplazado correctamente. Asegúrate de que es una versión compatible con el servidor.", "Sample configuration detected" : "Configuración de ejemplo detectada", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Se ha detectado que el ejemplo de configuración ha sido copiado. Esto podría afectar a su instalación, por lo que no tiene soporte. Lea la documentación antes de hacer cambios en config.php", "%s email verification" : "%s verificación del correo electrónico", "Email verification" : "Verificación del correo electrónico", - "Click the following button to confirm your email." : "Haz clic en el botón siguiente para confirmar tu correo electrónico.", - "Click the following link to confirm your email." : "Haz clic en el enlace siguiente para confirmar tu correo electrónico.", + "Click the following button to confirm your email." : "Haz clic en el siguiente botón para confirmar tu correo electrónico.", + "Click the following link to confirm your email." : "Haz clic en el siguiente enlace para confirmar tu correo electrónico.", "Confirm your email" : "Confirma tu correo electrónico", "Other activities" : "Otras actividades", "%1$s and %2$s" : "%1$s y %2$s", @@ -103,8 +103,8 @@ OC.L10N.register( "Website" : "Sitio web", "Visit %s" : "Visita %s", "Address" : "Dirección", - "Profile picture" : "Fotografía de perfil", - "About" : "Sobre", + "Profile picture" : "Imagen de perfil", + "About" : "Acerca de", "Full name" : "Nombre completo", "Headline" : "Titular", "Organisation" : "Organización", @@ -217,6 +217,7 @@ OC.L10N.register( "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "O, si prefieres mantener el archivo config.php como de solo lectura, marca la opción \"config_is_read_only\" a 'true' en él. Ver %s", "Cannot write into \"apps\" directory" : "No se puede escribir en el directorio de \"apps\"", "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "Se podría solucionar esto dando al servidor web acceso de escritura a la carpeta de apps o desactivando la tienda de apps en el archivo de configuración.", + "Cannot create \"data\" directory." : "No se puede crear la carpeta \"data\"", "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "Habitualmente, esto puede arreglarse dando al servidor web acceso de escritura al directorio raíz. Véase %s", "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Habitualmente, los permisos pueden arreglarse dando al servidor web acceso de escritura al directorio raíz. Véase %s", "Setting locale to %s failed" : "Ha fallado la activación de la localización %s ", diff --git a/lib/l10n/es.json b/lib/l10n/es.json index 19c6d6c1f03..9f72496f986 100644 --- a/lib/l10n/es.json +++ b/lib/l10n/es.json @@ -1,15 +1,15 @@ { "translations": { "Cannot write into \"config\" directory!" : "No se puede escribir en la carpeta \"config\"!", "This can usually be fixed by giving the webserver write access to the config directory." : "Se podría solucionar esto dándole al servidor permisos de escritura del directorio de configuración.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Pero, si prefieres mantener el archivo config.php con permisos solo de lectura, establece la opción \"config_is_read_only\" a true en él.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Pero, si prefieres mantener el archivo config.php como solo de lectura, establece la opción \"config_is_read_only\" a true en él.", "See %s" : "Ver %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la app %1$s no se han reemplazado correctamente. Asegúrate de que es una versión compatible con el servidor.", "Sample configuration detected" : "Configuración de ejemplo detectada", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Se ha detectado que el ejemplo de configuración ha sido copiado. Esto podría afectar a su instalación, por lo que no tiene soporte. Lea la documentación antes de hacer cambios en config.php", "%s email verification" : "%s verificación del correo electrónico", "Email verification" : "Verificación del correo electrónico", - "Click the following button to confirm your email." : "Haz clic en el botón siguiente para confirmar tu correo electrónico.", - "Click the following link to confirm your email." : "Haz clic en el enlace siguiente para confirmar tu correo electrónico.", + "Click the following button to confirm your email." : "Haz clic en el siguiente botón para confirmar tu correo electrónico.", + "Click the following link to confirm your email." : "Haz clic en el siguiente enlace para confirmar tu correo electrónico.", "Confirm your email" : "Confirma tu correo electrónico", "Other activities" : "Otras actividades", "%1$s and %2$s" : "%1$s y %2$s", @@ -101,8 +101,8 @@ "Website" : "Sitio web", "Visit %s" : "Visita %s", "Address" : "Dirección", - "Profile picture" : "Fotografía de perfil", - "About" : "Sobre", + "Profile picture" : "Imagen de perfil", + "About" : "Acerca de", "Full name" : "Nombre completo", "Headline" : "Titular", "Organisation" : "Organización", @@ -215,6 +215,7 @@ "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "O, si prefieres mantener el archivo config.php como de solo lectura, marca la opción \"config_is_read_only\" a 'true' en él. Ver %s", "Cannot write into \"apps\" directory" : "No se puede escribir en el directorio de \"apps\"", "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "Se podría solucionar esto dando al servidor web acceso de escritura a la carpeta de apps o desactivando la tienda de apps en el archivo de configuración.", + "Cannot create \"data\" directory." : "No se puede crear la carpeta \"data\"", "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "Habitualmente, esto puede arreglarse dando al servidor web acceso de escritura al directorio raíz. Véase %s", "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Habitualmente, los permisos pueden arreglarse dando al servidor web acceso de escritura al directorio raíz. Véase %s", "Setting locale to %s failed" : "Ha fallado la activación de la localización %s ", diff --git a/lib/l10n/ja.js b/lib/l10n/ja.js index 8edd47fbc5b..99eb5ddeab4 100644 --- a/lib/l10n/ja.js +++ b/lib/l10n/ja.js @@ -1,13 +1,18 @@ OC.L10N.register( "lib", { - "Cannot write into \"config\" directory!" : "\"config\"ディレクトリに書き込めません!", - "This can usually be fixed by giving the webserver write access to the config directory." : "多くの場合、これはWebサーバーにconfigディレクトリへの書き込み権限を与えることで解決できます。", + "Cannot write into \"config\" directory!" : "\"config\"ディレクトリに書き込むことは出来ません!", + "This can usually be fixed by giving the webserver write access to the config directory." : "Webサーバーにconfigディレクトリへの書き込み権限を与えることで解決する可能性があります。", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "しかし、config.phpファイルを読み取り専用にしたい場合は、オプションの \"config_is_read_only\"をtrueに設定してください。", "See %s" : "%s を閲覧", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "アプリ %1$s のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。", "Sample configuration detected" : "サンプル設定が見つかりました。", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "サンプル設定がコピーされてそのままです。このままではインストールが失敗し、サポート対象外になります。config.phpを変更する前にドキュメントを確認してください。", + "%s email verification" : "%sメールによる確認", + "Email verification" : "メールによる確認", + "Click the following button to confirm your email." : "下記のボタンをクリックして、メールを確認してください。", + "Click the following link to confirm your email." : "下記のリンクをクリックして、メールを確認してください。", + "Confirm your email" : "メールを確認", "Other activities" : "その他のアクティビティ", "%1$s and %2$s" : "%1$s と %2$s", "%1$s, %2$s and %3$s" : "%1$s と %2$s、%3$s", @@ -30,6 +35,7 @@ OC.L10N.register( "The following platforms are supported: %s" : "次のプラットフォームをサポートしています: %s", "Server version %s or higher is required." : "サーバーの %s よりも高いバージョンが必要です。", "Server version %s or lower is required." : "サーバーの %s よりも低いバージョンが必要です。", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", "Wiping of device %s has started" : "端末%sのワイプを開始しました。", @@ -48,6 +54,7 @@ OC.L10N.register( "Unknown filetype" : "不明なファイルタイプ", "Invalid image" : "無効な画像", "Avatar image is not square" : "アバター画像が正方形ではありません", + "View profile" : "プロフィールを表示", "today" : "今日", "tomorrow" : "明日", "yesterday" : "昨日", @@ -76,7 +83,7 @@ OC.L10N.register( "File name is a reserved word" : "ファイル名が予約された単語です", "File name contains at least one invalid character" : "ファイル名に1文字以上の無効な文字が含まれています", "File name is too long" : "ファイル名が長すぎます", - "Dot files are not allowed" : "ドットファイルは許可されていません", + "Dot files are not allowed" : "隠しファイルは許可されていません", "Empty filename is not allowed" : "空のファイル名は許可されていません", "App \"%s\" cannot be installed because appinfo file cannot be read." : "appinfoファイルが読み込めないため、アプリ名 \"%s\" がインストールできません。", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "\"%s\" アプリは、このバージョンのサーバーと互換性がないためインストールされませんでした。", @@ -87,6 +94,21 @@ OC.L10N.register( "Settings" : "設定", "Log out" : "ログアウト", "Users" : "ユーザー", + "Email" : "メール", + "Mail %s" : "メール %s", + "Phone" : "携帯", + "Call %s" : "電話 %s", + "Twitter" : "Twitter", + "View %s on Twitter" : "Twitterで%sを表示", + "Website" : "ウェブサイト", + "Visit %s" : "訪問先 %s", + "Address" : "アドレス", + "Profile picture" : "プロフィールの写真", + "About" : "詳細", + "Full name" : "フルネーム", + "Headline" : "見出し", + "Organisation" : "組織", + "Role" : "ロール", "Unknown user" : "不明なユーザー", "Additional settings" : "追加設定", "%s enter the database username and name." : "%s データベース名とデータベースのユーザー名を入力してください。", @@ -171,19 +193,19 @@ OC.L10N.register( "Oct." : "10月", "Nov." : "11月", "Dec." : "12月", - "The user limit has been reached and the user was not created." : "ユーザー制限に達し、ユーザーは作成されませんでした。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", + "The user limit has been reached and the user was not created." : "ユーザー数の上限に達したためユーザーを作成出来ませんでした。", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", "A valid username must be provided" : "有効なユーザー名を指定する必要があります", "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", - "Username must not consist of dots only" : "ユーザー名は、ドットのみではつけられません", - "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、ユーザー名は無効です", + "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", + "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", "A valid password must be provided" : "有効なパスワードを指定する必要があります", - "The username is already being used" : "ユーザー名はすでに使われています", + "The username is already being used" : "このユーザー名はすでに使われています", "Could not create user" : "ユーザーを作成できませんでした", "User disabled" : "ユーザーは無効です", "Login canceled by app" : "アプリによりログインが中止されました", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "次の依存関係を満たしていないため、アプリ \"%1$s\" をインストールできません: %2$s", - "a safe home for all your data" : "あらゆるデータを安全に保管します", + "a safe home for all your data" : "すべてのデータを安全に保管します", "File is currently busy, please try again later" : "現在ファイルはビジーです。後でもう一度試してください。", "Cannot read file" : "ファイルを読み込めません", "Application is not enabled" : "アプリケーションは無効です", @@ -192,16 +214,17 @@ OC.L10N.register( "No database drivers (sqlite, mysql, or postgresql) installed." : "データベースドライバー (sqlite, mysql, postgresql) がインストールされていません。", "Cannot write into \"config\" directory" : "\"config\" ディレクトリに書き込みができません", "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "多くの場合、Webサーバーの configディレクトリ に書き込み権限を与えることで直ります。%s を見てください", - "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "またはconfig.phpファイルを読み取り専用にしたい場合は、オプション \"config_is_read_only\"をtrueに設定してください。 %sを参照してください", + "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "またはconfig.phpファイルを読み取り専用にしたい場合は、オプション \"config_is_read_only\"をtrueに設定してください。 詳しくは%sを確認してください。", "Cannot write into \"apps\" directory" : "\"apps\" ディレクトリに書き込みができません", - "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "これは通常、Webサーバーにappsディレクトリへの書き込み権限を許可するか、構成ファイルでAppStoreを無効にすることで解決できます。", - "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "多くの場合、Webサーバーのルートディレクトリに書き込み権限を与えることで直ります。%s を見てください。", - "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Webサーバーのルートディレクトリに書き込み権限パーミッションが必要です。%s を見てください。", + "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "Webサーバーにappsディレクトリへの書き込み権限を許可するか、構成ファイルでAppStoreを無効にすることで解決する可能性があります。", + "Cannot create \"data\" directory." : "dataディレクトリを作成できません。", + "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "多くの場合、Webサーバーのルートディレクトリに書き込み権限を与えることで直ります。詳しくは%sを確認してください。", + "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Webサーバーのルートディレクトリに書き込み権限パーミッションが必要です。詳しくは%sを確認してください。", "Setting locale to %s failed" : "ロケールを %s に設定できませんでした", "Please install one of these locales on your system and restart your webserver." : "これらのロケールのうちいずれかをシステムにインストールし、Webサーバーを再起動してください。", - "PHP module %s not installed." : "PHP のモジュール %s がインストールされていません。", + "PHP module %s not installed." : "PHP のモジュールの %s がインストールされていません。", "Please ask your server administrator to install the module." : "サーバー管理者にモジュールのインストールを依頼してください。", - "PHP setting \"%s\" is not set to \"%s\"." : "PHP設定の\"%s\"は \"%s\"に設定されていません", + "PHP setting \"%s\" is not set to \"%s\"." : "PHP設定の\"%s\"が \"%s\"に設定されていません", "Adjusting this setting in php.ini will make Nextcloud run again" : "php.ini のこの設定を調整して、再度 Nextcloudを起動してください。", "mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload の値は \"0\" であるべきですが、\"%s\" に設定されています", "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "この問題を修正するには、php.ini ファイルの <code>mbstring.func_overload</code> を <code>0</code> に設定してください。", diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json index 1d2e99a63ff..1d96ca213e1 100644 --- a/lib/l10n/ja.json +++ b/lib/l10n/ja.json @@ -1,11 +1,16 @@ { "translations": { - "Cannot write into \"config\" directory!" : "\"config\"ディレクトリに書き込めません!", - "This can usually be fixed by giving the webserver write access to the config directory." : "多くの場合、これはWebサーバーにconfigディレクトリへの書き込み権限を与えることで解決できます。", + "Cannot write into \"config\" directory!" : "\"config\"ディレクトリに書き込むことは出来ません!", + "This can usually be fixed by giving the webserver write access to the config directory." : "Webサーバーにconfigディレクトリへの書き込み権限を与えることで解決する可能性があります。", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "しかし、config.phpファイルを読み取り専用にしたい場合は、オプションの \"config_is_read_only\"をtrueに設定してください。", "See %s" : "%s を閲覧", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "アプリ %1$s のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。", "Sample configuration detected" : "サンプル設定が見つかりました。", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "サンプル設定がコピーされてそのままです。このままではインストールが失敗し、サポート対象外になります。config.phpを変更する前にドキュメントを確認してください。", + "%s email verification" : "%sメールによる確認", + "Email verification" : "メールによる確認", + "Click the following button to confirm your email." : "下記のボタンをクリックして、メールを確認してください。", + "Click the following link to confirm your email." : "下記のリンクをクリックして、メールを確認してください。", + "Confirm your email" : "メールを確認", "Other activities" : "その他のアクティビティ", "%1$s and %2$s" : "%1$s と %2$s", "%1$s, %2$s and %3$s" : "%1$s と %2$s、%3$s", @@ -28,6 +33,7 @@ "The following platforms are supported: %s" : "次のプラットフォームをサポートしています: %s", "Server version %s or higher is required." : "サーバーの %s よりも高いバージョンが必要です。", "Server version %s or lower is required." : "サーバーの %s よりも低いバージョンが必要です。", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", "Wiping of device %s has started" : "端末%sのワイプを開始しました。", @@ -46,6 +52,7 @@ "Unknown filetype" : "不明なファイルタイプ", "Invalid image" : "無効な画像", "Avatar image is not square" : "アバター画像が正方形ではありません", + "View profile" : "プロフィールを表示", "today" : "今日", "tomorrow" : "明日", "yesterday" : "昨日", @@ -74,7 +81,7 @@ "File name is a reserved word" : "ファイル名が予約された単語です", "File name contains at least one invalid character" : "ファイル名に1文字以上の無効な文字が含まれています", "File name is too long" : "ファイル名が長すぎます", - "Dot files are not allowed" : "ドットファイルは許可されていません", + "Dot files are not allowed" : "隠しファイルは許可されていません", "Empty filename is not allowed" : "空のファイル名は許可されていません", "App \"%s\" cannot be installed because appinfo file cannot be read." : "appinfoファイルが読み込めないため、アプリ名 \"%s\" がインストールできません。", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "\"%s\" アプリは、このバージョンのサーバーと互換性がないためインストールされませんでした。", @@ -85,6 +92,21 @@ "Settings" : "設定", "Log out" : "ログアウト", "Users" : "ユーザー", + "Email" : "メール", + "Mail %s" : "メール %s", + "Phone" : "携帯", + "Call %s" : "電話 %s", + "Twitter" : "Twitter", + "View %s on Twitter" : "Twitterで%sを表示", + "Website" : "ウェブサイト", + "Visit %s" : "訪問先 %s", + "Address" : "アドレス", + "Profile picture" : "プロフィールの写真", + "About" : "詳細", + "Full name" : "フルネーム", + "Headline" : "見出し", + "Organisation" : "組織", + "Role" : "ロール", "Unknown user" : "不明なユーザー", "Additional settings" : "追加設定", "%s enter the database username and name." : "%s データベース名とデータベースのユーザー名を入力してください。", @@ -169,19 +191,19 @@ "Oct." : "10月", "Nov." : "11月", "Dec." : "12月", - "The user limit has been reached and the user was not created." : "ユーザー制限に達し、ユーザーは作成されませんでした。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", + "The user limit has been reached and the user was not created." : "ユーザー数の上限に達したためユーザーを作成出来ませんでした。", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", "A valid username must be provided" : "有効なユーザー名を指定する必要があります", "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", - "Username must not consist of dots only" : "ユーザー名は、ドットのみではつけられません", - "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、ユーザー名は無効です", + "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", + "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", "A valid password must be provided" : "有効なパスワードを指定する必要があります", - "The username is already being used" : "ユーザー名はすでに使われています", + "The username is already being used" : "このユーザー名はすでに使われています", "Could not create user" : "ユーザーを作成できませんでした", "User disabled" : "ユーザーは無効です", "Login canceled by app" : "アプリによりログインが中止されました", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "次の依存関係を満たしていないため、アプリ \"%1$s\" をインストールできません: %2$s", - "a safe home for all your data" : "あらゆるデータを安全に保管します", + "a safe home for all your data" : "すべてのデータを安全に保管します", "File is currently busy, please try again later" : "現在ファイルはビジーです。後でもう一度試してください。", "Cannot read file" : "ファイルを読み込めません", "Application is not enabled" : "アプリケーションは無効です", @@ -190,16 +212,17 @@ "No database drivers (sqlite, mysql, or postgresql) installed." : "データベースドライバー (sqlite, mysql, postgresql) がインストールされていません。", "Cannot write into \"config\" directory" : "\"config\" ディレクトリに書き込みができません", "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "多くの場合、Webサーバーの configディレクトリ に書き込み権限を与えることで直ります。%s を見てください", - "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "またはconfig.phpファイルを読み取り専用にしたい場合は、オプション \"config_is_read_only\"をtrueに設定してください。 %sを参照してください", + "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "またはconfig.phpファイルを読み取り専用にしたい場合は、オプション \"config_is_read_only\"をtrueに設定してください。 詳しくは%sを確認してください。", "Cannot write into \"apps\" directory" : "\"apps\" ディレクトリに書き込みができません", - "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "これは通常、Webサーバーにappsディレクトリへの書き込み権限を許可するか、構成ファイルでAppStoreを無効にすることで解決できます。", - "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "多くの場合、Webサーバーのルートディレクトリに書き込み権限を与えることで直ります。%s を見てください。", - "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Webサーバーのルートディレクトリに書き込み権限パーミッションが必要です。%s を見てください。", + "This can usually be fixed by giving the webserver write access to the apps directory or disabling the App Store in the config file." : "Webサーバーにappsディレクトリへの書き込み権限を許可するか、構成ファイルでAppStoreを無効にすることで解決する可能性があります。", + "Cannot create \"data\" directory." : "dataディレクトリを作成できません。", + "This can usually be fixed by giving the webserver write access to the root directory. See %s" : "多くの場合、Webサーバーのルートディレクトリに書き込み権限を与えることで直ります。詳しくは%sを確認してください。", + "Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Webサーバーのルートディレクトリに書き込み権限パーミッションが必要です。詳しくは%sを確認してください。", "Setting locale to %s failed" : "ロケールを %s に設定できませんでした", "Please install one of these locales on your system and restart your webserver." : "これらのロケールのうちいずれかをシステムにインストールし、Webサーバーを再起動してください。", - "PHP module %s not installed." : "PHP のモジュール %s がインストールされていません。", + "PHP module %s not installed." : "PHP のモジュールの %s がインストールされていません。", "Please ask your server administrator to install the module." : "サーバー管理者にモジュールのインストールを依頼してください。", - "PHP setting \"%s\" is not set to \"%s\"." : "PHP設定の\"%s\"は \"%s\"に設定されていません", + "PHP setting \"%s\" is not set to \"%s\"." : "PHP設定の\"%s\"が \"%s\"に設定されていません", "Adjusting this setting in php.ini will make Nextcloud run again" : "php.ini のこの設定を調整して、再度 Nextcloudを起動してください。", "mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload の値は \"0\" であるべきですが、\"%s\" に設定されています", "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "この問題を修正するには、php.ini ファイルの <code>mbstring.func_overload</code> を <code>0</code> に設定してください。", diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js index 81aa759f450..dc69f57c3c5 100644 --- a/lib/l10n/lt_LT.js +++ b/lib/l10n/lt_LT.js @@ -33,6 +33,7 @@ OC.L10N.register( "Unknown filetype" : "Nežinomas failo tipas", "Invalid image" : "Neteisingas paveikslas", "Avatar image is not square" : "Avataro paveikslas nėra kvadratinis", + "View profile" : "Rodyti profilį", "today" : "šiandien", "tomorrow" : "rytoj", "yesterday" : "vakar", diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json index 5974251dd62..27c7cee7d70 100644 --- a/lib/l10n/lt_LT.json +++ b/lib/l10n/lt_LT.json @@ -31,6 +31,7 @@ "Unknown filetype" : "Nežinomas failo tipas", "Invalid image" : "Neteisingas paveikslas", "Avatar image is not square" : "Avataro paveikslas nėra kvadratinis", + "View profile" : "Rodyti profilį", "today" : "šiandien", "tomorrow" : "rytoj", "yesterday" : "vakar", diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index d162bb54108..fffeffd4feb 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -260,6 +260,10 @@ class SecurityMiddleware extends Middleware { if (isset($this->request->server['REQUEST_URI'])) { $params['redirect_url'] = $this->request->server['REQUEST_URI']; } + $usernamePrefill = $this->request->getParam('user', ''); + if ($usernamePrefill !== '') { + $params['user'] = $usernamePrefill; + } $url = $this->urlGenerator->linkToRoute('core.login.showLoginForm', $params); $response = new RedirectResponse($url); } else { diff --git a/lib/private/AppScriptDependency.php b/lib/private/AppScriptDependency.php new file mode 100644 index 00000000000..35878e85b49 --- /dev/null +++ b/lib/private/AppScriptDependency.php @@ -0,0 +1,97 @@ +<?php +/** + * @copyright Copyright (c) 2021, Jonas Meurer <jonas@freesources.org> + * + * @author Jonas Meurer <jonas@freesources.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC; + +class AppScriptDependency { + /** @var string */ + private $id; + + /** @var array */ + private $deps; + + /** @var bool */ + private $visited; + + /** + * @param string $id + * @param array $deps + * @param bool $visited + */ + public function __construct(string $id, array $deps = [], bool $visited = false) { + $this->setId($id); + $this->setDeps($deps); + $this->setVisited($visited); + } + + /** + * @return string + */ + public function getId(): string { + return $this->id; + } + + /** + * @param string $id + */ + public function setId(string $id): void { + $this->id = $id; + } + + /** + * @return array + */ + public function getDeps(): array { + return $this->deps; + } + + /** + * @param array $deps + */ + public function setDeps(array $deps): void { + $this->deps = $deps; + } + + /** + * @param string $dep + */ + public function addDep(string $dep): void { + if (!in_array($dep, $this->deps, true)) { + $this->deps[] = $dep; + } + } + + /** + * @return bool + */ + public function isVisited(): bool { + return $this->visited; + } + + /** + * @param bool $visited + */ + public function setVisited(bool $visited): void { + $this->visited = $visited; + } +} diff --git a/lib/private/AppScriptSort.php b/lib/private/AppScriptSort.php new file mode 100644 index 00000000000..c42d02d485d --- /dev/null +++ b/lib/private/AppScriptSort.php @@ -0,0 +1,105 @@ +<?php +/** + * @copyright Copyright (c) 2021, Jonas Meurer <jonas@freesources.org> + * + * @author Jonas Meurer <jonas@freesources.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC; + +use Psr\Log\LoggerInterface; + +/** + * Sort scripts topologically by their dependencies + * Implementation based on https://github.com/marcj/topsort.php + */ +class AppScriptSort { + /** @var LoggerInterface */ + private $logger; + + public function __construct(LoggerInterface $logger) { + $this->logger = $logger; + } + + /** + * Recursive topological sorting + * + * @param AppScriptDependency $app + * @param array $parents + * @param array $scriptDeps + * @param array $sortedScriptDeps + */ + private function topSortVisit( + AppScriptDependency $app, + array &$parents, + array &$scriptDeps, + array &$sortedScriptDeps): void { + // Detect and log circular dependencies + if (isset($parents[$app->getId()])) { + $this->logger->error('Circular dependency in app scripts at app ' . $app->getId()); + } + + // If app has not been visited + if (!$app->isVisited()) { + $parents[$app->getId()] = true; + $app->setVisited(true); + + foreach ($app->getDeps() as $dep) { + if ($app->getId() === $dep) { + // Ignore dependency on itself + continue; + } + + if (isset($scriptDeps[$dep])) { + $newParents = $parents; + $this->topSortVisit($scriptDeps[$dep], $newParents, $scriptDeps, $sortedScriptDeps); + } + } + + $sortedScriptDeps[] = $app->getId(); + } + } + + /** + * @return array scripts sorted by dependencies + */ + public function sort(array $scripts, array $scriptDeps): array { + // Sort scriptDeps into sortedScriptDeps + $sortedScriptDeps = []; + foreach ($scriptDeps as $app) { + $parents = []; + $this->topSortVisit($app, $parents, $scriptDeps, $sortedScriptDeps); + } + + // Sort scripts into sortedScripts based on sortedScriptDeps order + $sortedScripts = []; + foreach ($sortedScriptDeps as $app) { + $sortedScripts[$app] = $scripts[$app] ?? []; + } + + // Add remaining scripts + foreach (array_keys($scripts) as $app) { + if (!isset($sortedScripts[$app])) { + $sortedScripts[$app] = $scripts[$app]; + } + } + + return $sortedScripts; + } +} diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php index 9d8d1d836b6..9442bd9eca9 100644 --- a/lib/private/BackgroundJob/JobList.php +++ b/lib/private/BackgroundJob/JobList.php @@ -65,28 +65,34 @@ class JobList implements IJobList { * @param mixed $argument */ public function add($job, $argument = null) { - if (!$this->has($job, $argument)) { - if ($job instanceof IJob) { - $class = get_class($job); - } else { - $class = $job; - } + if ($job instanceof IJob) { + $class = get_class($job); + } else { + $class = $job; + } - $argument = json_encode($argument); - if (strlen($argument) > 4000) { - throw new \InvalidArgumentException('Background job arguments can\'t exceed 4000 characters (json encoded)'); - } + $argumentJson = json_encode($argument); + if (strlen($argumentJson) > 4000) { + throw new \InvalidArgumentException('Background job arguments can\'t exceed 4000 characters (json encoded)'); + } - $query = $this->connection->getQueryBuilder(); + $query = $this->connection->getQueryBuilder(); + if (!$this->has($job, $argument)) { $query->insert('jobs') ->values([ 'class' => $query->createNamedParameter($class), - 'argument' => $query->createNamedParameter($argument), + 'argument' => $query->createNamedParameter($argumentJson), 'last_run' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT), 'last_checked' => $query->createNamedParameter($this->timeFactory->getTime(), IQueryBuilder::PARAM_INT), ]); - $query->execute(); + } else { + $query->update('jobs') + ->set('reserved_at', $query->expr()->literal(0, IQueryBuilder::PARAM_INT)) + ->set('last_checked', $query->createNamedParameter($this->timeFactory->getTime(), IQueryBuilder::PARAM_INT)) + ->where($query->expr()->eq('class', $query->createNamedParameter($class))) + ->andWhere($query->expr()->eq('argument', $query->createNamedParameter($argumentJson))); } + $query->executeStatement(); } /** diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index c0d0a55a1a1..9e35aa828da 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -239,10 +239,7 @@ class MailPlugin implements ISearchPlugin { } $reachedEnd = true; - if (!$this->shareeEnumeration) { - $result['wide'] = []; - $userResults['wide'] = []; - } else { + if ($this->shareeEnumeration) { $reachedEnd = (count($result['wide']) < $offset + $limit) && (count($userResults['wide']) < $offset + $limit); diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php index 21caf6823f8..d62db2926fb 100644 --- a/lib/private/Comments/Manager.php +++ b/lib/private/Comments/Manager.php @@ -677,6 +677,10 @@ class Manager implements ICommentsManager { * @since 21.0.0 */ public function getNumberOfCommentsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, string $verb = ''): int { + if ($verb !== '') { + return $this->getNumberOfCommentsWithVerbsForObjectSinceComment($objectType, $objectId, $lastRead, [$verb]); + } + $query = $this->dbConn->getQueryBuilder(); $query->select($query->func()->count('id', 'num_messages')) ->from('comments') @@ -684,11 +688,31 @@ class Manager implements ICommentsManager { ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId))) ->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastRead))); - if ($verb !== '') { - $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb))); - } + $result = $query->executeQuery(); + $data = $result->fetch(); + $result->closeCursor(); - $result = $query->execute(); + return (int) ($data['num_messages'] ?? 0); + } + + /** + * @param string $objectType + * @param string $objectId + * @param int $lastRead + * @param string[] $verbs + * @return int + * @since 24.0.0 + */ + public function getNumberOfCommentsWithVerbsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, array $verbs): int { + $query = $this->dbConn->getQueryBuilder(); + $query->select($query->func()->count('id', 'num_messages')) + ->from('comments') + ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType))) + ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId))) + ->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastRead))) + ->andWhere($query->expr()->in('verb', $query->createNamedParameter($verbs, IQueryBuilder::PARAM_STR_ARRAY))); + + $result = $query->executeQuery(); $data = $result->fetch(); $result->closeCursor(); diff --git a/lib/private/Config.php b/lib/private/Config.php index 2a83d2300dc..b044d0731a3 100644 --- a/lib/private/Config.php +++ b/lib/private/Config.php @@ -57,6 +57,8 @@ class Config { protected $configFilePath; /** @var string */ protected $configFileName; + /** @var bool */ + protected $isReadOnly; /** * @param string $configDir Path to the config dir, needs to end with '/' @@ -67,6 +69,7 @@ class Config { $this->configFilePath = $this->configDir.$fileName; $this->configFileName = $fileName; $this->readData(); + $this->isReadOnly = $this->getValue('config_is_read_only', false); } /** @@ -109,6 +112,7 @@ class Config { * * @param array $configs Associative array with `key => value` pairs * If value is null, the config key will be deleted + * @throws HintException */ public function setValues(array $configs) { $needsUpdate = false; @@ -131,6 +135,7 @@ class Config { * * @param string $key key * @param mixed $value value + * @throws HintException */ public function setValue($key, $value) { if ($this->set($key, $value)) { @@ -145,8 +150,11 @@ class Config { * @param string $key key * @param mixed $value value * @return bool True if the file needs to be updated, false otherwise + * @throws HintException */ protected function set($key, $value) { + $this->checkReadOnly(); + if (!isset($this->cache[$key]) || $this->cache[$key] !== $value) { // Add change $this->cache[$key] = $value; @@ -158,7 +166,9 @@ class Config { /** * Removes a key from the config and removes it from config.php if required + * * @param string $key + * @throws HintException */ public function deleteKey($key) { if ($this->delete($key)) { @@ -172,8 +182,11 @@ class Config { * * @param string $key * @return bool True if the file needs to be updated, false otherwise + * @throws HintException */ protected function delete($key) { + $this->checkReadOnly(); + if (isset($this->cache[$key])) { // Delete key from cache unset($this->cache[$key]); @@ -239,6 +252,8 @@ class Config { * @throws \Exception If no file lock can be acquired */ private function writeData() { + $this->checkReadOnly(); + // Create a php file ... $content = "<?php\n"; $content .= '$CONFIG = '; @@ -274,4 +289,15 @@ class Config { @opcache_invalidate($this->configFilePath, true); } } + + /** + * @throws HintException + */ + private function checkReadOnly(): void { + if ($this->isReadOnly) { + throw new HintException( + 'Config is set to be read-only via option "config_is_read_only".', + 'Unset "config_is_read_only" to allow changes to the config file.'); + } + } } diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php index 9efacb0f9ae..b8d1a747fa2 100644 --- a/lib/private/DB/Connection.php +++ b/lib/private/DB/Connection.php @@ -272,7 +272,7 @@ class Connection extends \Doctrine\DBAL\Connection { protected function logQueryToFile(string $sql): void { $logFile = $this->systemConfig->getValue('query_log_file', ''); - if ($logFile !== '' && is_writable($logFile)) { + if ($logFile !== '' && is_writable(dirname($logFile)) && (!file_exists($logFile) || is_writable($logFile))) { file_put_contents( $this->systemConfig->getValue('query_log_file', ''), $sql . "\n", diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php index dfc0d0a6d61..37518bda3ec 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php @@ -26,18 +26,23 @@ namespace OC\DB\QueryBuilder\FunctionBuilder; use OC\DB\QueryBuilder\QueryFunction; use OC\DB\QueryBuilder\QuoteHelper; use OCP\DB\QueryBuilder\IFunctionBuilder; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use OCP\IDBConnection; class FunctionBuilder implements IFunctionBuilder { + /** @var IDBConnection */ + protected $connection; + + /** @var IQueryBuilder */ + protected $queryBuilder; + /** @var QuoteHelper */ protected $helper; - /** - * ExpressionBuilder constructor. - * - * @param QuoteHelper $helper - */ - public function __construct(QuoteHelper $helper) { + public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder, QuoteHelper $helper) { + $this->connection = $connection; + $this->queryBuilder = $queryBuilder; $this->helper = $helper; } @@ -49,6 +54,11 @@ class FunctionBuilder implements IFunctionBuilder { return new QueryFunction('CONCAT(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')'); } + public function groupConcat($expr, ?string $separator = ','): IQueryFunction { + $separator = $this->connection->quote($separator); + return new QueryFunction('GROUP_CONCAT(' . $this->helper->quoteColumnName($expr) . ' SEPARATOR ' . $separator . ')'); + } + public function substring($input, $start, $length = null): IQueryFunction { if ($length) { return new QueryFunction('SUBSTR(' . $this->helper->quoteColumnName($input) . ', ' . $this->helper->quoteColumnName($start) . ', ' . $this->helper->quoteColumnName($length) . ')'); diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php index 5581207a166..3871070a583 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php @@ -72,4 +72,14 @@ class OCIFunctionBuilder extends FunctionBuilder { return parent::least($x, $y); } + + public function groupConcat($expr, ?string $separator = ','): IQueryFunction { + $orderByClause = ' WITHIN GROUP(ORDER BY NULL)'; + if (is_null($separator)) { + return new QueryFunction('LISTAGG(' . $this->helper->quoteColumnName($expr) . ')' . $orderByClause); + } + + $separator = $this->connection->quote($separator); + return new QueryFunction('LISTAGG(' . $this->helper->quoteColumnName($expr) . ', ' . $separator . ')' . $orderByClause); + } } diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php index 853c65ac32a..0b22775acc8 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php @@ -24,10 +24,22 @@ namespace OC\DB\QueryBuilder\FunctionBuilder; use OC\DB\QueryBuilder\QueryFunction; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; class PgSqlFunctionBuilder extends FunctionBuilder { public function concat($x, $y): IQueryFunction { return new QueryFunction('(' . $this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y) . ')'); } + + public function groupConcat($expr, ?string $separator = ','): IQueryFunction { + $castedExpression = $this->queryBuilder->expr()->castColumn($expr, IQueryBuilder::PARAM_STR); + + if (is_null($separator)) { + return new QueryFunction('string_agg(' . $castedExpression . ')'); + } + + $separator = $this->connection->quote($separator); + return new QueryFunction('string_agg(' . $castedExpression . ', ' . $separator . ')'); + } } diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php index 19cff52546b..1067f8f0925 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php @@ -31,6 +31,11 @@ class SqliteFunctionBuilder extends FunctionBuilder { return new QueryFunction('(' . $this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y) . ')'); } + public function groupConcat($expr, ?string $separator = ','): IQueryFunction { + $separator = $this->connection->quote($separator); + return new QueryFunction('GROUP_CONCAT(' . $this->helper->quoteColumnName($expr) . ', ' . $separator . ')'); + } + public function greatest($x, $y): IQueryFunction { return new QueryFunction('MAX(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')'); } diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php index 89265c74fae..a362ff8016e 100644 --- a/lib/private/DB/QueryBuilder/QueryBuilder.php +++ b/lib/private/DB/QueryBuilder/QueryBuilder.php @@ -155,16 +155,16 @@ class QueryBuilder implements IQueryBuilder { */ public function func() { if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) { - return new OCIFunctionBuilder($this->helper); + return new OCIFunctionBuilder($this->connection, $this, $this->helper); } if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { - return new SqliteFunctionBuilder($this->helper); + return new SqliteFunctionBuilder($this->connection, $this, $this->helper); } if ($this->connection->getDatabasePlatform() instanceof PostgreSQL94Platform) { - return new PgSqlFunctionBuilder($this->helper); + return new PgSqlFunctionBuilder($this->connection, $this, $this->helper); } - return new FunctionBuilder($this->helper); + return new FunctionBuilder($this->connection, $this, $this->helper); } /** diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php index 543f1e5adb7..e6efc6d28aa 100644 --- a/lib/private/DirectEditing/Manager.php +++ b/lib/private/DirectEditing/Manager.php @@ -82,7 +82,7 @@ class Manager implements IManager { $this->connection = $connection; $this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null; $this->rootFolder = $rootFolder; - $this->l10n = $l10nFactory->get('core'); + $this->l10n = $l10nFactory->get('lib'); $this->encryptionManager = $encryptionManager; } diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php index df72978a142..53f69be7127 100644 --- a/lib/private/Files/AppData/AppData.php +++ b/lib/private/Files/AppData/AppData.php @@ -79,7 +79,7 @@ class AppData implements IAppData { return 'appdata_' . $instanceId; } - private function getAppDataRootFolder(): Folder { + protected function getAppDataRootFolder(): Folder { $name = $this->getAppDataFolderName(); try { diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php index c99ebdbcd5c..b72b0ebee53 100644 --- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php +++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php @@ -32,7 +32,6 @@ namespace OC\Files\ObjectStore; use Aws\ClientResolver; use Aws\Credentials\CredentialProvider; -use Aws\Credentials\EcsCredentialProvider; use Aws\Credentials\Credentials; use Aws\Exception\CredentialsException; use Aws\S3\Exception\S3Exception; @@ -63,6 +62,9 @@ trait S3ConnectionTrait { /** @var int */ protected $uploadPartSize; + /** @var int */ + private $putSizeLimit; + protected $test; protected function parseParams($params) { @@ -77,6 +79,7 @@ trait S3ConnectionTrait { $this->proxy = $params['proxy'] ?? false; $this->timeout = $params['timeout'] ?? 15; $this->uploadPartSize = $params['uploadPartSize'] ?? 524288000; + $this->putSizeLimit = $params['putSizeLimit'] ?? 104857600; $params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region']; $params['hostname'] = empty($params['hostname']) ? 's3.' . $params['region'] . '.amazonaws.com' : $params['hostname']; if (!isset($params['port']) || $params['port'] === '') { @@ -109,15 +112,11 @@ trait S3ConnectionTrait { $base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/'; // Adding explicit credential provider to the beginning chain. - // Including environment variables and IAM instance profiles. + // Including default credential provider (skipping AWS shared config files). $provider = CredentialProvider::memoize( CredentialProvider::chain( $this->paramCredentialProvider(), - CredentialProvider::env(), - CredentialProvider::assumeRoleWithWebIdentityCredentialProvider(), - !empty(getenv(EcsCredentialProvider::ENV_URI)) - ? CredentialProvider::ecsCredentials() - : CredentialProvider::instanceProfile() + CredentialProvider::defaultProvider(['use_aws_shared_config_files' => false]) ) ); diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index 01da7a88dc8..769901acc79 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -144,9 +144,9 @@ trait S3ObjectTrait { // ($psrStream->isSeekable() && $psrStream->getSize() !== null) evaluates to true for a On-Seekable stream // so the optimisation does not apply $buffer = new Psr7\Stream(fopen("php://memory", 'rwb+')); - Utils::copyToStream($psrStream, $buffer, MultipartUploader::PART_MIN_SIZE); + Utils::copyToStream($psrStream, $buffer, $this->uploadPartSize); $buffer->seek(0); - if ($buffer->getSize() < MultipartUploader::PART_MIN_SIZE) { + if ($buffer->getSize() < $this->putSizeLimit) { // buffer is fully seekable, so use it directly for the small upload $this->writeSingle($urn, $buffer, $mimetype); } else { diff --git a/lib/private/Installer.php b/lib/private/Installer.php index f3af74167d1..b63619b821c 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -151,7 +151,7 @@ class Installer { //install the database $ms = new MigrationService($info['id'], \OC::$server->get(Connection::class)); - $ms->migrate('latest', true); + $ms->migrate('latest', !$previousVersion); if ($previousVersion) { OC_App::executeRepairSteps($appId, $info['repair-steps']['post-migration']); @@ -597,8 +597,11 @@ class Installer { $appPath = OC_App::getAppPath($app); \OC_App::registerAutoloading($app, $appPath); + $config = \OC::$server->getConfig(); + $ms = new MigrationService($app, \OC::$server->get(Connection::class)); - $ms->migrate('latest', true); + $previousVersion = $config->getAppValue($app, 'installed_version', false); + $ms->migrate('latest', !$previousVersion); //run appinfo/install.php self::includeAppScript("$appPath/appinfo/install.php"); @@ -611,8 +614,6 @@ class Installer { OC_App::executeRepairSteps($app, $info['repair-steps']['install']); - $config = \OC::$server->getConfig(); - $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); if (array_key_exists('ocsid', $info)) { $config->setAppValue($app, 'ocsid', $info['ocsid']); diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php index 74d8da187fe..63180dd8066 100644 --- a/lib/private/Memcache/Redis.php +++ b/lib/private/Memcache/Redis.php @@ -54,8 +54,12 @@ class Redis extends Cache implements IMemcacheTTL { return $this->prefix; } + private function logEnabled(): bool { + return $this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile)); + } + public function get($key) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::get::' . $key . "\n", @@ -72,7 +76,7 @@ class Redis extends Cache implements IMemcacheTTL { } public function set($key, $value, $ttl = 0) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::set::' . $key . '::' . $ttl . '::' . json_encode($value) . "\n", @@ -88,7 +92,7 @@ class Redis extends Cache implements IMemcacheTTL { } public function hasKey($key) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::hasKey::' . $key . "\n", @@ -100,7 +104,7 @@ class Redis extends Cache implements IMemcacheTTL { } public function remove($key) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::remove::' . $key . "\n", @@ -116,7 +120,7 @@ class Redis extends Cache implements IMemcacheTTL { } public function clear($prefix = '') { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::clear::' . $prefix . "\n", @@ -149,7 +153,7 @@ class Redis extends Cache implements IMemcacheTTL { if ($ttl !== 0 && is_int($ttl)) { $args['ex'] = $ttl; } - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::add::' . $key . '::' . $value . "\n", @@ -169,7 +173,7 @@ class Redis extends Cache implements IMemcacheTTL { * @return int | bool */ public function inc($key, $step = 1) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::inc::' . $key . "\n", @@ -188,7 +192,7 @@ class Redis extends Cache implements IMemcacheTTL { * @return int | bool */ public function dec($key, $step = 1) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::dec::' . $key . "\n", @@ -211,7 +215,7 @@ class Redis extends Cache implements IMemcacheTTL { * @return bool */ public function cas($key, $old, $new) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::cas::' . $key . "\n", @@ -241,7 +245,7 @@ class Redis extends Cache implements IMemcacheTTL { * @return bool */ public function cad($key, $old) { - if ($this->logFile !== '' && is_writable($this->logFile)) { + if ($this->logEnabled()) { file_put_contents( $this->logFile, $this->getNameSpace() . '::cad::' . $key . "\n", diff --git a/lib/private/Preview/BackgroundCleanupJob.php b/lib/private/Preview/BackgroundCleanupJob.php index c78ef7d7257..ab40aeaaa79 100644 --- a/lib/private/Preview/BackgroundCleanupJob.php +++ b/lib/private/Preview/BackgroundCleanupJob.php @@ -134,6 +134,7 @@ class BackgroundCleanupJob extends TimedJob { )) ->where( $qb->expr()->andX( + $qb->expr()->eq('a.storage', $qb->createNamedParameter($this->previewFolder->getStorageId())), $qb->expr()->isNull('b.fileid'), $qb->expr()->like('a.path', $qb->createNamedParameter($like)), $qb->expr()->eq('a.mimetype', $qb->createNamedParameter($this->mimeTypeLoader->getId('httpd/unix-directory'))) diff --git a/lib/private/Preview/Storage/Root.php b/lib/private/Preview/Storage/Root.php index 0eac3ce2064..c4191228ec7 100644 --- a/lib/private/Preview/Storage/Root.php +++ b/lib/private/Preview/Storage/Root.php @@ -85,4 +85,8 @@ class Root extends AppData { public static function getInternalFolder(string $name): string { return implode('/', str_split(substr(md5($name), 0, 7))) . '/' . $name; } + + public function getStorageId(): int { + return $this->getAppDataRootFolder()->getStorage()->getCache()->getNumericStorageId(); + } } diff --git a/lib/private/Updater/ChangesCheck.php b/lib/private/Updater/ChangesCheck.php index 600c8db9a3c..e3ced6e5b12 100644 --- a/lib/private/Updater/ChangesCheck.php +++ b/lib/private/Updater/ChangesCheck.php @@ -138,9 +138,13 @@ class ChangesCheck { protected function extractData($body):array { $data = []; if ($body) { - $loadEntities = libxml_disable_entity_loader(true); - $xml = @simplexml_load_string($body); - libxml_disable_entity_loader($loadEntities); + if (\LIBXML_VERSION < 20900) { + $loadEntities = libxml_disable_entity_loader(true); + $xml = @simplexml_load_string($body); + libxml_disable_entity_loader($loadEntities); + } else { + $xml = @simplexml_load_string($body); + } if ($xml !== false) { $data['changelogURL'] = (string)$xml->changelog['href']; $data['whatsNew'] = []; diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php index ffa707d8990..d9f795796b8 100644 --- a/lib/private/Updater/VersionCheck.php +++ b/lib/private/Updater/VersionCheck.php @@ -95,9 +95,13 @@ class VersionCheck { } if ($xml) { - $loadEntities = libxml_disable_entity_loader(true); - $data = @simplexml_load_string($xml); - libxml_disable_entity_loader($loadEntities); + if (\LIBXML_VERSION < 20900) { + $loadEntities = libxml_disable_entity_loader(true); + $data = @simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); + } else { + $data = @simplexml_load_string($xml); + } if ($data !== false) { $tmp['version'] = (string)$data->version; $tmp['versionstring'] = (string)$data->versionstring; diff --git a/lib/public/Comments/ICommentsManager.php b/lib/public/Comments/ICommentsManager.php index 64bb98db478..9aacf028b4e 100644 --- a/lib/public/Comments/ICommentsManager.php +++ b/lib/public/Comments/ICommentsManager.php @@ -201,6 +201,17 @@ interface ICommentsManager { */ public function getNumberOfCommentsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, string $verb = ''): int; + + /** + * @param string $objectType + * @param string $objectId + * @param int $lastRead + * @param string[] $verbs + * @return int + * @since 24.0.0 + */ + public function getNumberOfCommentsWithVerbsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, array $verbs): int; + /** * @param string $objectType * @param string $objectId diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php index 33d0fbe3b1a..1e8d8c89f81 100644 --- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php +++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php @@ -44,7 +44,7 @@ interface IFunctionBuilder { * Combines two input strings * * @param string|ILiteral|IParameter|IQueryFunction $x The first input string - * @param string|ILiteral|IParameter|IQueryFunction $y The seccond input string + * @param string|ILiteral|IParameter|IQueryFunction $y The second input string * * @return IQueryFunction * @since 12.0.0 @@ -52,6 +52,22 @@ interface IFunctionBuilder { public function concat($x, $y): IQueryFunction; /** + * Returns a string which is the concatenation of all non-NULL values of X + * + * Usage examples: + * + * groupConcat('column') -- with comma as separator (default separator) + * + * groupConcat('column', ';') -- with different separator + * + * @param string|IQueryFunction $expr The expression to group + * @param string|null $separator The separator + * @return IQueryFunction + * @since 24.0.0 + */ + public function groupConcat($expr, ?string $separator = ','): IQueryFunction; + + /** * Takes a substring from the input string * * @param string|ILiteral|IParameter|IQueryFunction $input The input string diff --git a/lib/public/IConfig.php b/lib/public/IConfig.php index 6b396624556..33b9c97971a 100644 --- a/lib/public/IConfig.php +++ b/lib/public/IConfig.php @@ -47,6 +47,7 @@ interface IConfig { * * @param array $configs Associative array with `key => value` pairs * If value is null, the config key will be deleted + * @throws HintException if config file is read-only * @since 8.0.0 */ public function setSystemValues(array $configs); @@ -56,6 +57,7 @@ interface IConfig { * * @param string $key the key of the value, under which will be saved * @param mixed $value the value that should be stored + * @throws HintException if config file is read-only * @since 8.0.0 */ public function setSystemValue($key, $value); diff --git a/lib/public/LDAP/ILDAPProvider.php b/lib/public/LDAP/ILDAPProvider.php index 0355a0052c4..8fad3bd2266 100644 --- a/lib/public/LDAP/ILDAPProvider.php +++ b/lib/public/LDAP/ILDAPProvider.php @@ -79,7 +79,7 @@ interface ILDAPProvider { /** * Return a new LDAP connection resource for the specified user. * @param string $uid user id - * @return resource of the LDAP connection + * @return \LDAP\Connection|resource * @since 11.0.0 */ public function getLDAPConnection($uid); @@ -87,7 +87,7 @@ interface ILDAPProvider { /** * Return a new LDAP connection resource for the specified group. * @param string $gid group id - * @return resource of the LDAP connection + * @return \LDAP\Connection|resource * @since 13.0.0 */ public function getGroupLDAPConnection($gid); diff --git a/lib/public/Util.php b/lib/public/Util.php index d0b23ddd3e0..f8d8b1aaf71 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -12,6 +12,7 @@ * @author J0WI <J0WI@users.noreply.github.com> * @author Jens-Christian Fischer <jens-christian.fischer@switch.ch> * @author Joas Schilling <coding@schilljs.com> + * @author Jonas Meurer <jonas@freesources.org> * @author Julius Härtl <jus@bitgrid.net> * @author Lukas Reschke <lukas@statuscode.ch> * @author Michael Gapczynski <GapczynskiM@gmail.com> @@ -45,6 +46,9 @@ namespace OCP; +use OC\AppScriptDependency; +use OC\AppScriptSort; + /** * This class provides different helper functions to make the life of a developer easier * @@ -78,6 +82,12 @@ class Util { /** @var array */ private static $scripts = []; + /** @var array */ + private static $scriptDeps = []; + + /** @var array */ + private static $sortedScriptDeps = []; + /** * get the current installed version of Nextcloud * @return array @@ -174,12 +184,13 @@ class Util { /** * add a javascript file + * * @param string $application - * @param string $file + * @param string|null $file * @param string $afterAppId * @since 4.0.0 */ - public static function addScript($application, $file = null, $afterAppId = null) { + public static function addScript(string $application, string $file = null, string $afterAppId = 'core'): void { if (!empty($application)) { $path = "$application/js/$file"; } else { @@ -195,56 +206,29 @@ class Util { self::addTranslations($application); } - // manage priorities if defined - // we store the data like this, then flatten everything - // [ - // 'core' => [ - // 'first' => [ - // '/core/js/main.js', - // ], - // 'last' => [ - // '/apps/viewer/js/viewer-main.js', - // ] - // ], - // 'viewer' => [ - // 'first' => [ - // '/apps/viewer/js/viewer-public.js', - // ], - // 'last' => [ - // '/apps/files_pdfviewer/js/files_pdfviewer-main.js', - // ] - // ] - // ] - if (!empty($afterAppId)) { - // init afterAppId app array if it doesn't exists - if (!array_key_exists($afterAppId, self::$scripts)) { - self::$scripts[$afterAppId] = ['first' => [], 'last' => []]; - } - self::$scripts[$afterAppId]['last'][] = $path; + // store app in dependency list + if (!array_key_exists($application, self::$scriptDeps)) { + self::$scriptDeps[$application] = new AppScriptDependency($application, [$afterAppId]); } else { - // init app array if it doesn't exists - if (!array_key_exists($application, self::$scripts)) { - self::$scripts[$application] = ['first' => [], 'last' => []]; - } - self::$scripts[$application]['first'][] = $path; + self::$scriptDeps[$application]->addDep($afterAppId); } + + self::$scripts[$application][] = $path; } /** * Return the list of scripts injected to the page + * * @return array * @since 24.0.0 */ public static function getScripts(): array { - // merging first and last data set - $mapFunc = function (array $scriptsArray): array { - return array_merge(...array_values($scriptsArray)); - }; - $appScripts = array_map($mapFunc, self::$scripts); - // sort core first - $scripts = array_merge(isset($appScripts['core']) ? $appScripts['core'] : [], ...array_values($appScripts)); - // remove duplicates - return array_unique($scripts); + // Sort scriptDeps into sortedScriptDeps + $scriptSort = \OC::$server->get(AppScriptSort::class); + $sortedScripts = $scriptSort->sort(self::$scripts, self::$scriptDeps); + + // Flatten array and remove duplicates + return $sortedScripts ? array_unique(array_merge(...array_values(($sortedScripts)))) : []; } /** @@ -262,7 +246,7 @@ class Util { } else { $path = "l10n/$languageCode"; } - self::$scripts[$application]['first'][] = $path; + self::$scripts[$application][] = $path; } /** diff --git a/lib/versioncheck.php b/lib/versioncheck.php index 4b1d9dec4d7..3e840ff5b46 100644 --- a/lib/versioncheck.php +++ b/lib/versioncheck.php @@ -33,10 +33,10 @@ if (PHP_VERSION_ID < 70300) { exit(1); } -// Show warning if > PHP 8.0 is used as Nextcloud is not compatible with > PHP 8.0 for now -if (PHP_VERSION_ID >= 80100) { +// Show warning if >= PHP 8.2 is used as Nextcloud is not compatible with >= PHP 8.2 for now +if (PHP_VERSION_ID >= 80200) { http_response_code(500); - echo 'This version of Nextcloud is not compatible with > PHP 8.0.<br/>'; + echo 'This version of Nextcloud is not compatible with PHP>=8.2.<br/>'; echo 'You are currently running ' . PHP_VERSION . '.'; exit(1); } |