fix: ensure invitation feature is disabled when registrations are not

Signed-off-by: Miguel Nogueira <me@nogueira.codes>
This commit is contained in:
2025-08-07 21:21:38 +01:00
parent 0de1be64b5
commit f551576730
6 changed files with 136 additions and 35 deletions

View File

@@ -2,7 +2,10 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\ApproveInviteRequest;
use App\Http\Requests\DenyInviteRequest;
use App\Http\Requests\InvitationRequest; use App\Http\Requests\InvitationRequest;
use App\Http\Requests\ValidateInviteRequest;
use App\Invitation; use App\Invitation;
use App\Mail\InviteApprovedMail; use App\Mail\InviteApprovedMail;
use App\Mail\InvitedToApp; use App\Mail\InvitedToApp;
@@ -60,7 +63,7 @@ class InvitationController extends Controller
return redirect()->back(); return redirect()->back();
} }
public function approveInvite(Request $request, Invitation $invitation) public function approveInvite(ApproveInviteRequest $request, Invitation $invitation)
{ {
$approvableStates = [ $approvableStates = [
'pending' 'pending'
@@ -88,7 +91,7 @@ class InvitationController extends Controller
} }
} }
public function denyInvite(Request $request, Invitation $invitation) public function denyInvite(DenyInviteRequest $request, Invitation $invitation)
{ {
$declinableStates = [ $declinableStates = [
'pending' 'pending'
@@ -115,7 +118,7 @@ class InvitationController extends Controller
return view('auth.redeem-invite', ['validationToken' => $request->route('token')]); return view('auth.redeem-invite', ['validationToken' => $request->route('token')]);
} }
public function validateInvite(Request $request) public function validateInvite(ValidateInviteRequest $request)
{ {
$token = $request->input('validation_token'); $token = $request->input('validation_token');
$email = $request->input('email'); $email = $request->input('email');

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests;
use App\Facades\Options;
use Illuminate\Foundation\Http\FormRequest;
class ApproveInviteRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return !Options::getOption('enable_registrations');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests;
use App\Facades\Options;
use Illuminate\Foundation\Http\FormRequest;
class DenyInviteRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return !Options::getOption('enable_registrations');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
//
];
}
}

View File

@@ -17,11 +17,7 @@ class InvitationRequest extends FormRequest
public function authorize(): bool public function authorize(): bool
{ {
if (Options::getOption('enable_registrations')) { return !Options::getOption('enable_registrations');
return false;
}
return true;
} }
protected function failedAuthorization() protected function failedAuthorization()

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests;
use App\Facades\Options;
use Illuminate\Foundation\Http\FormRequest;
class ValidateInviteRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return !Options::getOption('enable_registrations');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'validation_token' => 'required|string',
'email' => 'required|email'
];
}
}

View File

@@ -14,16 +14,30 @@
@section('content') @section('content')
@if(\App\Facades\Options::getOption('enable_registrations'))
<x-alert alert-type="danger" title="{{ __('Invitation system disabled') }}" icon="fas fa-ban">
<p>{!! __('The invitation system is currently disabled because sign ups are open to everyone. If you\'d like to change this, head over to App Settings > <a href=":globalSettingsLink">Global Settings</a> and disable registrations.', ['globalSettingsLink' => route('showSettings')]) !!}</p>
</x-alert>
@endif
<div class="row mt-5"> <div class="row mt-5">
<div class="col"> <div class="col">
<x-card id="inviteManagement" card-title="{{ __('Invitation management system') }}" footer-style="text-muted"> <x-card id="inviteManagement" card-title="{{ __('Invitation management system') }}" footer-style="text-muted">
<x-slot name="cardHeader"> <x-slot name="cardHeader">
<div class="d-flex justify-content-end"> @if(\App\Facades\Options::getOption('enable_registrations'))
<button type="button" id="inviteUserBtn" class="btn btn-success btn-sm ml-3" data-toggle="modal" data-target="#inviteUserModal"> <div class="d-flex justify-content-end">
<i class="fas fa-user-plus"></i> {{ __('Invite user') }} <button type="button" id="inviteUserBtn" class="btn btn-success btn-sm ml-3" disabled>
</button> <i class="fas fa-user-plus"></i> {{ __('Invite user') }}
</div> </button>
</div>
@else
<div class="d-flex justify-content-end">
<button type="button" id="inviteUserBtn" class="btn btn-success btn-sm ml-3" data-toggle="modal" data-target="#inviteUserModal">
<i class="fas fa-user-plus"></i> {{ __('Invite user') }}
</button>
</div>
@endif
</x-slot> </x-slot>
@if(!empty($invites) && count($invites) > 0) @if(!empty($invites) && count($invites) > 0)
@@ -111,35 +125,37 @@
</div> </div>
<x-modal id="inviteUserModal" :modalTitle="__('Invite a User')" :modalLabel="'inviteUserModalLabel'" :includeCloseButton="true"> @if(!\App\Facades\Options::getOption('enable_registrations'))
<form method="POST" action="{{ route('invitations.request') }}"> <x-modal id="inviteUserModal" :modalTitle="__('Invite a User')" :modalLabel="'inviteUserModalLabel'" :includeCloseButton="true">
@csrf <form method="POST" action="{{ route('invitations.request') }}">
<div class="input-group mt-3"> @csrf
<div class="input-group-prepend"> <div class="input-group mt-3">
<div class="input-group-prepend">
<span class="input-group-text"> <span class="input-group-text">
<i class="fas fa-envelope"></i> <i class="fas fa-envelope"></i>
</span> </span>
</div>
<label for="inviteEmail" class="sr-only">{{ __('Email address') }}</label>
<input type="email" class="form-control" id="inviteEmail" name="email" required placeholder="{{ __('Enter an email address to send the invite to') }}">
</div> </div>
<label for="inviteEmail" class="sr-only">{{ __('Email address') }}</label> <p class="text-muted mt-2 mb-2"><i class="fas fa-info-circle"></i> {{ __('Sending an invite here will immediately create an approved invite request which will in turn send this user an email message with a link. Be aware that this will allow them to register for a new account.') }}</p>
<input type="email" class="form-control" id="inviteEmail" name="email" required placeholder="{{ __('Enter an email address to send the invite to') }}"> </form>
</div>
<p class="text-muted mt-2 mb-2"><i class="fas fa-info-circle"></i> {{ __('Sending an invite here will immediately create an approved invite request which will in turn send this user an email message with a link. Be aware that this will allow them to register for a new account.') }}</p>
</form>
<x-slot name="modalFooter"> <x-slot name="modalFooter">
<button id="sendInviteBtn" class="btn btn-success" type="button"> <button id="sendInviteBtn" class="btn btn-success" type="button">
<i class="fas fa-paper-plane"></i> {{ __('Invite') }} <i class="fas fa-paper-plane"></i> {{ __('Invite') }}
</button> </button>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
document.getElementById('sendInviteBtn').addEventListener('click', function () { document.getElementById('sendInviteBtn').addEventListener('click', function () {
document.querySelector('#inviteUserModal form').submit(); document.querySelector('#inviteUserModal form').submit();
});
}); });
}); </script>
</script> </x-slot>
</x-slot>
</x-modal> </x-modal>
@endif
@stop @stop