File transfer
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Migration: Network Metrics Tables
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('addon_network_metrics', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('server_id')->index();
|
||||
$table->unsignedInteger('node_id')->index();
|
||||
$table->unsignedBigInteger('rx_bytes')->default(0);
|
||||
$table->unsignedBigInteger('tx_bytes')->default(0);
|
||||
$table->enum('resolution', ['raw', '5m', '1h', '1d'])->default('raw');
|
||||
$table->timestamp('recorded_at');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['server_id', 'resolution', 'recorded_at']);
|
||||
$table->index(['node_id', 'recorded_at']);
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('node_id')
|
||||
->references('id')->on('nodes')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('addon_network_port_metrics', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('server_id')->index();
|
||||
$table->unsignedSmallInteger('port');
|
||||
$table->enum('protocol', ['tcp', 'udp'])->default('tcp');
|
||||
$table->unsignedBigInteger('rx_bytes')->default(0);
|
||||
$table->unsignedBigInteger('tx_bytes')->default(0);
|
||||
$table->enum('resolution', ['raw', '5m', '1h', '1d'])->default('raw');
|
||||
$table->timestamp('recorded_at');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['server_id', 'port', 'recorded_at']);
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('addon_network_flows', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('src_server_id')->nullable()->index();
|
||||
$table->unsignedInteger('dst_server_id')->nullable()->index();
|
||||
$table->string('src_ip', 45)->nullable();
|
||||
$table->string('dst_ip', 45)->nullable();
|
||||
$table->unsignedBigInteger('bytes')->default(0);
|
||||
$table->unsignedBigInteger('packets')->default(0);
|
||||
$table->timestamp('recorded_at');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['src_server_id', 'recorded_at']);
|
||||
$table->index(['dst_server_id', 'recorded_at']);
|
||||
|
||||
$table->foreign('src_server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('set null');
|
||||
$table->foreign('dst_server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('addon_network_flows');
|
||||
Schema::dropIfExists('addon_network_port_metrics');
|
||||
Schema::dropIfExists('addon_network_metrics');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Migration: Role-Based Permissions Tables
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('addon_roles', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name', 100);
|
||||
$table->text('description')->nullable();
|
||||
$table->string('color', 7)->default('#6366f1'); // indigo
|
||||
$table->unsignedInteger('priority')->default(0);
|
||||
$table->boolean('is_default')->default(false);
|
||||
$table->unsignedInteger('created_by')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('created_by')
|
||||
->references('id')->on('users')
|
||||
->onDelete('set null');
|
||||
});
|
||||
|
||||
Schema::create('addon_role_permissions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('role_id');
|
||||
$table->string('permission', 100);
|
||||
$table->enum('value', ['allow', 'deny']);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['role_id', 'permission']);
|
||||
$table->index(['role_id', 'permission']);
|
||||
|
||||
$table->foreign('role_id')
|
||||
->references('id')->on('addon_roles')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('addon_server_role_assignments', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('server_id');
|
||||
$table->unsignedInteger('user_id');
|
||||
$table->unsignedInteger('role_id');
|
||||
$table->unsignedInteger('assigned_by')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['server_id', 'user_id', 'role_id']);
|
||||
$table->index(['server_id', 'user_id']);
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('user_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('role_id')
|
||||
->references('id')->on('addon_roles')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('assigned_by')
|
||||
->references('id')->on('users')
|
||||
->onDelete('set null');
|
||||
});
|
||||
|
||||
Schema::create('addon_server_permission_overrides', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('server_id');
|
||||
$table->unsignedInteger('user_id');
|
||||
$table->string('permission', 100);
|
||||
$table->enum('value', ['allow', 'deny', 'unset'])->default('unset');
|
||||
$table->unsignedInteger('set_by')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['server_id', 'user_id', 'permission']);
|
||||
$table->index(['server_id', 'user_id']);
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('user_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('addon_role_audit_log', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('actor_id')->nullable();
|
||||
$table->string('action', 80);
|
||||
$table->string('target_type', 50)->nullable();
|
||||
$table->unsignedBigInteger('target_id')->nullable();
|
||||
$table->json('payload')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['actor_id', 'created_at']);
|
||||
$table->index(['action', 'created_at']);
|
||||
|
||||
$table->foreign('actor_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('addon_role_audit_log');
|
||||
Schema::dropIfExists('addon_server_permission_overrides');
|
||||
Schema::dropIfExists('addon_server_role_assignments');
|
||||
Schema::dropIfExists('addon_role_permissions');
|
||||
Schema::dropIfExists('addon_roles');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Migration: File Revision History Tables
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('addon_file_revisions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('server_id');
|
||||
$table->string('file_path', 500);
|
||||
$table->char('path_hash', 64); // SHA-256(server_id.file_path) for lookup
|
||||
$table->char('content_hash', 64); // SHA-256 of content (deduplication)
|
||||
$table->unsignedInteger('revision_number')->default(1);
|
||||
$table->string('storage_key', 255); // relative path under storage disk
|
||||
$table->enum('storage_type', ['full', 'delta'])->default('full');
|
||||
$table->unsignedBigInteger('size_bytes')->default(0);
|
||||
$table->unsignedBigInteger('compressed_size')->default(0);
|
||||
$table->unsignedInteger('author_id')->nullable();
|
||||
$table->string('change_summary', 500)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->unique(['server_id', 'path_hash', 'revision_number']);
|
||||
$table->index(['server_id', 'path_hash', 'created_at']);
|
||||
$table->index('content_hash');
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('author_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('set null');
|
||||
});
|
||||
|
||||
Schema::create('addon_file_revision_storage_usage', function (Blueprint $table) {
|
||||
$table->unsignedInteger('server_id')->primary();
|
||||
$table->unsignedBigInteger('total_bytes')->default(0);
|
||||
$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('addon_file_revision_storage_usage');
|
||||
Schema::dropIfExists('addon_file_revisions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Migration: Console Autocomplete Tables
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('addon_command_definitions', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('server_id')->nullable()->index();
|
||||
$table->unsignedInteger('node_id')->nullable()->index();
|
||||
$table->unsignedInteger('egg_id')->nullable()->index();
|
||||
$table->string('plugin_source', 100)->default('custom');
|
||||
$table->string('command_name', 100)->index();
|
||||
$table->json('definition'); // full command schema
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('node_id')
|
||||
->references('id')->on('nodes')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('addon_console_player_cache', function (Blueprint $table) {
|
||||
$table->unsignedInteger('server_id');
|
||||
$table->string('player_name', 64);
|
||||
$table->timestamp('last_seen_at')->useCurrent()->useCurrentOnUpdate();
|
||||
|
||||
$table->primary(['server_id', 'player_name']);
|
||||
$table->index(['server_id', 'last_seen_at']);
|
||||
|
||||
$table->foreign('server_id')
|
||||
->references('id')->on('servers')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('addon_console_player_cache');
|
||||
Schema::dropIfExists('addon_command_definitions');
|
||||
}
|
||||
};
|
||||
109
database/seeders/DefaultRolesSeeder.php
Normal file
109
database/seeders/DefaultRolesSeeder.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Default Roles Seeder
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Addons\AdvancedAdmin\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Models\Role;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Models\RolePermission;
|
||||
|
||||
class DefaultRolesSeeder extends Seeder
|
||||
{
|
||||
private const ROLES = [
|
||||
[
|
||||
'name' => 'Owner',
|
||||
'description' => 'Full server access — assigned to the server owner',
|
||||
'color' => '#f59e0b',
|
||||
'priority' => 100,
|
||||
'is_default' => false,
|
||||
'permissions' => [
|
||||
'control.console' => 'allow', 'control.start' => 'allow', 'control.stop' => 'allow', 'control.restart' => 'allow',
|
||||
'file.read' => 'allow', 'file.read-content' => 'allow', 'file.create' => 'allow', 'file.update' => 'allow', 'file.delete' => 'allow', 'file.archive' => 'allow', 'file.sftp' => 'allow',
|
||||
'backup.read' => 'allow', 'backup.create' => 'allow', 'backup.delete' => 'allow', 'backup.download' => 'allow', 'backup.restore' => 'allow',
|
||||
'allocation.read' => 'allow', 'allocation.create' => 'allow', 'allocation.update' => 'allow', 'allocation.delete' => 'allow',
|
||||
'startup.read' => 'allow', 'startup.update' => 'allow', 'startup.docker-image' => 'allow',
|
||||
'database.read' => 'allow', 'database.create' => 'allow', 'database.update' => 'allow', 'database.delete' => 'allow', 'database.view-password' => 'allow',
|
||||
'schedule.read' => 'allow', 'schedule.create' => 'allow', 'schedule.update' => 'allow', 'schedule.delete' => 'allow',
|
||||
'settings.read' => 'allow', 'settings.rename' => 'allow', 'settings.reinstall' => 'allow',
|
||||
'user.read' => 'allow', 'user.create' => 'allow', 'user.update' => 'allow', 'user.delete' => 'allow',
|
||||
'activity.read' => 'allow', 'websocket.connect' => 'allow',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Administrator',
|
||||
'description' => 'High-privilege access — can manage files, users, databases',
|
||||
'color' => '#ef4444',
|
||||
'priority' => 80,
|
||||
'is_default' => false,
|
||||
'permissions' => [
|
||||
'control.console' => 'allow', 'control.start' => 'allow', 'control.stop' => 'allow', 'control.restart' => 'allow',
|
||||
'file.read' => 'allow', 'file.read-content' => 'allow', 'file.create' => 'allow', 'file.update' => 'allow', 'file.delete' => 'allow', 'file.archive' => 'allow', 'file.sftp' => 'allow',
|
||||
'backup.read' => 'allow', 'backup.create' => 'allow', 'backup.delete' => 'allow', 'backup.download' => 'allow', 'backup.restore' => 'allow',
|
||||
'database.read' => 'allow', 'database.create' => 'allow', 'database.update' => 'allow', 'database.delete' => 'allow', 'database.view-password' => 'allow',
|
||||
'schedule.read' => 'allow', 'schedule.create' => 'allow', 'schedule.update' => 'allow', 'schedule.delete' => 'allow',
|
||||
'settings.read' => 'allow', 'user.read' => 'allow', 'user.create' => 'allow', 'user.update' => 'allow',
|
||||
'activity.read' => 'allow', 'websocket.connect' => 'allow',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Moderator',
|
||||
'description' => 'Console access, read files, manage schedules',
|
||||
'color' => '#3b82f6',
|
||||
'priority' => 50,
|
||||
'is_default' => false,
|
||||
'permissions' => [
|
||||
'control.console' => 'allow', 'control.start' => 'allow', 'control.stop' => 'allow', 'control.restart' => 'allow',
|
||||
'file.read' => 'allow', 'file.read-content' => 'allow',
|
||||
'backup.read' => 'allow', 'backup.create' => 'allow',
|
||||
'schedule.read' => 'allow', 'schedule.create' => 'allow', 'schedule.update' => 'allow',
|
||||
'settings.read' => 'allow', 'activity.read' => 'allow', 'websocket.connect' => 'allow',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Viewer',
|
||||
'description' => 'Read-only access — can view console and files',
|
||||
'color' => '#6b7280',
|
||||
'priority' => 10,
|
||||
'is_default' => true,
|
||||
'permissions' => [
|
||||
'control.console' => 'allow',
|
||||
'file.read' => 'allow', 'file.read-content' => 'allow',
|
||||
'backup.read' => 'allow',
|
||||
'schedule.read' => 'allow',
|
||||
'settings.read' => 'allow', 'activity.read' => 'allow', 'websocket.connect' => 'allow',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
foreach (self::ROLES as $roleData) {
|
||||
if (Role::where('name', $roleData['name'])->exists()) continue;
|
||||
|
||||
$role = Role::create([
|
||||
'name' => $roleData['name'],
|
||||
'description' => $roleData['description'],
|
||||
'color' => $roleData['color'],
|
||||
'priority' => $roleData['priority'],
|
||||
'is_default' => $roleData['is_default'],
|
||||
'created_by' => null,
|
||||
]);
|
||||
|
||||
foreach ($roleData['permissions'] as $perm => $value) {
|
||||
RolePermission::create([
|
||||
'role_id' => $role->id,
|
||||
'permission' => $perm,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->command->info("Created default role: {$roleData['name']}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user