Added Demo mode

Demo mode allows to safely run a demo version of the app, with destructive features limited.

Some bugs were also fixed in this commit.
This commit is contained in:
2021-09-04 00:44:54 +01:00
parent 8942623bde
commit 3f4bc28fd4
29 changed files with 385 additions and 83 deletions

View File

@@ -16,6 +16,22 @@
<p class="login-card-description">{{__('messages.signin_cta')}}</p>
<form action="{{ route('login') }}" method="POST" id="loginForm">
@csrf
@if ($demoActive)
<div class="alert alert-warning">
<p class="font-weight-bold"></i>{{__('Warning')}}</p>
<p>{{ __('Do not use real credentials; The application is in demo mode.') }}</p>
<p class="font-weight-bold">{{ __('Demo accounts:') }}</p>
<ul>
<li>admin@example.com</li>
<li>staffmember@example.com</li>
<li>enduser@example.com</li>
</ul>
<p>{{ __('The password is ":password" for all accounts.', ['password' => 'password']) }}</p>
</div>
@endif
<div class="form-group">
<label for="email" class="sr-only">{{__('messages.contactlabel_email')}}</label>
<input type="email" name="email" id="email" class="form-control" placeholder="Email address">

View File

@@ -14,7 +14,7 @@
<img src="{{ config('adminlte.logo_img') }}" alt="logo" class="logo">{{ config('adminlte.logo') }}
</div> <!-- main content start -->
<p class="login-card-description">{{__('messages.register_acc')}}</p>
@if(\App\Facades\Options::getOption('pw_security_policy') !== 'off')
<div class="alert alert-warning alert-dismissible">
@@ -25,7 +25,7 @@
<p>{{__('messages.pwsec.line3')}} </p>
<ul>
@switch(\App\Facades\Options::getOption('pw_security_policy'))
@case('low')
<li>A minimum of 10 characters</li>
@break
@@ -34,14 +34,14 @@
<li>A minimum of 12 characters;</li>
<li>At least one special character;</li>
<li>Lower case and upper case characters</li>
@break
@break
@case('high')
<li>A minimum of 20 characters;</li>
<li>At least one special character;</li>
<li>Lower case and upper case characters</li>
<li>At least one numerical character</li>
@break
@break
@endswitch
</ul>
@@ -49,6 +49,15 @@
@endif
@if($demoActive)
<div class="alert alert-warning">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i>{{ __('Warning') }}</p>
<p>{{ __('Do not use real credentials here. The application is in demo mode. Additionally, the database is wiped every six hours.') }}</p>
<p>{{ __('Also note: If a game license is required to sign up, you may find valid MC usernames at NameMC') }}</p>
</div>
@endif
<form action="{{ route('register') }}" method="POST" id="registerForm">
@csrf
<div class="form-group">
@@ -68,7 +77,7 @@
<input type="password" id="passwordc" name="password_confirmation" class="form-control" placeholder="{{__('messages.sronly_confirmpassword')}}" />
</div>
@if(\App\Facades\Options::getOption('requireGameLicense') && \App\Facades\Options::getOption('currentGame') == 'MINECRAFT')
<div class="form-group mt-5">
<label for="mcusername" class="sr-only">{{__('messages.sronly_mcusername')}}</label>

View File

@@ -34,6 +34,12 @@
@endif
@if(session()->has('exception'))
<script>
toastr.error("{{session('exception')}}")
</script>
@endif
@stop
@section('content')

View File

