diff --git a/.env.example b/.env.example index c979b4e52..3db40f368 100644 --- a/.env.example +++ b/.env.example @@ -23,7 +23,7 @@ REDIS_PASSWORD=null REDIS_PORT=6379 CACHE_STORE=file -QUEUE_CONNECTION=redis +QUEUE_CONNECTION=sync SESSION_DRIVER=file HASHIDS_SALT= @@ -36,7 +36,7 @@ MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=no-reply@example.com -MAIL_FROM_NAME="Panel Administrator" +MAIL_FROM_NAME="Pelican Admin" # Set this to your domain to prevent it defaulting to 'localhost', causing mail servers such as Gmail to reject your mail # MAIL_EHLO_DOMAIN=panel.example.com SESSION_ENCRYPT=false diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4aed1d674..be1b59369 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,9 +1,6 @@ name: Build on: - push: - branches: - - '**' pull_request: branches: - '**' diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 95458fcd2..81f80c4e9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,7 @@ name: Tests on: - push: + pull_request: branches: - '**' diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml new file mode 100644 index 000000000..4efdecca4 --- /dev/null +++ b/.github/workflows/cla.yaml @@ -0,0 +1,30 @@ +name: "CLA Assistant" +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened,closed,synchronize] + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +jobs: + CLAAssistant: + runs-on: ubuntu-latest + steps: + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@v2.3.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + with: + path-to-signatures: 'version1/cla.json' + path-to-document: 'https://github.com/pelican-dev/panel/blob/3.x/contributor_license_agreement.md' + branch: 'main' + allowlist: dependabot[bot] + remote-organization-name: pelican-dev + remote-repository-name: cla-signatures diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index ab4515283..3dd538aad 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,9 +1,6 @@ name: Lint on: - push: - branches: - - '**' pull_request: branches: - '**' diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php index 343130168..c1f857f4e 100644 --- a/app/Console/Commands/Environment/AppSettingsCommand.php +++ b/app/Console/Commands/Environment/AppSettingsCommand.php @@ -11,23 +11,23 @@ class AppSettingsCommand extends Command use EnvironmentWriterTrait; public const CACHE_DRIVERS = [ - 'redis' => 'Redis (recommended)', + 'redis' => 'Redis', 'memcached' => 'Memcached', - 'file' => 'Filesystem', + 'file' => 'Filesystem (recommended)', ]; public const SESSION_DRIVERS = [ - 'redis' => 'Redis (recommended)', + 'redis' => 'Redis', 'memcached' => 'Memcached', 'database' => 'MySQL Database', - 'file' => 'Filesystem', + 'file' => 'Filesystem (recommended)', 'cookie' => 'Cookie', ]; public const QUEUE_DRIVERS = [ - 'redis' => 'Redis (recommended)', + 'redis' => 'Redis', 'database' => 'MySQL Database', - 'sync' => 'Sync', + 'sync' => 'Sync (recommended)', ]; protected $description = 'Configure basic environment settings for the Panel.'; @@ -91,21 +91,21 @@ class AppSettingsCommand extends Command config('app.timezone') ); - $selected = config('cache.default', 'redis'); + $selected = config('cache.default', 'file'); $this->variables['CACHE_STORE'] = $this->option('cache') ?? $this->choice( 'Cache Driver', self::CACHE_DRIVERS, array_key_exists($selected, self::CACHE_DRIVERS) ? $selected : null ); - $selected = config('session.driver', 'redis'); + $selected = config('session.driver', 'file'); $this->variables['SESSION_DRIVER'] = $this->option('session') ?? $this->choice( 'Session Driver', self::SESSION_DRIVERS, array_key_exists($selected, self::SESSION_DRIVERS) ? $selected : null ); - $selected = config('queue.default', 'redis'); + $selected = config('queue.default', 'sync'); $this->variables['QUEUE_CONNECTION'] = $this->option('queue') ?? $this->choice( 'Queue Driver', self::QUEUE_DRIVERS, diff --git a/app/Console/Commands/UpgradeCommand.php b/app/Console/Commands/UpgradeCommand.php index 45c127767..e04d1a50c 100644 --- a/app/Console/Commands/UpgradeCommand.php +++ b/app/Console/Commands/UpgradeCommand.php @@ -51,7 +51,7 @@ class UpgradeCommand extends Command } if (is_null($this->option('user'))) { - $userDetails = posix_getpwuid(fileowner('public')); + $userDetails = function_exists('posix_getpwuid') ? posix_getpwuid(fileowner('public')) : []; $user = $userDetails['name'] ?? 'www-data'; if (!$this->confirm("Your webserver user has been detected as [{$user}]: is this correct?", true)) { @@ -67,7 +67,7 @@ class UpgradeCommand extends Command } if (is_null($this->option('group'))) { - $groupDetails = posix_getgrgid(filegroup('public')); + $groupDetails = function_exists('posix_getgrgid') ? posix_getgrgid(filegroup('public')) : []; $group = $groupDetails['name'] ?? 'www-data'; if (!$this->confirm("Your webserver group has been detected as [{$group}]: is this correct?", true)) { diff --git a/app/Http/Middleware/VerifyReCaptcha.php b/app/Http/Middleware/VerifyReCaptcha.php index 762a9646d..bfe09ce98 100644 --- a/app/Http/Middleware/VerifyReCaptcha.php +++ b/app/Http/Middleware/VerifyReCaptcha.php @@ -19,6 +19,10 @@ class VerifyReCaptcha return $next($request); } + if (app()->isLocal()) { + return $next($request); + } + if ($request->filled('g-recaptcha-response')) { $client = new Client(); $res = $client->post(config('recaptcha.domain'), [ diff --git a/app/Models/Egg.php b/app/Models/Egg.php index 559482839..95ad31cb5 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -139,6 +139,7 @@ class Egg extends Model 'features' => 'array', 'docker_images' => 'array', 'file_denylist' => 'array', + 'tags' => 'array', ]; } diff --git a/composer.json b/composer.json index 8034d6e70..6ba5fb658 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,6 @@ "ext-mbstring": "*", "ext-pdo": "*", "ext-pdo_mysql": "*", - "ext-posix": "*", "ext-zip": "*", "abdelhamiderrahmouni/filament-monaco-editor": "^0.2.0", "aws/aws-sdk-php": "~3.288.1", diff --git a/composer.lock b/composer.lock index 46683ce35..2c13d13dc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "278443a024fc60ce0a5d2ab2680e13a4", + "content-hash": "d56ab7da7dfcd2fe28a500ccac69fca5", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -1560,16 +1560,16 @@ }, { "name": "filament/actions", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", - "reference": "46decf6a9fc438c60c9fb1c5631820fab49fefb6" + "reference": "02ddfa646d1f11579dd92f9055bf6c58b70e6e01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/actions/zipball/46decf6a9fc438c60c9fb1c5631820fab49fefb6", - "reference": "46decf6a9fc438c60c9fb1c5631820fab49fefb6", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/02ddfa646d1f11579dd92f9055bf6c58b70e6e01", + "reference": "02ddfa646d1f11579dd92f9055bf6c58b70e6e01", "shasum": "" }, "require": { @@ -1609,20 +1609,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T15:42:36+00:00" + "time": "2024-04-18T11:26:11+00:00" }, { "name": "filament/filament", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "f9011967b6ea0cd79cf7b210bbb59de6bbe2ce1f" + "reference": "4b8ddda726dffd962ca6b142559d3ae2b2b74cdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/f9011967b6ea0cd79cf7b210bbb59de6bbe2ce1f", - "reference": "f9011967b6ea0cd79cf7b210bbb59de6bbe2ce1f", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/4b8ddda726dffd962ca6b142559d3ae2b2b74cdb", + "reference": "4b8ddda726dffd962ca6b142559d3ae2b2b74cdb", "shasum": "" }, "require": { @@ -1674,20 +1674,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T15:42:54+00:00" + "time": "2024-04-18T11:26:17+00:00" }, { "name": "filament/forms", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "85670891877fd57e322a8a4c8580ebef1d368f87" + "reference": "b49dde3268095dced856188c71c18df593ee6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/85670891877fd57e322a8a4c8580ebef1d368f87", - "reference": "85670891877fd57e322a8a4c8580ebef1d368f87", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/b49dde3268095dced856188c71c18df593ee6b96", + "reference": "b49dde3268095dced856188c71c18df593ee6b96", "shasum": "" }, "require": { @@ -1730,20 +1730,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T17:20:05+00:00" + "time": "2024-04-18T11:26:15+00:00" }, { "name": "filament/infolists", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", - "reference": "123bbd4e81cd3e8bcdfad77b9554bf8e4185689f" + "reference": "d205fbeacc7faf4430abb05c49334a64fb4d84ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/infolists/zipball/123bbd4e81cd3e8bcdfad77b9554bf8e4185689f", - "reference": "123bbd4e81cd3e8bcdfad77b9554bf8e4185689f", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/d205fbeacc7faf4430abb05c49334a64fb4d84ae", + "reference": "d205fbeacc7faf4430abb05c49334a64fb4d84ae", "shasum": "" }, "require": { @@ -1781,20 +1781,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T15:42:38+00:00" + "time": "2024-04-18T11:26:13+00:00" }, { "name": "filament/notifications", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", - "reference": "5731f4b9eb2b3f292b45fbb9ce173ee7d6b7dddb" + "reference": "dcc47b498c2a5a89296c2f46da651a8aa5e0bf55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/notifications/zipball/5731f4b9eb2b3f292b45fbb9ce173ee7d6b7dddb", - "reference": "5731f4b9eb2b3f292b45fbb9ce173ee7d6b7dddb", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/dcc47b498c2a5a89296c2f46da651a8aa5e0bf55", + "reference": "dcc47b498c2a5a89296c2f46da651a8aa5e0bf55", "shasum": "" }, "require": { @@ -1833,20 +1833,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T15:42:43+00:00" + "time": "2024-04-18T11:26:15+00:00" }, { "name": "filament/support", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "fc9038785de9d49802c36c1aef341af8dfa4dbe0" + "reference": "e6bd0dee0dda9f70b6f278747a5780c676edf21b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/fc9038785de9d49802c36c1aef341af8dfa4dbe0", - "reference": "fc9038785de9d49802c36c1aef341af8dfa4dbe0", + "url": "https://api.github.com/repos/filamentphp/support/zipball/e6bd0dee0dda9f70b6f278747a5780c676edf21b", + "reference": "e6bd0dee0dda9f70b6f278747a5780c676edf21b", "shasum": "" }, "require": { @@ -1891,20 +1891,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T17:58:12+00:00" + "time": "2024-04-18T11:26:31+00:00" }, { "name": "filament/tables", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "87f802bb8bfea1e77ed17ecd86a9d2074786f88a" + "reference": "e45917f8be86338c385b86d3e5a42ac12f9699a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/87f802bb8bfea1e77ed17ecd86a9d2074786f88a", - "reference": "87f802bb8bfea1e77ed17ecd86a9d2074786f88a", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/e45917f8be86338c385b86d3e5a42ac12f9699a5", + "reference": "e45917f8be86338c385b86d3e5a42ac12f9699a5", "shasum": "" }, "require": { @@ -1944,11 +1944,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2024-04-16T15:43:11+00:00" + "time": "2024-04-18T11:26:35+00:00" }, { "name": "filament/widgets", - "version": "v3.2.69", + "version": "v3.2.70", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", @@ -12975,7 +12975,6 @@ "ext-mbstring": "*", "ext-pdo": "*", "ext-pdo_mysql": "*", - "ext-posix": "*", "ext-zip": "*" }, "platform-dev": [], diff --git a/config/panel.php b/config/panel.php index b605675bb..a51028047 100644 --- a/config/panel.php +++ b/config/panel.php @@ -92,7 +92,7 @@ return [ 'cdn' => [ 'cache_time' => 60, - 'url' => 'https://cdn.example.com/releases/latest.json', + 'url' => 'https://cdn.pelican.dev/releases/latest.json', ], /* diff --git a/contributor_license_agreement.md b/contributor_license_agreement.md new file mode 100644 index 000000000..8594ea679 --- /dev/null +++ b/contributor_license_agreement.md @@ -0,0 +1,96 @@ +Thank you for your interest in Pelican ("Pelican Developers"). To clarify the intellectual property license +granted with Contributions from any person or entity, the Pelican Developers +must have on file a signed Contributor License Agreement ("CLA") +from each Contributor, indicating agreement with the license +terms below. This agreement is for your protection as a Contributor +as well as the protection of the Pelican Developers and its users. It does not +change your rights to use your own Contributions for any other purpose. + +You accept and agree to the following terms and conditions for Your +Contributions (present and future) that you submit to the Pelican Developers. In +return, the Pelican Developers shall not use Your Contributions in a way that +is contrary to the public benefit or inconsistent with its nonprofit +status and bylaws in effect at the time of the Contribution. Except +for the license granted herein to the Pelican Developers and recipients of +software distributed by the Pelican Developers, You reserve all right, title, +and interest in and to Your Contributions. +1. Definitions. + "You" (or "Your") shall mean the copyright owner or legal entity + authorized by the copyright owner that is making this Agreement + with the Pelican Developers. For legal entities, the entity making a + Contribution and all other entities that control, are controlled + by, or are under common control with that entity are considered to + be a single Contributor. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + "Contribution" shall mean any original work of authorship, + including any modifications or additions to an existing work, that + is intentionally submitted by You to the Pelican Developers for inclusion + in, or documentation of, any of the products owned or managed by + the Pelican Developers (the "Work"). For the purposes of this definition, + "submitted" means any form of electronic, verbal, or written + communication sent to the Pelican Developers or its representatives, + including but not limited to communication on electronic mailing + lists, source code control systems, and issue tracking systems that + are managed by, or on behalf of, the Pelican Developers for the purpose of + discussing and improving the Work, but excluding communication that + is conspicuously marked or otherwise designated in writing by You + as "Not a Contribution." +2. Grant of Copyright License. Subject to the terms and conditions of + this Agreement, You hereby grant to the Pelican Developers and to + recipients of software distributed by the Pelican Developers a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare derivative works of, + publicly display, publicly perform, sublicense, and distribute Your + Contributions and such derivative works. +3. Grant of Patent License. Subject to the terms and conditions of + this Agreement, You hereby grant to the Pelican Developers and to + recipients of software distributed by the Pelican Developers a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have + made, use, offer to sell, sell, import, and otherwise transfer the + Work, where such license applies only to those patent claims + licensable by You that are necessarily infringed by Your + Contribution(s) alone or by combination of Your Contribution(s) + with the Work to which such Contribution(s) was submitted. If any + entity institutes patent litigation against You or any other entity + (including a cross-claim or counterclaim in a lawsuit) alleging + that your Contribution, or the Work to which you have contributed, + constitutes direct or contributory patent infringement, then any + patent licenses granted to that entity under this Agreement for + that Contribution or Work shall terminate as of the date such + litigation is filed. +4. You represent that you are legally entitled to grant the above + license. If your employer(s) has rights to intellectual property + that you create that includes your Contributions, you represent + that you have received permission to make Contributions on behalf + of that employer, that your employer has waived such rights for + your Contributions to the Pelican Developers, or that your employer has + executed a separate Corporate CLA with the Pelican Developers. +5. You represent that each of Your Contributions is Your original + creation (see section 7 for submissions on behalf of others). You + represent that Your Contribution submissions include complete + details of any third-party license or other restriction (including, + but not limited to, related patents and trademarks) of which you + are personally aware and which are associated with any part of Your + Contributions. +6. You are not expected to provide support for Your Contributions, + except to the extent You desire to provide support. You may provide + support for free, for a fee, or not at all. Unless required by + applicable law or agreed to in writing, You provide Your + Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + OF ANY KIND, either express or implied, including, without + limitation, any warranties or conditions of TITLE, NON- + INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. +7. Should You wish to submit work that is not Your original creation, + You may submit it to the Pelican Developers separately from any + Contribution, identifying the complete details of its source and of + any license or other restriction (including, but not limited to, + related patents, trademarks, and license agreements) of which you + are personally aware, and conspicuously marking the work as + "Submitted on behalf of a third-party: [named here]". +8. You agree to notify the Pelican Developers of any facts or circumstances of + which you become aware that would make these representations + inaccurate in any respect. diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..6f49cab9d --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,11 @@ +files: + - source: /lang/en/*.php + translation: /lang/%two_letters_code%/%original_file_name% + - source: /lang/en/admin + translation: /lang/%two_letters_code%/admin/%original_file_name% + - source: /lang/en/command + translation: /lang/%two_letters_code%/command/%original_file_name% + - source: /lang/en/dashboard + translation: /lang/%two_letters_code%/dashboard/%original_file_name% + - source: /lang/en/server + translation: /lang/%two_letters_code%/server/%original_file_name% diff --git a/database/migrations/2024_03_12_154408_remove_nests_table.php b/database/migrations/2024_03_12_154408_remove_nests_table.php index b363de80d..2d665d3e3 100644 --- a/database/migrations/2024_03_12_154408_remove_nests_table.php +++ b/database/migrations/2024_03_12_154408_remove_nests_table.php @@ -3,12 +3,30 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { + Schema::table('eggs', function (Blueprint $table) { + $table->text('tags'); + }); + + DB::table('eggs')->update(['tags' => '[]']); + + $eggsWithNests = DB::table('eggs') + ->select(['eggs.id', 'nests.name']) + ->join('nests', 'nests.id', '=', 'eggs.nest_id') + ->get(); + + foreach ($eggsWithNests as $egg) { + DB::table('eggs') + ->where('id', $egg->id) + ->update(['tags' => "[\"$egg->name\"]"]); + } + Schema::table('eggs', function (Blueprint $table) { $table->dropForeign('service_options_nest_id_foreign'); $table->dropColumn('nest_id'); @@ -26,6 +44,7 @@ return new class extends Migration }); } + // Not really reversible, but... public function down(): void { Schema::table('api_keys', function (Blueprint $table) { @@ -42,6 +61,7 @@ return new class extends Migration }); Schema::table('eggs', function (Blueprint $table) { + $table->dropColumn('tags'); $table->mediumInteger('nest_id')->unsigned(); $table->foreign(['nest_id'], 'service_options_nest_id_foreign'); }); diff --git a/database/migrations/2024_03_14_055537_remove_locations_table.php b/database/migrations/2024_03_14_055537_remove_locations_table.php index a6e74e8bb..7c72d7617 100644 --- a/database/migrations/2024_03_14_055537_remove_locations_table.php +++ b/database/migrations/2024_03_14_055537_remove_locations_table.php @@ -2,17 +2,33 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class extends Migration { - /** - * Run the migrations. - */ public function up(): void { + Schema::table('nodes', function (Blueprint $table) { + $table->text('tags'); + }); + + DB::table('nodes')->update(['tags' => '[]']); + + $nodesWithLocations = DB::table('nodes') + ->select(['nodes.id', 'locations.short']) + ->join('locations', 'locations.id', '=', 'nodes.location_id') + ->get(); + + foreach ($nodesWithLocations as $node) { + DB::table('nodes') + ->where('id', $node->id) + ->update(['tags' => "[\"$node->short\"]"]); + } + Schema::table('nodes', function (Blueprint $table) { $table->dropForeign('nodes_location_id_foreign'); + $table->dropColumn('location_id'); }); Schema::drop('locations'); @@ -22,9 +38,7 @@ return new class extends Migration }); } - /** - * Reverse the migrations. - */ + // Not really reversible, but... public function down(): void { Schema::create('locations', function (Blueprint $table) { @@ -34,6 +48,11 @@ return new class extends Migration $table->timestamps(); }); + Schema::table('nodes', function (Blueprint $table) { + $table->unsignedInteger('location_id')->default(0); + $table->foreign('location_id')->references('id')->on('locations'); + }); + Schema::table('api_keys', function (Blueprint $table) { $table->unsignedTinyInteger('r_locations')->default(0); }); diff --git a/lang/es/activity.php b/lang/es/activity.php new file mode 100644 index 000000000..68f9fa468 --- /dev/null +++ b/lang/es/activity.php @@ -0,0 +1,130 @@ + [ + 'fail' => 'Inicio de sesión fallido', + 'success' => 'Sesión iniciada', + 'password-reset' => 'Restablecimiento de contraseña', + 'reset-password' => 'Solicitud de restablecimiento de contraseña', + 'checkpoint' => 'Solicitud de autenticación de dos factores', + 'recovery-token' => 'Token de recuperación de dos factores utilizado', + 'token' => 'Resuelto desafío de dos factores', + 'ip-blocked' => 'Solicitud bloqueada desde la dirección IP no listada para :identifier', + 'sftp' => [ + 'fail' => 'Inicio de sesión SFTP fallido', + ], + ], + 'user' => [ + 'account' => [ + 'email-changed' => 'Cambio de correo electrónico de :old a :new', + 'password-changed' => 'Contraseña cambiada', + ], + 'api-key' => [ + 'create' => 'Se creó una nueva clave API :identifier', + 'delete' => 'Se eliminó la clave API :identifier', + ], + 'ssh-key' => [ + 'create' => 'Se agregó la clave SSH :fingerprint a la cuenta', + 'delete' => 'Se eliminó la clave SSH :fingerprint de la cuenta', + ], + 'two-factor' => [ + 'create' => 'Se habilitó la autenticación de dos factores', + 'delete' => 'Se deshabilitó la autenticación de dos factores', + ], + ], + 'server' => [ + 'reinstall' => 'Servidor reinstalado', + 'console' => [ + 'command' => 'Ejecutado ":command" en el servidor', + ], + 'power' => [ + 'start' => 'Iniciado el servidor', + 'stop' => 'Detenido el servidor', + 'restart' => 'Reiniciado el servidor', + 'kill' => 'Finalizado el proceso del servidor', + ], + 'backup' => [ + 'download' => 'Descargada la copia de seguridad :name', + 'delete' => 'Eliminada la copia de seguridad :name', + 'restore' => 'Restaurada la copia de seguridad :name (archivos eliminados: :truncate)', + 'restore-complete' => 'Restauración completa de la copia de seguridad :name', + 'restore-failed' => 'Falló la restauración de la copia de seguridad :name', + 'start' => 'Iniciada una nueva copia de seguridad :name', + 'complete' => 'Marcada la copia de seguridad :name como completada', + 'fail' => 'Marcada la copia de seguridad :name como fallida', + 'lock' => 'Bloqueada la copia de seguridad :name', + 'unlock' => 'Desbloqueada la copia de seguridad :name', + ], + 'database' => [ + 'create' => 'Creada nueva base de datos :name', + 'rotate-password' => 'Contraseña rotada para la base de datos :name', + 'delete' => 'Eliminada la base de datos :name', + ], + 'file' => [ + 'compress_one' => 'Comprimido :directory:file', + 'compress_other' => 'Comprimidos :count archivos en :directory', + 'read' => 'Visto el contenido de :file', + 'copy' => 'Creada una copia de :file', + 'create-directory' => 'Creado directorio :directory:name', + 'decompress' => 'Descomprimidos :files en :directory', + 'delete_one' => 'Eliminado :directory:files.0', + 'delete_other' => 'Eliminados :count archivos en :directory', + 'download' => 'Descargado :file', + 'pull' => 'Descargado un archivo remoto desde :url a :directory', + 'rename_one' => 'Renombrado :directory:files.0.from a :directory:files.0.to', + 'rename_other' => 'Renombrados :count archivos en :directory', + 'write' => 'Escrito nuevo contenido en :file', + 'upload' => 'Iniciada una carga de archivo', + 'uploaded' => 'Cargado :directory:file', + ], + 'sftp' => [ + 'denied' => 'Acceso SFTP bloqueado debido a permisos', + 'create_one' => 'Creado :files.0', + 'create_other' => 'Creados :count nuevos archivos', + 'write_one' => 'Modificado el contenido de :files.0', + 'write_other' => 'Modificado el contenido de :count archivos', + 'delete_one' => 'Eliminado :files.0', + 'delete_other' => 'Eliminados :count archivos', + 'create-directory_one' => 'Creado el directorio :files.0', + 'create-directory_other' => 'Creados :count directorios', + 'rename_one' => 'Renombrado :files.0.from a :files.0.to', + 'rename_other' => 'Renombrados o movidos :count archivos', + ], + 'allocation' => [ + 'create' => 'Añadida :allocation al servidor', + 'notes' => 'Actualizadas las notas para :allocation de ":old" a ":new"', + 'primary' => 'Establecida :allocation como la asignación primaria del servidor', + 'delete' => 'Eliminada la asignación :allocation', + ], + 'schedule' => [ + 'create' => 'Creado el horario :name', + 'update' => 'Actualizado el horario :name', + 'execute' => 'Ejecutado manualmente el horario :name', + 'delete' => 'Eliminado el horario :name', + ], + 'task' => [ + 'create' => 'Creada una nueva tarea ":action" para el horario :name', + 'update' => 'Actualizada la tarea ":action" para el horario :name', + 'delete' => 'Eliminada una tarea para el horario :name', + ], + 'settings' => [ + 'rename' => 'Renombrado el servidor de :old a :new', + 'description' => 'Cambiada la descripción del servidor de :old a :new', + ], + 'startup' => [ + 'edit' => 'Cambiada la variable :variable de ":old" a ":new"', + 'image' => 'Actualizada la imagen de Docker del servidor de :old a :new', + ], + 'subuser' => [ + 'create' => 'Añadido :email como subusuario', + 'update' => 'Actualizados los permisos del subusuario :email', + 'delete' => 'Eliminado :email como subusuario', + ], + ], +]; diff --git a/lang/es/admin/eggs.php b/lang/es/admin/eggs.php new file mode 100644 index 000000000..ebb5c948c --- /dev/null +++ b/lang/es/admin/eggs.php @@ -0,0 +1,19 @@ + [ + 'imported' => 'El Egg y sus variables asociadas se importaron correctamente.', + 'updated_via_import' => 'Este Egg se ha actualizado utilizando el archivo proporcionado.', + 'deleted' => 'Se eliminó correctamente el Egg solicitado del Panel.', + 'updated' => 'La configuración del Egg se ha actualizado correctamente.', + 'script_updated' => 'El script de instalación del Egg se ha actualizado y se ejecutará cada vez que se instalen servidores.', + 'egg_created' => 'Se ha creado un nuevo Egg correctamente. Deberás reiniciar cualquier daemon en ejecución para aplicar este nuevo Egg.', + ], + 'variables' => [ + 'notices' => [ + 'variable_deleted' => 'La variable ":variable" se ha eliminado y ya no estará disponible para los servidores una vez reconstruidos.', + 'variable_updated' => 'La variable ":variable" se ha actualizado. Deberás reconstruir cualquier servidor que utilice esta variable para aplicar los cambios.', + 'variable_created' => 'Se ha creado correctamente una nueva variable y se ha asignado a este Egg.', + ], + ], +]; diff --git a/lang/es/admin/node.php b/lang/es/admin/node.php new file mode 100644 index 000000000..95556057b --- /dev/null +++ b/lang/es/admin/node.php @@ -0,0 +1,15 @@ + [ + 'fqdn_not_resolvable' => 'El FQDN o la dirección IP proporcionada no se resuelve a una dirección IP válida.', + 'fqdn_required_for_ssl' => 'Se requiere un nombre de dominio completo que se resuelva a una dirección IP pública para poder utilizar SSL en este nodo.', + ], + 'notices' => [ + 'allocations_added' => 'Se han añadido correctamente las asignaciones a este nodo.', + 'node_deleted' => 'El nodo se ha eliminado correctamente del panel.', + 'node_created' => 'Se ha creado correctamente un nuevo nodo. Puedes configurar automáticamente el daemon en esta máquina visitando la pestaña \'Configuración\'. Antes de poder añadir cualquier servidor, primero debes asignar al menos una dirección IP y puerto.', + 'node_updated' => 'Se ha actualizado la información del nodo. Si se cambiaron ajustes del daemon, necesitarás reiniciarlo para que los cambios surtan efecto.', + 'unallocated_deleted' => 'Se han eliminado todos los puertos no asignados para :ip.', + ], +]; diff --git a/lang/es/admin/server.php b/lang/es/admin/server.php new file mode 100644 index 000000000..38af8b29c --- /dev/null +++ b/lang/es/admin/server.php @@ -0,0 +1,27 @@ + [ + 'no_new_default_allocation' => 'Estás intentando eliminar la asignación predeterminada para este servidor pero no hay una asignación de respaldo para usar.', + 'marked_as_failed' => 'Este servidor fue marcado como que ha fallado en una instalación anterior. El estado actual no se puede cambiar en este estado.', + 'bad_variable' => 'Hubo un error de validación con la variable :name.', + 'daemon_exception' => 'Hubo una excepción al intentar comunicarse con el daemon que resultó en un código de respuesta HTTP/:code. Esta excepción ha sido registrada. (ID de solicitud: :request_id)', + 'default_allocation_not_found' => 'La asignación predeterminada solicitada no se encontró en las asignaciones de este servidor.', + ], + 'alerts' => [ + 'startup_changed' => 'La configuración de inicio de este servidor se ha actualizado. Si se cambió el huevo de este servidor, se iniciará una reinstalación ahora.', + 'server_deleted' => 'El servidor se ha eliminado correctamente del sistema.', + 'server_created' => 'El servidor se ha creado correctamente en el panel. Por favor, permite al daemon unos minutos para instalar completamente este servidor.', + 'build_updated' => 'Los detalles de construcción para este servidor se han actualizado. Algunos cambios pueden requerir un reinicio para surtir efecto.', + 'suspension_toggled' => 'El estado de suspensión del servidor se ha cambiado a :status.', + 'rebuild_on_boot' => 'Este servidor se ha marcado como que requiere una reconstrucción del contenedor Docker. Esto ocurrirá la próxima vez que se inicie el servidor.', + 'install_toggled' => 'El estado de instalación para este servidor se ha cambiado.', + 'server_reinstalled' => 'Este servidor ha sido encolado para una reinstalación que comienza ahora.', + 'details_updated' => 'Los detalles del servidor se han actualizado correctamente.', + 'docker_image_updated' => 'Se cambió con éxito la imagen Docker predeterminada para usar en este servidor. Se requiere un reinicio para aplicar este cambio.', + 'node_required' => 'Debes tener al menos un nodo configurado antes de poder añadir un servidor a este panel.', + 'transfer_nodes_required' => 'Debes tener al menos dos nodos configurados antes de poder transferir servidores.', + 'transfer_started' => 'La transferencia del servidor se ha iniciado.', + 'transfer_not_viable' => 'El nodo que seleccionaste no tiene el espacio en disco o la memoria disponible requerida para acomodar este servidor.', + ], +]; diff --git a/lang/es/admin/user.php b/lang/es/admin/user.php new file mode 100644 index 000000000..ab4373270 --- /dev/null +++ b/lang/es/admin/user.php @@ -0,0 +1,12 @@ + [ + 'user_has_servers' => 'No se puede eliminar un usuario con servidores activos asociados a su cuenta. Por favor, elimina sus servidores antes de continuar.', + 'user_is_self' => 'No se puede eliminar tu propia cuenta de usuario.', + ], + 'notices' => [ + 'account_created' => 'La cuenta se ha creado correctamente.', + 'account_updated' => 'La cuenta se ha actualizado correctamente.', + ], +]; diff --git a/lang/es/auth.php b/lang/es/auth.php new file mode 100644 index 000000000..a3c86efb4 --- /dev/null +++ b/lang/es/auth.php @@ -0,0 +1,27 @@ + 'Iniciar sesión', + 'go_to_login' => 'Ir al inicio de sesión', + 'failed' => 'No se pudo encontrar ninguna cuenta que coincida con esas credenciales.', + + 'forgot_password' => [ + 'label' => '¿Olvidaste tu contraseña?', + 'label_help' => 'Ingresa la dirección de correo electrónico de tu cuenta para recibir instrucciones sobre cómo restablecer tu contraseña.', + 'button' => 'Recuperar cuenta', + ], + + 'reset_password' => [ + 'button' => 'Restablecer e iniciar sesión', + ], + + 'two_factor' => [ + 'label' => 'Token de 2 Factores', + 'label_help' => 'Esta cuenta requiere un segundo nivel de autenticación para continuar. Por favor, ingresa el código generado por tu dispositivo para completar este inicio de sesión.', + 'checkpoint_failed' => 'El token de autenticación de dos factores no era válido.', + ], + + 'throttle' => 'Demasiados intentos de inicio de sesión. Por favor, inténtalo de nuevo en :seconds segundos.', + 'password_requirements' => 'La contraseña debe tener al menos 8 caracteres de longitud y debe ser única para este sitio.', + '2fa_must_be_enabled' => 'El administrador ha requerido que la Autenticación de 2 Factores esté habilitada para tu cuenta para poder usar el Panel.', +]; diff --git a/lang/es/command/messages.php b/lang/es/command/messages.php new file mode 100644 index 000000000..1723749c2 --- /dev/null +++ b/lang/es/command/messages.php @@ -0,0 +1,59 @@ + [ + 'search_users' => 'Introduce un nombre de usuario, ID de usuario o dirección de correo electrónico', + 'select_search_user' => 'ID del usuario a eliminar (Introduce \'0\' para volver a buscar)', + 'deleted' => 'Usuario eliminado correctamente del Panel.', + 'confirm_delete' => '¿Estás seguro de que quieres eliminar este usuario del Panel?', + 'no_users_found' => 'No se encontraron usuarios para el término de búsqueda proporcionado.', + 'multiple_found' => 'Se encontraron varias cuentas para el usuario proporcionado, no se puede eliminar un usuario debido a la bandera --no-interaction.', + 'ask_admin' => '¿Es este usuario un administrador?', + 'ask_email' => 'Dirección de correo electrónico', + 'ask_username' => 'Nombre de usuario', + 'ask_name_first' => 'Nombre', + 'ask_name_last' => 'Apellido', + 'ask_password' => 'Contraseña', + 'ask_password_tip' => 'Si deseas crear una cuenta con una contraseña aleatoria enviada por correo electrónico al usuario, vuelve a ejecutar este comando (CTRL+C) y pasa la bandera `--no-password`.', + 'ask_password_help' => 'Las contraseñas deben tener al menos 8 caracteres de longitud y contener al menos una letra mayúscula y un número.', + '2fa_help_text' => [ + 'Este comando deshabilitará la autenticación de dos factores para la cuenta de un usuario si está habilitada. Esto solo debe usarse como un comando de recuperación de cuenta si el usuario está bloqueado fuera de su cuenta.', + 'Si esto no es lo que querías hacer, presiona CTRL+C para salir de este proceso.', + ], + '2fa_disabled' => 'La autenticación de dos factores ha sido desactivada para :email.', + ], + 'schedule' => [ + 'output_line' => 'Enviando trabajo para la primera tarea en `:schedule` (:hash).', + ], + 'maintenance' => [ + 'deleting_service_backup' => 'Eliminando archivo de copia de seguridad del servicio :file.', + ], + 'server' => [ + 'rebuild_failed' => 'La solicitud de reconstrucción para ":name" (#:id) en el nodo ":node" falló con el error: :message', + 'reinstall' => [ + 'failed' => 'La solicitud de reinstalación para ":name" (#:id) en el nodo ":node" falló con el error: :message', + 'confirm' => 'Estás a punto de reinstalar contra un grupo de servidores. ¿Deseas continuar?', + ], + 'power' => [ + 'confirm' => 'Estás a punto de realizar una :action contra :count servidores. ¿Deseas continuar?', + 'action_failed' => 'La acción de energía para ":name" (#:id) en el nodo ":node" falló con el error: :message', + ], + ], + 'environment' => [ + 'mail' => [ + 'ask_smtp_host' => 'Host SMTP (por ejemplo, smtp.gmail.com)', + 'ask_smtp_port' => 'Puerto SMTP', + 'ask_smtp_username' => 'Nombre de usuario SMTP', + 'ask_smtp_password' => 'Contraseña SMTP', + 'ask_mailgun_domain' => 'Dominio de Mailgun', + 'ask_mailgun_endpoint' => 'Extremo de Mailgun', + 'ask_mailgun_secret' => 'Secreto de Mailgun', + 'ask_mandrill_secret' => 'Secreto de Mandrill', + 'ask_postmark_username' => 'Clave API de Postmark', + 'ask_driver' => '¿Qué controlador debe usarse para enviar correos electrónicos?', + 'ask_mail_from' => 'Dirección de correo electrónico desde la cual deben originarse los correos electrónicos', + 'ask_mail_name' => 'Nombre que debe aparecer en los correos electrónicos', + 'ask_encryption' => 'Método de cifrado a utilizar', + ], + ], +]; diff --git a/lang/es/dashboard/account.php b/lang/es/dashboard/account.php new file mode 100644 index 000000000..df74c95d9 --- /dev/null +++ b/lang/es/dashboard/account.php @@ -0,0 +1,28 @@ + [ + 'title' => 'Actualizar tu correo electrónico', + 'updated' => 'Tu dirección de correo electrónico ha sido actualizada.', + ], + 'password' => [ + 'title' => 'Cambiar tu contraseña', + 'requirements' => 'Tu nueva contraseña debe tener al menos 8 caracteres de longitud.', + 'updated' => 'Tu contraseña ha sido actualizada.', + ], + 'two_factor' => [ + 'button' => 'Configurar autenticación de 2 factores', + 'disabled' => 'La autenticación de dos factores ha sido desactivada en tu cuenta. Ya no se te pedirá que proporciones un token al iniciar sesión.', + 'enabled' => '¡La autenticación de dos factores ha sido activada en tu cuenta! A partir de ahora, al iniciar sesión, se te pedirá que proporciones el código generado por tu dispositivo.', + 'invalid' => 'El token proporcionado no era válido.', + 'setup' => [ + 'title' => 'Configurar autenticación de dos factores', + 'help' => '¿No puedes escanear el código? Ingresa el código a continuación en tu aplicación:', + 'field' => 'Introduce el token', + ], + 'disable' => [ + 'title' => 'Desactivar autenticación de dos factores', + 'field' => 'Introduce el token', + ], + ], +]; diff --git a/lang/es/dashboard/index.php b/lang/es/dashboard/index.php new file mode 100644 index 000000000..ccbdd18f2 --- /dev/null +++ b/lang/es/dashboard/index.php @@ -0,0 +1,8 @@ + 'Buscar servidores...', + 'no_matches' => 'No se encontraron servidores que coincidan con los criterios de búsqueda proporcionados.', + 'cpu_title' => 'CPU', + 'memory_title' => 'Memoria', +]; diff --git a/lang/es/exceptions.php b/lang/es/exceptions.php new file mode 100644 index 000000000..14ebcfb85 --- /dev/null +++ b/lang/es/exceptions.php @@ -0,0 +1,55 @@ + 'Se produjo una excepción al intentar comunicarse con el daemon, lo que resultó en un código de respuesta HTTP/:code. Esta excepción ha sido registrada.', + 'node' => [ + 'servers_attached' => 'Un nodo no debe tener servidores vinculados a él para poder ser eliminado.', + 'daemon_off_config_updated' => 'La configuración del daemon se ha actualizado, sin embargo, se encontró un error al intentar actualizar automáticamente el archivo de configuración en el daemon. Deberás actualizar manualmente el archivo de configuración (config.yml) para que el daemon aplique estos cambios.', + ], + 'allocations' => [ + 'server_using' => 'Actualmente hay un servidor asignado a esta asignación. Una asignación solo puede ser eliminada si ningún servidor está asignado actualmente.', + 'too_many_ports' => 'Agregar más de 1000 puertos en un solo rango a la vez no está soportado.', + 'invalid_mapping' => 'El mapeo proporcionado para el puerto :port era inválido y no pudo ser procesado.', + 'cidr_out_of_range' => 'La notación CIDR solo permite máscaras entre /25 y /32.', + 'port_out_of_range' => 'Los puertos en una asignación deben ser mayores que 1024 y menores o iguales a 65535.', + ], + 'egg' => [ + 'delete_has_servers' => 'Un Huevo con servidores activos vinculados a él no puede ser eliminado del Panel.', + 'invalid_copy_id' => 'El Huevo seleccionado para copiar un script desde no existe o está copiando un script en sí mismo.', + 'has_children' => 'Este Huevo es padre de uno o más otros Huevos. Por favor, elimina esos Huevos antes de eliminar este Huevo.', + ], + 'variables' => [ + 'env_not_unique' => 'La variable de entorno :name debe ser única para este Huevo.', + 'reserved_name' => 'La variable de entorno :name está protegida y no se puede asignar a una variable.', + 'bad_validation_rule' => 'La regla de validación ":rule" no es una regla válida para esta aplicación.', + ], + 'importer' => [ + 'json_error' => 'Hubo un error al intentar analizar el archivo JSON: :error.', + 'file_error' => 'El archivo JSON proporcionado no era válido.', + 'invalid_json_provided' => 'El archivo JSON proporcionado no está en un formato que pueda ser reconocido.', + ], + 'subusers' => [ + 'editing_self' => 'No está permitido editar tu propia cuenta de subusuario.', + 'user_is_owner' => 'No puedes agregar al propietario del servidor como subusuario para este servidor.', + 'subuser_exists' => 'Ya hay un usuario con esa dirección de correo electrónico asignado como subusuario para este servidor.', + ], + 'databases' => [ + 'delete_has_databases' => 'No se puede eliminar un servidor de host de base de datos que tiene bases de datos activas vinculadas a él.', + ], + 'tasks' => [ + 'chain_interval_too_long' => 'El tiempo máximo de intervalo para una tarea encadenada es de 15 minutos.', + ], + 'locations' => [ + 'has_nodes' => 'No se puede eliminar una ubicación que tiene nodos activos vinculados a ella.', + ], + 'users' => [ + 'node_revocation_failed' => 'Error al revocar las claves en Nodo #:node. :error', + ], + 'deployment' => [ + 'no_viable_nodes' => 'No se encontraron nodos que satisfagan los requisitos especificados para el despliegue automático.', + 'no_viable_allocations' => 'No se encontraron asignaciones que satisfagan los requisitos para el despliegue automático.', + ], + 'api' => [ + 'resource_not_found' => 'El recurso solicitado no existe en este servidor.', + ], +]; diff --git a/lang/es/pagination.php b/lang/es/pagination.php new file mode 100644 index 000000000..51862f2eb --- /dev/null +++ b/lang/es/pagination.php @@ -0,0 +1,17 @@ + '« Anterior', + 'next' => 'Siguiente »', +]; diff --git a/lang/es/passwords.php b/lang/es/passwords.php new file mode 100644 index 000000000..1f0855205 --- /dev/null +++ b/lang/es/passwords.php @@ -0,0 +1,19 @@ + 'Las contraseñas deben tener al menos seis caracteres y coincidir con la confirmación.', + 'reset' => '¡Tu contraseña ha sido restablecida!', + 'sent' => '¡Hemos enviado por correo electrónico el enlace para restablecer tu contraseña!', + 'token' => 'Este token de restablecimiento de contraseña no es válido.', + 'user' => 'No podemos encontrar un usuario con esa dirección de correo electrónico.', +]; diff --git a/lang/es/server/users.php b/lang/es/server/users.php new file mode 100644 index 000000000..b71f9389a --- /dev/null +++ b/lang/es/server/users.php @@ -0,0 +1,33 @@ + [ + 'websocket_*' => 'Permite el acceso al websocket para este servidor.', + 'control_console' => 'Permite al usuario enviar datos a la consola del servidor.', + 'control_start' => 'Permite al usuario iniciar la instancia del servidor.', + 'control_stop' => 'Permite al usuario detener la instancia del servidor.', + 'control_restart' => 'Permite al usuario reiniciar la instancia del servidor.', + 'control_kill' => 'Permite al usuario eliminar la instancia del servidor.', + 'user_create' => 'Permite al usuario crear nuevas cuentas de usuario para el servidor.', + 'user_read' => 'Permite al usuario ver los usuarios asociados con este servidor.', + 'user_update' => 'Permite al usuario modificar otros usuarios asociados con este servidor.', + 'user_delete' => 'Permite al usuario eliminar otros usuarios asociados con este servidor.', + 'file_create' => 'Permite al usuario crear nuevos archivos y directorios.', + 'file_read' => 'Permite al usuario ver archivos y carpetas asociados con esta instancia de servidor, así como ver su contenido.', + 'file_update' => 'Permite al usuario actualizar archivos y carpetas asociados con el servidor.', + 'file_delete' => 'Permite al usuario eliminar archivos y directorios.', + 'file_archive' => 'Permite al usuario crear archivos de archivos y descomprimir archivos existentes.', + 'file_sftp' => 'Permite al usuario realizar las acciones de archivo anteriores utilizando un cliente SFTP.', + 'allocation_read' => 'Permite el acceso a las páginas de gestión de asignación del servidor.', + 'allocation_update' => 'Permite al usuario realizar modificaciones en las asignaciones del servidor.', + 'database_create' => 'Permite al usuario crear una nueva base de datos para el servidor.', + 'database_read' => 'Permite al usuario ver las bases de datos del servidor.', + 'database_update' => 'Permite al usuario realizar modificaciones en una base de datos. Si el usuario no tiene también el permiso de "Ver contraseña", no podrá modificar la contraseña.', + 'database_delete' => 'Permite al usuario eliminar una instancia de base de datos.', + 'database_view_password' => 'Permite al usuario ver la contraseña de una base de datos en el sistema.', + 'schedule_create' => 'Permite al usuario crear un nuevo horario para el servidor.', + 'schedule_read' => 'Permite al usuario ver los horarios de un servidor.', + 'schedule_update' => 'Permite al usuario realizar modificaciones en un horario existente del servidor.', + 'schedule_delete' => 'Permite al usuario eliminar un horario del servidor.', + ], +]; diff --git a/lang/es/strings.php b/lang/es/strings.php new file mode 100644 index 000000000..107d4deb5 --- /dev/null +++ b/lang/es/strings.php @@ -0,0 +1,95 @@ + 'Correo electrónico', + 'email_address' => 'Dirección de correo electrónico', + 'user_identifier' => 'Nombre de usuario o Correo electrónico', + 'password' => 'Contraseña', + 'new_password' => 'Nueva contraseña', + 'confirm_password' => 'Confirmar nueva contraseña', + 'login' => 'Iniciar sesión', + 'home' => 'Inicio', + 'servers' => 'Servidores', + 'id' => 'ID', + 'name' => 'Nombre', + 'node' => 'Nodo', + 'connection' => 'Conexión', + 'memory' => 'Memoria', + 'cpu' => 'CPU', + 'disk' => 'Disco', + 'status' => 'Estado', + 'search' => 'Buscar', + 'suspended' => 'Suspendido', + 'account' => 'Cuenta', + 'security' => 'Seguridad', + 'ip' => 'Dirección IP', + 'last_activity' => 'Última Actividad', + 'revoke' => 'Revocar', + '2fa_token' => 'Token de Autenticación', + 'submit' => 'Enviar', + 'close' => 'Cerrar', + 'settings' => 'Ajustes', + 'configuration' => 'Configuración', + 'sftp' => 'SFTP', + 'databases' => 'Bases de Datos', + 'memo' => 'Nota', + 'created' => 'Creado', + 'expires' => 'Caduca', + 'public_key' => 'Token', + 'api_access' => 'Acceso API', + 'never' => 'nunca', + 'sign_out' => 'Cerrar sesión', + 'admin_control' => 'Control de Administrador', + 'required' => 'Requerido', + 'port' => 'Puerto', + 'username' => 'Nombre de usuario', + 'database' => 'Base de datos', + 'new' => 'Nuevo', + 'danger' => 'Peligro', + 'create' => 'Crear', + 'select_all' => 'Seleccionar Todo', + 'select_none' => 'Seleccionar Ninguno', + 'alias' => 'Alias', + 'primary' => 'Principal', + 'make_primary' => 'Hacer Principal', + 'none' => 'Ninguno', + 'cancel' => 'Cancelar', + 'created_at' => 'Creado en', + 'action' => 'Acción', + 'data' => 'Datos', + 'queued' => 'En cola', + 'last_run' => 'Última Ejecución', + 'next_run' => 'Próxima Ejecución', + 'not_run_yet' => 'Todavía no se ha ejecutado', + 'yes' => 'Sí', + 'no' => 'No', + 'delete' => 'Eliminar', + '2fa' => '2FA', + 'logout' => 'Cerrar sesión', + 'admin_cp' => 'Panel de Control de Administrador', + 'optional' => 'Opcional', + 'read_only' => 'Solo Lectura', + 'relation' => 'Relación', + 'owner' => 'Propietario', + 'admin' => 'Administrador', + 'subuser' => 'Subusuario', + 'captcha_invalid' => 'El captcha proporcionado no es válido.', + 'tasks' => 'Tareas', + 'seconds' => 'Segundos', + 'minutes' => 'Minutos', + 'under_maintenance' => 'En Mantenimiento', + 'days' => [ + 'sun' => 'Domingo', + 'mon' => 'Lunes', + 'tues' => 'Martes', + 'wed' => 'Miércoles', + 'thurs' => 'Jueves', + 'fri' => 'Viernes', + 'sat' => 'Sábado', + ], + 'last_used' => 'Último Uso', + 'enable' => 'Activar', + 'disable' => 'Desactivar', + 'save' => 'Guardar', + 'copyright' => '® 2024 - :year Pelican', +]; diff --git a/lang/es/validation.php b/lang/es/validation.php new file mode 100644 index 000000000..c5b76a490 --- /dev/null +++ b/lang/es/validation.php @@ -0,0 +1,106 @@ + 'El campo :attribute debe ser aceptado.', + 'active_url' => 'El campo :attribute no es una URL válida.', + 'after' => 'El campo :attribute debe ser una fecha posterior a :date.', + 'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.', + 'alpha' => 'El campo :attribute solo puede contener letras.', + 'alpha_dash' => 'El campo :attribute solo puede contener letras, números y guiones.', + 'alpha_num' => 'El campo :attribute solo puede contener letras y números.', + 'array' => 'El campo :attribute debe ser un conjunto.', + 'before' => 'El campo :attribute debe ser una fecha anterior a :date.', + 'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.', + 'between' => [ + 'numeric' => 'El campo :attribute debe estar entre :min y :max.', + 'file' => 'El campo :attribute debe tener entre :min y :max kilobytes.', + 'string' => 'El campo :attribute debe tener entre :min y :max caracteres.', + 'array' => 'El campo :attribute debe tener entre :min y :max elementos.', + ], + 'boolean' => 'El campo :attribute debe ser verdadero o falso.', + 'confirmed' => 'La confirmación de :attribute no coincide.', + 'date' => 'El campo :attribute no es una fecha válida.', + 'date_format' => 'El campo :attribute no coincide con el formato :format.', + 'different' => 'Los campos :attribute y :other deben ser diferentes.', + 'digits' => 'El campo :attribute debe tener :digits dígitos.', + 'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.', + 'dimensions' => 'Las dimensiones de la imagen :attribute no son válidas.', + 'distinct' => 'El campo :attribute tiene un valor duplicado.', + 'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.', + 'exists' => 'El :attribute seleccionado no es válido.', + 'file' => 'El campo :attribute debe ser un archivo.', + 'filled' => 'El campo :attribute es obligatorio.', + 'image' => 'El campo :attribute debe ser una imagen.', + 'in' => 'El :attribute seleccionado no es válido.', + 'in_array' => 'El campo :attribute no existe en :other.', + 'integer' => 'El campo :attribute debe ser un número entero.', + 'ip' => 'El campo :attribute debe ser una dirección IP válida.', + 'json' => 'El campo :attribute debe ser una cadena JSON válida.', + 'max' => [ + 'numeric' => 'El campo :attribute no debe ser mayor que :max.', + 'file' => 'El tamaño del archivo :attribute no debe ser mayor que :max kilobytes.', + 'string' => 'El campo :attribute no debe contener más de :max caracteres.', + 'array' => 'El campo :attribute no debe contener más de :max elementos.', + ], + 'mimes' => 'El campo :attribute debe ser un archivo del tipo: :values.', + 'mimetypes' => 'El campo :attribute debe ser un archivo del tipo: :values.', + 'min' => [ + 'numeric' => 'El campo :attribute debe tener al menos :min.', + 'file' => 'El tamaño del archivo :attribute debe ser al menos :min kilobytes.', + 'string' => 'El campo :attribute debe tener al menos :min caracteres.', + 'array' => 'El campo :attribute debe tener al menos :min elementos.', + ], + 'not_in' => 'El campo :attribute seleccionado no es válido.', + 'numeric' => 'El campo :attribute debe ser un número.', + 'present' => 'El campo :attribute debe estar presente.', + 'regex' => 'El formato del campo :attribute no es válido.', + 'required' => 'El campo :attribute es obligatorio.', + 'required_if' => 'El campo :attribute es obligatorio cuando :other es :value.', + 'required_unless' => 'El campo :attribute es obligatorio a menos que :other esté en :values.', + 'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.', + 'required_with_all' => 'El campo :attribute es obligatorio cuando :values está presente.', + 'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.', + 'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de :values está presente.', + 'same' => 'Los campos :attribute y :other deben coincidir.', + 'size' => [ + 'numeric' => 'El campo :attribute debe ser :size.', + 'file' => 'El campo :attribute debe tener :size kilobytes.', + 'string' => 'El campo :attribute debe tener :size caracteres.', + 'array' => 'El campo :attribute debe contener :size elementos.', + ], + 'string' => 'El campo :attribute debe ser una cadena de texto.', + 'timezone' => 'El campo :attribute debe ser una zona horaria válida.', + 'unique' => 'El valor del campo :attribute ya ha sido tomado.', + 'uploaded' => 'La carga del archivo :attribute ha fallado.', + 'url' => 'El formato de :attribute no es válido.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + + // Internal validation logic for Panel + 'internal' => [ + 'variable_value' => 'Variable :env', + 'invalid_password' => 'La contraseña proporcionada no es válida para esta cuenta.', + ], +]; diff --git a/license b/license index fe6b9036b..301cbf999 100644 --- a/license +++ b/license @@ -1,3 +1,7 @@ +Pelican Panel is offered under the AGPL-3 license to the open source community. +Pelican Panel is alternatively available under a commercial license. +Contact team@pelican.dev for information about commercial licensing. + GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 diff --git a/resources/scripts/components/elements/PageContentBlock.tsx b/resources/scripts/components/elements/PageContentBlock.tsx index ffea8819c..1f62eedb5 100644 --- a/resources/scripts/components/elements/PageContentBlock.tsx +++ b/resources/scripts/components/elements/PageContentBlock.tsx @@ -28,7 +28,7 @@ const PageContentBlock: React.FC = ({ title, showFlashKey

diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 91ede7fce..052373b8c 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -44,7 +44,7 @@