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

@@ -20,6 +20,6 @@ class ApiKey extends Model
public function user()
{
return $this->belongsTo('App\User', 'id');
return $this->belongsTo('App\User', 'owner_user_id', 'id');
}
}

View File

@@ -38,13 +38,18 @@ class IP
'ip' => $IP,
];
// TODO: Maybe unwrap this? Methods are chained here
return json_decode(Cache::remember($IP, 3600, function () use ($IP) {
return Http::get(config('general.urls.ipapi.ipcheck'), [
'apiKey' => config('general.keys.ipapi.apikey'),
'ip' => $IP,
])->body();
}));
if (!config('demo.is_enabled')) {
return json_decode(Cache::remember($IP, 3600, function () use ($IP) {
return Http::get(config('general.urls.ipapi.ipcheck'), [
'apiKey' => config('general.keys.ipapi.apikey'),
'ip' => $IP,
])->body();
}));
}
return new class {
public $message = "This feature is disabled.";
};
}
}

View File

@@ -22,6 +22,7 @@
namespace App\Http\Controllers;
use App\Application;
use App\Exceptions\ApplicationNotFoundException;
use App\Exceptions\IncompleteApplicationException;
use App\Exceptions\UnavailableApplicationException;
use App\Exceptions\VacancyNotFoundException;
@@ -74,14 +75,22 @@ class ApplicationController extends Controller
{
$this->authorize('viewAny', Application::class);
return view('dashboard.appmanagement.all');
return view('dashboard.appmanagement.all')
->with('applications', Application::all());
}
public function renderApplicationForm($vacancySlug)
{
return $this->applicationService->renderForm($vacancySlug);
try {
return $this->applicationService->renderForm($vacancySlug);
}
catch (ApplicationNotFoundException $ex) {
return redirect()
->back()
->with('error', $ex->getMessage());
}
}
public function saveApplicationAnswers(Request $request, $vacancySlug)
@@ -98,7 +107,7 @@ class ApplicationController extends Controller
}
return redirect()
->back()
->to(route('showUserApps'))
->with('success', __('Thank you! Your application has been processed and our team will get to it shortly.'));
}

View File

@@ -92,7 +92,7 @@ class RegisterController extends Controller
case 'low':
$password = ['required', 'string', 'min:10', 'confirmed'];
break;
case 'medium':
$password = ['required', 'string', 'confirmed', 'regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[#?!@$%^&*-]).{12,}$/'];
break;
@@ -124,11 +124,11 @@ class RegisterController extends Controller
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'originalIP' => request()->ip(),
'originalIP' => config('demo.is_enabled') ? '0.0.0.0' : request()->ip(),
]);
// It's not the registration controller's concern to create a profile for the user,
// so this code has been moved to it's respective observer, following the separation of concerns pattern.
// so this code has been moved to its respective observer, following the separation of concerns pattern.
$user->assignRole('user');

View File

@@ -42,6 +42,12 @@ class BanController extends Controller
public function insert(BanUserRequest $request, User $user)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$this->authorize('create', [Ban::class, $user]);
@@ -60,6 +66,12 @@ class BanController extends Controller
public function delete(Request $request, User $user)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$this->authorize('delete', $user->bans);
if ($this->suspensionService->isSuspended($user)) {

View File

@@ -24,6 +24,7 @@ namespace App\Http\Controllers;
use App\Application;
use App\User;
use App\Vacancy;
use Illuminate\Support\Facades\Auth;
class DashboardController extends Controller
{
@@ -34,14 +35,27 @@ class DashboardController extends Controller
$totalPeerReview = Application::where('applicationStatus', 'STAGE_PEERAPPROVAL')->get()->count();
$totalNewApplications = Application::where('applicationStatus', 'STAGE_SUBMITTED')->get()->count();
$totalDenied = Application::where('applicationStatus', 'DENIED')->get()->count();
$vacancies = Vacancy::where('vacancyStatus', '<>', 'CLOSED')->get();
$totalDeniedSingle = Application::where([
['applicationStatus', '=', 'DENIED'],
['applicantUserID', '=', Auth::user()->id]
])->get();
$totalNewSingle = Application::where([
['applicationStatus', '=', 'STAGE_SUBMITTED'],
['applicantUserID', '=', Auth::user()->id]
])->get();
return view('dashboard.dashboard')
->with([
'vacancies' => Vacancy::all(),
'vacancies' => $vacancies,
'totalUserCount' => User::all()->count(),
'totalDenied' => $totalDenied,
'totalPeerReview' => $totalPeerReview,
'totalNewApplications' => $totalNewApplications,
'totalNewSingle' => $totalNewSingle->count(),
'totalDeniedSingle' => $totalDeniedSingle->count()
]);
}
}

View File