@@ -9,11 +9,46 @@
@section('js')
<script src="js/dashboard.js"></script>
<x-global-errors></x-global-errors>
@endsection
@section('content')
@if ($demoActive)
<div class="alert alert-info">
<p class="font-weight-bold"><i class="fas fa-info-circle"></i> {{__('Reminder')}}</p>
<p>{{__('The application is in demo mode.')}}</p>
<p>{{ __('Demo mode disables some app features in order to preserve it\'s integrity for everyone who wants to test it. Here\'s what\'s disabled: ') }}</p>
<ul>
<li>{{ __('All user account operations such as: ') }}
<ul>
<li>{{ __('Password change') }}</li>
<li>{{ __('Two factor authentication') }}</li>
<li>{{ __('Email change') }}</li>
<li>{{ __('Account deletion') }}</li>
</ul>
</li>
<li>{{ __('Administrative actions such as:') }}
<ul>
<li>{{__('Account suspension')}}</li>
<li>{{ __('Termination') }}</li>
<li>{{ __('Account deletion') }}</li>
<li>{{ __('Privilege editing') }}</li>
</ul>
</li>
<li>{{ __('Team file uploads') }}</li>
<li>{{__('Developer mode')}}</li>
<li>{{ __('Admin logs') }}</li>
</ul>
<p>To keep everyone safe, IP addresses are censored everywhere in the app, and they're also not collected during registration. The IP address lookup feature is also disabled.</p>
<p>Only system administrators can disable demo mode - it cannot be disabled via app settings.</p>
<p class="font-weight-bold">Note! The database is wiped every six hours during demo mode.</p>
</div>
@endif
@if (!$vacancies->isEmpty())
@foreach($vacancies as $vacancy)
@@ -80,7 +115,7 @@
<!-- small box -->
<div class="small-box bg-info">
<div class="inner">
<h3>{{ $openApplications ?? 0 }}</h3>
<h3>{{ $totalNewSingle ?? 0 }}</h3>
<p>{{__('messages.ongoing_apps')}}</p>
</div>
@@ -95,7 +130,7 @@
<!-- small box -->
<div class="small-box bg-danger">
<div class="inner">
<h3>{{ $deniedApplications ?? 0 }}</h3>
<h3>{{ $totalDeniedSingle ?? 0 }}</h3>
<p>{{__('messages.denied_apps')}}</p>
</div>
@@ -190,7 +225,7 @@
@endif
@if ($isEligibleForApplication && !Auth::user()->isStaffMember())
@if (!$vacancies->isEmpty() && $isEligibleForApplication && !Auth::user()->isStaffMember())
<div class="row mt-5 mb-5">
<div class="col text-center">

View File

@@ -13,43 +13,56 @@
@section('content')
<x-modal id="upload-dropzone" modal-label="upload-dropzone-modal" modal-title="Upload Files" include-close-button="true">
@if(!$demoActive)
<x-modal id="upload-dropzone" modal-label="upload-dropzone-modal" modal-title="Upload Files" include-close-button="true">
<form action="{{route('uploadTeamFile')}}" enctype="multipart/form-data" method="POST" id="newFile">
@csrf
<div class="form-group">
<form action="{{route('uploadTeamFile')}}" enctype="multipart/form-data" method="POST" id="newFile">
@csrf
<div class="form-group">
<label for="caption">Caption</label>
<input id="caption" type="text" class="form-control" name="caption" required>
<label for="caption">Caption</label>
<input id="caption" type="text" class="form-control" name="caption" required>
<label for="description">File description (optional)</label>
<textarea rows="5" name="description" id="description" class="form-control"></textarea>
<label for="description">File description (optional)</label>
<textarea rows="5" name="description" id="description" class="form-control"></textarea>
</div>
</div>
<label class="btn btn-primary" for="file-selector">
<input id="file-selector" name="file" type="file" style="display:none"
onchange="$('#upload-file-info').html(this.files[0].name)">
Choose File (max {{ini_get('post_max_size')}})
</label>
<span class='label label-info' id="upload-file-info"></span>
<label class="btn btn-primary" for="file-selector">
<input id="file-selector" name="file" type="file" style="display:none"
onchange="$('#upload-file-info').html(this.files[0].name)">
Choose File (max {{ini_get('post_max_size')}})
</label>
<span class='label label-info' id="upload-file-info"></span>
</form>
</form>
<x-slot name="modalFooter">
<button onclick="$('#newFile').submit()" type="button" class="btn btn-warning" rel="buttonTxtTooltip" title="Upload chosen file" data-placement="top"><i class="fas fa-upload"></i></button>
</x-slot>
</x-modal>
<x-slot name="modalFooter">
<button onclick="$('#newFile').submit()" type="button" class="btn btn-warning" rel="buttonTxtTooltip" title="Upload chosen file" data-placement="top"><i class="fas fa-upload"></i></button>
</x-slot>
</x-modal>
@endif
<div class="row">
<div class="col-3 offset-3">
<div class="col-3 offset-4">
<img src="/img/files.svg" width="230px" height="230px" alt="Team files illustration">
</div>
</div>
@if($demoActive)
<div class="row">
<div class="col">
<div class="alert alert-warning">
<p class="text-bold"><i class="fa fa-info-circle"></i> Warning</p>
<p>Since many users may use the app at any given time, file uploads are disabled whilst demo mode is on.</p>
</div>
</div>
</div>
@endif
<div class="row">
<div class="col">
@@ -119,7 +132,7 @@
</div>
<div class="card-footer text-center">
<button type="button" class="btn btn-warning ml-3" onclick="$('#upload-dropzone').modal('show')"><i class="fas fa-upload"></i> Upload Files</button>
<button {{ ($demoActive) ? 'disabled' : '' }} type="button" class="btn btn-warning ml-3" onclick="$('#upload-dropzone').modal('show')"><i class="fas fa-upload"></i> Upload Files</button>
<button type="button" class="btn btn-success ml-3" onclick="window.location.href='{{route('teams.index')}}'"><i class="fas fa-arrow-circle-left"></i> Back</button>
{{ $files->links() }}
</div>

