Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions register/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,17 @@ A simple way for users to register themselves on the panel without administrator

- Self-service user registration
- Seamless integration with existing login flow
- Optional maximum user cap (auto-disables new signups after limit is reached)
- Automatic default `user_resource_limits` assignment for newly registered users when `user-creatable-servers` is installed

## Integration with User Creatable Servers

This plugin can automatically assign default CPU, RAM, disk, and server limit values for every newly registered user.

Configure these values in the plugin settings UI:

- `max_users` (`0` = unlimited)
- `default_cpu`
- `default_memory`
- `default_disk`
- `default_server_limit` (`0` = unlimited)
9 changes: 9 additions & 0 deletions register/config/register.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

return [
'max_users' => 0,
'default_cpu' => 0,
'default_memory' => 0,
'default_disk' => 0,
'default_server_limit' => 0,
];
5 changes: 5 additions & 0 deletions register/lang/en/messages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

return [
'registration_closed' => 'Registration is currently closed because the maximum number of users has been reached.',
];
4 changes: 2 additions & 2 deletions register/plugin.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"id": "register",
"name": "Register",
"author": "Boy132",
"version": "1.0.0",
"author": "Boy132 (& TheOriginalCER06)",
"version": "1.0.1",
"description": "A simple way for users to register themselves",
"category": "plugin",
"url": "https://github.com/pelican-dev/plugins/tree/main/register",
Expand Down
71 changes: 71 additions & 0 deletions register/src/Filament/Pages/Auth/Register.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
namespace Boy132\Register\Filament\Pages\Auth;

use App\Extensions\Captcha\CaptchaService;
use Boy132\UserCreatableServers\Models\UserResourceLimits;
use Filament\Auth\Pages\Register as BaseRegister;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Component;
use Filament\Schemas\Schema;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema as SchemaFacade;
use Illuminate\Validation\ValidationException;

class Register extends BaseRegister
{
Expand All @@ -17,6 +22,13 @@ public function boot(CaptchaService $captchaService): void
$this->captchaService = $captchaService;
}

public function mount(): void
{
$this->abortIfRegistrationLimitReached();

parent::mount();
}

public function form(Schema $schema): Schema
{
$components = [
Expand Down Expand Up @@ -50,4 +62,63 @@ protected function getNameFormComponent(): Component
->label(trans('profile.username'))
->unique($this->getUserModel(), 'username');
}

/**
* @param array<string, mixed> $data
*/
protected function handleRegistration(array $data): Model
{
return DB::transaction(function () use ($data): Model {
$this->throwIfRegistrationLimitReached(true);

$user = parent::handleRegistration($data);

$this->createDefaultUserResourceLimits($user);

return $user;
});
}

private function abortIfRegistrationLimitReached(): void
{
$maxUsers = (int) config('register.max_users', 0);

if ($maxUsers > 0 && $this->getUserModel()::query()->count() >= $maxUsers) {
abort(403, trans('register::messages.registration_closed'));
}
}

private function throwIfRegistrationLimitReached(bool $lockForUpdate = false): void
{
$maxUsers = (int) config('register.max_users', 0);

$query = $this->getUserModel()::query();

if ($lockForUpdate) {
$query->lockForUpdate();
}

if ($maxUsers > 0 && $query->count() >= $maxUsers) {
throw ValidationException::withMessages([
'email' => trans('register::messages.registration_closed'),
]);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

private function createDefaultUserResourceLimits(Model $user): void
{
if (!class_exists(UserResourceLimits::class) || !SchemaFacade::hasTable('user_resource_limits')) {
return;
}

UserResourceLimits::query()->updateOrCreate(
['user_id' => $user->getKey()],
[
'cpu' => (int) config('register.default_cpu', 0),
'memory' => (int) config('register.default_memory', 0),
'disk' => (int) config('register.default_disk', 0),
'server_limit' => ((int) config('register.default_server_limit', 0)) ?: null,
],
);
}
}
111 changes: 110 additions & 1 deletion register/src/RegisterPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

namespace Boy132\Register;

use App\Contracts\Plugins\HasPluginSettings;
use Boy132\Register\Filament\Pages\Auth\Register;
use Filament\Contracts\Plugin;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Panel;
use Filament\Schemas\Components\Section;
use Illuminate\Support\Facades\Artisan;
use Throwable;

class RegisterPlugin implements Plugin
class RegisterPlugin implements HasPluginSettings, Plugin
{
public function getId(): string
{
Expand All @@ -19,4 +25,107 @@ public function register(Panel $panel): void
}

public function boot(Panel $panel): void {}

public function getSettingsForm(): array
{
return [
Section::make('Registration Limits')
->columns(1)
->schema([
TextInput::make('max_users')
->label('Maximum number of users')
->helperText('Set to 0 for unlimited registrations.')
->required()
->numeric()
->minValue(0)
->default(fn () => config('register.max_users')),
]),
Section::make('Default Resource Limits for New Users')
->columns(4)
->schema([
TextInput::make('default_cpu')
->label('CPU (%)')
->required()
->numeric()
->minValue(0)
->default(fn () => config('register.default_cpu')),
TextInput::make('default_memory')
->label('RAM (MB)')
->required()
->numeric()
->minValue(0)
->default(fn () => config('register.default_memory')),
TextInput::make('default_disk')
->label('Disk (MB)')
->required()
->numeric()
->minValue(0)
->default(fn () => config('register.default_disk')),
TextInput::make('default_server_limit')
->label('Server limit')
->helperText('Set to 0 for unlimited servers.')
->required()
->numeric()
->minValue(0)
->default(fn () => config('register.default_server_limit')),
]),
];
}

public function saveSettings(array $data): void
{
try {
$this->persistSettingsToConfig($data);

Notification::make()
->title('Settings saved')
->success()
->send();
} catch (Throwable $exception) {
report($exception);

Notification::make()
->title('Unable to save settings')
->body('Could not write to register/config/register.php. Check file permissions.')
->danger()
->send();
}
}

/**
* @param array<string, mixed> $data
*/
private function persistSettingsToConfig(array $data): void
{
$configPath = plugin_path($this->getId(), 'config/register.php');

$config = [
'max_users' => max(0, (int) ($data['max_users'] ?? 0)),
'default_cpu' => max(0, (int) ($data['default_cpu'] ?? 0)),
'default_memory' => max(0, (int) ($data['default_memory'] ?? 0)),
'default_disk' => max(0, (int) ($data['default_disk'] ?? 0)),
'default_server_limit' => max(0, (int) ($data['default_server_limit'] ?? 0)),
];
Comment thread
coderabbitai[bot] marked this conversation as resolved.

$content = <<<'PHP'
<?php

return
PHP;

$content .= var_export($config, true);
$content .= ";\n";

if (file_put_contents($configPath, $content, LOCK_EX) === false) {
throw new \RuntimeException('Failed writing register config file.');
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

foreach ($config as $key => $value) {
config()->set("register.{$key}", $value);
}

if (app()->configurationIsCached()) {
Artisan::call('config:clear');
}
}
}