@@ -21,6 +21,7 @@
namespace App\Http\Controllers;
use App\Exceptions\EmptyFormException;
use App\Exceptions\FormHasConstraintsException;
use App\Form;
use App\Services\FormManagementService;
@@ -53,7 +54,15 @@ class FormController extends Controller
public function saveForm(Request $request)
{
$form = $this->formService->addForm($request->all());
try {
$form = $this->formService->addForm($request->all());
}
catch (EmptyFormException $ex)
{
return redirect()
->back()
->with('exception', $ex->getMessage());
}
// Form is boolean or array
if ($form)

View File

@@ -62,6 +62,13 @@ class TeamFileController extends Controller
{
$this->authorize('store', TeamFile::class);
if (config('demo.is_enabled'))
{
return redirect()
->back()
->with('error', 'This feature is disabled');
}
try {
$caption = $request->caption;
$description = $request->description;
@@ -110,6 +117,13 @@ class TeamFileController extends Controller
{
$this->authorize('delete', $teamFile);
if (config('demo.is_enabled'))
{
return redirect()
->back()
->with('error', 'This feature is disabled');
}
try
{
Storage::delete($teamFile->fs_location);

View File

@@ -32,6 +32,7 @@ use App\Http\Requests\SearchPlayerRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Notifications\ChangedPassword;
use App\Notifications\EmailChanged;
use App\Traits\DisablesFeatures;
use App\Traits\ReceivesAccountTokens;
use App\User;
use Google2FA;
@@ -168,6 +169,11 @@ class UserController extends Controller
public function changePassword(ChangePasswordRequest $request)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$user = User::find(Auth::user()->id);
if (! is_null($user)) {
@@ -191,6 +197,12 @@ class UserController extends Controller
public function changeEmail(ChangeEmailRequest $request)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$user = User::find(Auth::user()->id);
if (! is_null($user)) {
@@ -214,6 +226,12 @@ class UserController extends Controller
public function delete(DeleteUserRequest $request, User $user)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$this->authorize('delete', $user);
if ($request->confirmPrompt == 'DELETE ACCOUNT') {
@@ -228,6 +246,11 @@ class UserController extends Controller
public function update(UpdateUserRequest $request, User $user)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$this->authorize('adminEdit', $user);
// Mass update would not be possible here without extra code, making route model binding useless
@@ -262,6 +285,12 @@ class UserController extends Controller
public function add2FASecret(Add2FASecretRequest $request)
{
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
$currentSecret = $request->session()->get('current2FA');
$isValid = Google2FA::verifyKey($currentSecret, $request->otp);
@@ -314,6 +343,11 @@ class UserController extends Controller
public function terminate(Request $request, User $user)
{
$this->authorize('terminate', User::class);
if (config('demo.is_enabled')) {
return redirect()
->back()
->with('error', 'This feature is disabled');
}
// TODO: move logic to policy
if (! $user->isStaffMember() || $user->is(Auth::user())) {

View File

@@ -27,6 +27,7 @@ use App\Observers\UserObserver;
use App\User;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Sentry;
@@ -67,5 +68,7 @@ class AppServiceProvider extends ServiceProvider
$https = true;
$this->app['request']->server->set('HTTPS', $https);
View::share('demoActive', config('demo.is_enabled'));
}
}

View File

@@ -47,7 +47,7 @@ class ApplicationService
* @throws VacancyNotFoundException Thrown when the associated vacancy is not found
* @throws IncompleteApplicationException Thrown when there are missing fields
*/
public function fillForm(Authenticatable $applicant, array $formData, $vacancySlug): bool
public function fillForm(User $applicant, array $formData, $vacancySlug): bool
{
$vacancy = Vacancy::with('forms')->where('vacancySlug', $vacancySlug)->get();

View File

@@ -56,12 +56,7 @@ class AppointmentService
*/
public function updateAppointment(Application $application, $status, $updateApplication = true)
{
$validStatuses = [
'SCHEDULED',
'CONCLUDED',
];
if ($status == 'SCHEDULED' || $status == 'CONCLUDED')
if ($status == 'SCHEDULED' || $status == 'concluded')
{
$application->appointment->appointmentStatus = strtoupper($status);
$application->appointment->save();

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Services;
class DemoService {
public function isDemoEnabled(): bool {
return config('demo.is_enabled');
}
}

View File

@@ -43,7 +43,7 @@ class SecuritySettingsService
}
Options::changeOption('graceperiod', $options['graceperiod']);
Options::changeOption('password_expiry', $options['pwexpiry']);
Options::changeOption('password_expiry', $options['pwExpiry']);
Options::changeOption('force2fa', $options['enforce2fa']);
Options::changeOption('requireGameLicense', $options['requirePMC']);

View File

@@ -33,6 +33,13 @@ trait ReceivesAccountTokens
{
public function userDelete(UserDeleteRequest $request)
{
if (config('demo.is_enabled'))
{
return redirect()
->back()
->with('error', 'This feature is disabled');
}
// a little verbose
$user = User::find(Auth::user()->id);
$tokens = $user->generateAccountTokens();
@@ -49,6 +56,13 @@ trait ReceivesAccountTokens
public function processDeleteConfirmation(Request $request, $ID, $action, $token)
{
if (config('demo.is_enabled'))
{
return redirect()
->back()
->with('error', 'This feature is disabled');
}
// We can't rely on Laravel's route model injection, because it'll ignore soft-deleted models,
// so we have to use a special scope to find them ourselves.
$user = User::withTrashed()->findOrFail($ID);