View File

@@ -43,6 +43,12 @@
<form id="banAccountForm" name="banAccount" method="POST" action="{{route('banUser', ['user' => $profile->user->id])}}">
@csrf
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<div class="row">
<div class="col">
@@ -69,7 +75,7 @@
</form>
<x-slot name="modalFooter">
<button id="banAccountButton" type="button" class="btn btn-danger"><i class="fa fa-gavel"></i> {{__('Confirm')}}</button>
<button id="banAccountButton" type="button" class="btn btn-danger" {{ ($demoActive) ? 'disabled' : '' }} ><i class="fa fa-gavel"></i> {{__('Confirm')}}</button>
</x-slot>
</x-modal>
@@ -77,6 +83,12 @@
@if (!Auth::user()->is($profile->user) && $profile->user->isStaffMember())
<x-modal id="terminateUser" modal-label="terminateUser" modal-title="{{__('messages.reusable.confirm')}}" include-close-button="true">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<p><i class="fa fa-exclamation-triangle"></i> <b>{{__('messages.profile.terminate_notice')}}</b></p>
<p>
{{__('messages.profile.terminate_notice_warning')}}
@@ -91,7 +103,7 @@
<form method="POST" action="{{route('terminateStaffMember', ['user' => $profile->user->id])}}" id="terminateUserForm">
@csrf
@method('PATCH')
<button type="submit" class="btn btn-warning"><i class="fas fa-exclamation-circle"></i> {{__('messages.reusable.confirm')}}</button>
<button type="submit" class="btn btn-warning" {{ ($demoActive) ? 'disabled' : '' }}><i class="fas fa-exclamation-circle"></i> {{__('messages.reusable.confirm')}}</button>
</form>
@@ -102,6 +114,12 @@
<x-modal id="deleteAccount" modal-label="deleteAccount" modal-title="{{__('messages.reusable.confirm')}}" include-close-button="true">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<p><i class="fa fa-exclamation-triangle"></i><b> {{__('messages.profile.delete_acc_warn')}}</b></p>
<p>{{__('messages.profile.delete_acc_consequence')}}</p>
@@ -118,12 +136,12 @@
<x-slot name="modalFooter">
<button type="button" class="btn btn-danger" onclick="document.getElementById('deleteAccountForm').submit()"><i class="fa fa-trash"></i> {{strtoupper(__('messages.reusable.confirm'))}}</button>
<button type="button" class="btn btn-danger" {{ ($demoActive) ? 'disabled' : '' }} onclick="document.getElementById('deleteAccountForm').submit()"><i class="fa fa-trash"></i> {{strtoupper(__('messages.reusable.confirm'))}}</button>
</x-slot>
</x-modal>
<x-modal id="ipInfo" modal-label="ipInfo" modal-title="{{__('messages.reusable.ip_info')}} {{$ipInfo->ip ?? 'Unknown'}}" include-close-button="true">
<x-modal id="ipInfo" modal-label="ipInfo" modal-title="{{__('IP Address Information')}}" include-close-button="true">
<h4 class="text-center">{{__('messages.profile.search_result')}}</h3>
@@ -209,18 +227,24 @@
<x-modal id="editUser" modal-label="editUser" modal-title="{{__('messages.profile.edituser')}}" include-close-button="true">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<form id="updateUserForm" method="post" action="{{ route('updateUser', ['user' => $profile->user->id]) }}">
@csrf
@method('PATCH')
<label for="email">{{__('messages.contactlabel_email')}}</label>
<input id="email" type="text" name="email" class="form-control" required value="{{ $profile->user->email }}" />
<input {{ ($demoActive) ? 'disabled' : '' }} id="email" type="text" name="email" class="form-control" required value="{{ $profile->user->email }}" />
<label for="name">{{__('messages.contactlabel_name')}}</label>
<input id="name" type="text" name="name" class="form-control" required value="{{ $profile->user->name }}" />
<input {{ ($demoActive) ? 'disabled' : '' }} id="name" type="text" name="name" class="form-control" required value="{{ $profile->user->name }}" />
<label for="uuid">Mojang UUID</label>
<input id="uuid" type="text" name="uuid" class="form-control" required value="{{ $profile->user->uuid }}" />
<input {{ ($demoActive) ? 'disabled' : '' }} id="uuid" type="text" name="uuid" class="form-control" required value="{{ $profile->user->uuid }}" />
<p class="text-muted text-sm">
<i class="fas fa-exclamation-triangle"></i> {{__('messages.profile.edituser_consequence')}}
</p>
@@ -233,7 +257,7 @@
@foreach($roles as $roleName => $status)
<tr>
<th><input type="checkbox" name="roles[]" value="{{ $roleName }}" {{ ($status) ? 'checked' : '' }}></th>
<th><input {{ ($demoActive) ? 'disabled' : '' }} type="checkbox" name="roles[]" value="{{ $roleName }}" {{ ($status) ? 'checked' : '' }}></th>
<td class="col-md-2">{{ ucfirst($roleName) }}</td>
</tr>
@@ -250,7 +274,7 @@
<x-slot name="modalFooter">
<button type="button" class="btn btn-warning" onclick="$('#updateUserForm').submit()"><i class="fa fa-exclamation-cicle"></i> {{__('messages.vacancy.save')}}</button>
<button type="button" {{ ($demoActive) ? 'disabled' : '' }} class="btn btn-warning" onclick="$('#updateUserForm').submit()"><i class="fa fa-exclamation-cicle"></i> {{__('messages.vacancy.save')}}</button>
</x-slot>
@@ -293,7 +317,7 @@
<p class="text-muted">{{$profile->profileShortBio}}</p>
<p class="text-muted">{{__('messages.reusable.member_since', ['date' => $since])}}</p>
@if (Auth::user()->hasRole('admin'))
<button type="button" class="btn btn-sm btn-info" onclick="$('#ipInfo').modal('show')">{{__('messages.reusable.lookup', ['ipAddress' => $profile->user->originalIP])}}</button>
<button type="button" class="btn btn-sm btn-info" onclick="$('#ipInfo').modal('show')">{{__('messages.reusable.lookup', ['ipAddress' => (!$demoActive) ? $profile->user->originalIP : '0.0.0.0'])}}</button>
@endif
@if ($profile->user->is(Auth::user()))

View File

@@ -22,6 +22,14 @@
<x-modal id="deleteAccountModal" modal-label="deleteAccountModalLabel" modal-title="Close account" include-close-button="true">
@if ($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fas fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<p>Deleting your account is an irreversible process. The following data will be deleted (including personally identifiable data):</p>
<ul>
<li>Last IP address</li>
@@ -66,7 +74,7 @@
<x-slot name="modalFooter">
<button onclick="$('#deleteAccountForm').submit()" type="button" class="btn btn-warning"><i class="fas fa-exclamation-triangle"></i> Continue</button>
<button {{ ($demoActive) ? 'disabled' : '' }} onclick="$('#deleteAccountForm').submit()" type="button" class="btn btn-warning"><i class="fas fa-exclamation-triangle"></i> Continue</button>
</x-slot>
@@ -74,10 +82,16 @@
@if (!Auth::user()->has2FA())
<x-modal id="twoFactorAuthModal" modal-label="2faLabel" modal-title="{{__('messages.2fa_txt')}}" include-close-button="true">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fa fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<h3><i class="fas fa-user-shield"></i> {{__('messages.profile.2fa_welcome')}}</h3>
<p><b>{{__('messages.profile.supported_apps')}}</b></p>
@@ -118,7 +132,7 @@
<x-slot name="modalFooter">
<button type="button" class="btn btn-success" onclick="$('#enable2Fa').submit()"><i class="fas fa-key"></i> {{__('messages.profile.2fa_enable')}}</button>
<button {{ ($demoActive) ? 'disabled' : '' }} type="button" class="btn btn-success" onclick="$('#enable2Fa').submit()"><i class="fas fa-key"></i> {{__('messages.profile.2fa_enable')}}</button>
</x-slot>
@@ -248,6 +262,12 @@
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active p-3" id="accountSecurity" role="tabpanel" aria-labelledby="accountSecurityTab">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fa fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<h5 class="card-title">{{__('messages.profile.change_password')}}</h5>
<p class="card-text">{{__('messages.profile.change_password_exp')}}</p>
@@ -271,7 +291,7 @@
</form>
<button class="btn btn-success" type="button" onclick="document.getElementById('changePassword').submit()">{{__('messages.profile.change_password')}}</button>
<button {{ ($demoActive) ? 'disabled' : '' }} class="btn btn-success" type="button" onclick="document.getElementById('changePassword').submit()">{{__('messages.profile.change_password')}}</button>
</div>
<div class="tab-pane fade p-3" id="twofa" role="tabpanel" aria-labelledby="twofaTab">
<h5 class="card-title">{{__('messages.profile.2fa')}}</h5>
@@ -289,10 +309,15 @@
<div class="tab-pane fade p-3" id="sessions" role="tabpanel" aria-labelledby="sessionsTab">
<h5 class="card-title">{{__('messages.profile.session_manager')}}</h5>
<p class="card-text">{{__('messages.profile.terminate_others')}}</p>
<p>{{__('messages.profile.current_session', ['ipAddress' => $ip])}}</p>
<p>{{__('messages.profile.current_session', ['ipAddress' => ($demoActive) ? '0.0.0.0 (censored)' : $ip])}}</p>
<button type="button" class="btn btn-warning" onclick="$('#authenticationForm').modal('show')">{{__('messages.profile.flush_session')}}</button>
</div>
<div class="tab-pane fade p-3" id="contactSettings" role="tabpanel" aria-labelledby="contactSettingsTab">
@if($demoActive)
<div class="alert alert-danger">
<p class="font-weight-bold"><i class="fa fa-exclamation-triangle"></i> This feature is disabled</p>
</div>
@endif
<h5 class="card-title">{{__('messages.profile.contact_settings')}}</h5>
<p class="card-text">{{__('messages.profile.personal_data_change')}}</p>
@@ -320,7 +345,7 @@
</div>
</form>
<button class="btn btn-success" type="button" onclick="document.getElementById('changeEmail').submit()">{{__('messages.profile.change_email')}}</button>
<button {{ ($demoActive) ? 'disabled' : '' }} class="btn btn-success" type="button" onclick="document.getElementById('changeEmail').submit()">{{__('messages.profile.change_email')}}</button>
</div>

View File

@@ -103,7 +103,7 @@
<div class="mt-4 mb-3">
<h5>{{$content['title']}}</h5>
<p>{!! GrahamCampbell\Markdown\Facades\Markdown::convertToHtml($content['response']) !!}</p>
</div>
@@ -132,7 +132,7 @@
<p><b>{{__('messages.application_m.applicant_name')}} </b> <span class="badge badge-primary">{{$application->user->name}}</span></p>
@if (Auth::user()->hasRole('hiringManager'))
<p><b>{{__('messages.view_app.appl_ip')}}</b> <span class="badge badge-primary">{{$application->user->originalIP}}</span></p>
<p><b>{{__('messages.view_app.appl_ip')}}</b> <span class="badge badge-primary">{{ ($demoActive) ? '0.0.0.0 (censored)' : $application->user->originalIP }}</span></p>
@endif
<p><b>{{__('messages.application_m.application_date')}}</b> <span class="badge badge-primary">{{$application->created_at}}</span></p>
<p><b>{{__('messages.last_updated')}}</b><span class="badge badge-primary">{{$application->updated_at}}</span></p>

View File

@@ -41,6 +41,19 @@
<div class="container-fluid">
@if ($demoActive)
<div class="row">
<div class="col">
<div class="alert alert-warning">
<p class="font-weight-bold"><i class="fas fa-exclamation-circle"></i> Attention</p>
<p>Demo mode is active on this instance. The database is refreshed daily and some features are disabled for security reasons.</p>
<p>If you're seeing this message in error, please contact your system administrator.</p>
</div>
</div>
</div>
@endif
<div class="row">
<div class="col text-center">