Skip to content
14 changes: 12 additions & 2 deletions app/Audit.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

class Audit extends Model {
protected $table = 'audits';
protected $fillable = ['id', 'cid', 'ip', 'what', 'created_at', 'updated_at'];

public function getTimeDateAttribute() {
$date = $this->created_at;
Expand All @@ -17,10 +16,21 @@ public function getTimeDateAttribute() {
}

public static function newAudit(string $message): void {
$impersonated_by_id = null;
$impersonation_string = '';
if (session()->has('impersonating_user')) {
$impersonated_by_id = session('impersonating_user');
$impersonation_user = User::find($impersonated_by_id);

$impersonation_string = 'IMPERSONATED BY ' . (is_null($impersonation_user) ? 'UNKNOWN' : $impersonation_user->full_name) . ': ';
}
$impersonated_by_id = session()->has('impersonating_user') ? session('impersonating_user') : null;

$audit = new Audit;
$audit->cid = Auth::id();
$audit->impersonated_by_id = $impersonated_by_id;
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' ' . $message;
$audit->what = $impersonation_string . Auth::user()->full_name . ' ' . $message;
$audit->save();
}
}
270 changes: 45 additions & 225 deletions app/Http/Controllers/AdminDash.php

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions app/Http/Controllers/ImpersonationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace App\Http\Controllers;

use App\Audit;
use App\User;
use Illuminate\Http\Request;

class ImpersonationController extends Controller {
public function start(Request $request) {
$user = User::find($request->user_id);
if (is_null($user)) {
return redirect()->back()->with('error', 'That user does not exist');
}

session()->put('impersonate', $user->id);

Audit::newAudit('started impersonating user ' . $user->impersonation_name . '.');
return redirect('/dashboard')->with('warning', 'Successfully started impersonationg ' . $user->full_name . '. CAUTION: Impersonating actively logs you into the user\'s REAL account. Changes made while impersonating will be reflected on the user\'s actual account. PROCEED WITH CARE.');
}

public function stop() {
Audit::newAudit('impersonation session ending...');

session()->forget('impersonate');
session()->forget('impersonating_user');

return redirect('/dashboard');
}
}
13 changes: 2 additions & 11 deletions app/Http/Controllers/MerchStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use App\Audit;
use App\Merch;
use Auth;
use Carbon\Carbon;
use Config;
use Illuminate\Http\Request;
Expand Down Expand Up @@ -60,11 +59,7 @@ public function saveItem(Request $request, $id = null) {
$store_item->flag = $request->input('flag');
$store_item->save();

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name.' modified a store item.';
$audit->save();
Audit::newAudit(' modified a store item.');

return redirect('/dashboard/admin/store')->with('success', 'Store item modified successfully.');
}
Expand All @@ -73,11 +68,7 @@ public function deleteItem($id) {
$store_item = Merch::find($id);
$store_item->delete();

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name.' removed a store item.';
$audit->save();
Audit::newAudit(' removed a store item.');

return redirect('/dashboard/admin/store')->with('success', 'Store item deleted successfully.');
}
Expand Down
50 changes: 13 additions & 37 deletions app/Http/Controllers/TrainingDash.php
Original file line number Diff line number Diff line change
Expand Up @@ -470,11 +470,7 @@ public function deleteTicket($id) {
$ticket->delete();

if (! $draft) {
$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' deleted a training ticket for ' . User::find($controller_id)->full_name . '.';
$audit->save();
Audit::newAudit(' deleted a training ticket for ' . User::find($controller_id)->full_name . '.');
}

return redirect('/dashboard/training/tickets?id=' . $controller_id)->with('success', 'The ticket has been deleted successfully.');
Expand All @@ -499,11 +495,7 @@ public function acceptRecommendation($id) {
$ots->ins_id = Auth::id();
$ots->save();

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' accepted an OTS for ' . User::find($ots->controller_id)->full_name . '.';
$audit->save();
Audit::newAudit(' accepted an OTS for ' . User::find($ots->controller_id)->full_name . '.');

return redirect()->back()->with('success', 'You have sucessfully accepted this OTS. Please email the controller at ' . User::find($ots->controller_id)->email . ' in order to schedule the OTS.');
}
Expand Down Expand Up @@ -533,11 +525,7 @@ public function assignRecommendation(Request $request, $id) {

Mail::to($ins->email)->cc('training@ztlartcc.org')->send(new OtsAssignment($ots, $controller, $ins));

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' assigned an OTS for ' . User::find($ots->controller_id)->full_name . ' to ' . User::find($ots->ins_id)->full_name . '.';
$audit->save();
Audit::newAudit(' assigned an OTS for ' . User::find($ots->controller_id)->full_name . ' to ' . User::find($ots->ins_id)->full_name . '.');

return redirect()->back()->with('success', 'The OTS has been assigned successfully and the instructor has been notified.');
}
Expand All @@ -554,11 +542,7 @@ public function completeOTS(Request $request, $id) {
$ots->status = $request->result;
$ots->save();

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' updated an OTS for ' . User::find($ots->controller_id)->full_name . '.';
$audit->save();
Audit::newAudit(' updated an OTS for ' . User::find($ots->controller_id)->full_name . '.');

return redirect()->back()->with('success', 'The OTS has been updated successfully!');
} else {
Expand All @@ -572,11 +556,7 @@ public function otsCancel($id) {
$ots->status = 0;
$ots->save();

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' cancelled an OTS for ' . User::find($ots->controller_id)->full_name . '.';
$audit->save();
Audit::newAudit(' cancelled an OTS for ' . User::find($ots->controller_id)->full_name . '.');

return redirect()->back()->with('success', 'The OTS has been unassigned from you and cancelled successfully.');
}
Expand Down Expand Up @@ -943,14 +923,12 @@ private function saveNewTicket(Request $request, $id) {
$student->save();
}

$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' added a training ticket for ' . User::find($ticket->controller_id)->full_name . '.';

$audit_msg = ' added a training ticket for ' . User::find($ticket->controller_id)->full_name . '.';
if ($promotion) {
$audit->what .= ' A promotion was pushed to VATUSA.';
$audit_msg .= ' A promotion was pushed to VATUSA.';
}
$audit->save();
Audit::newAudit($audit_msg);

return redirect('/dashboard/training/tickets?id=' . $ticket->controller_id)->with('success', 'The training ticket has been submitted successfully' . $extra . '.');
}
Expand Down Expand Up @@ -1045,14 +1023,12 @@ private function saveTicket(Request $request, $id) {
$student->rating_id = 2; // Needed to prevent data discontinuity
$student->save();
}
$audit = new Audit;
$audit->cid = Auth::id();
$audit->ip = $_SERVER['REMOTE_ADDR'];
$audit->what = Auth::user()->full_name . ' edited a training ticket for ' . User::find($request->controller)->full_name . '.';

$audit_msg = ' edited a training ticket for ' . User::find($request->controller)->full_name . '.';
if ($promotion) {
$audit->what .= ' A promotion was pushed to VATUSA.';
$audit_msg .= ' A promotion was pushed to VATUSA.';
}
$audit->save();
Audit::newAudit($audit_msg);

return redirect('/dashboard/training/tickets/view/' . $ticket->id)->with('success', 'The ticket has been updated successfully' . $extra . '.');
} else {
Expand Down
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Kernel extends HttpKernel {
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\Impersonation::class,
],

'api' => [
Expand Down
24 changes: 24 additions & 0 deletions app/Http/Middleware/Impersonation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Http\Middleware;

use Auth;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class Impersonation {
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response {
if (toggleEnabled('impersonation') && session()->has('impersonate') && Auth::user()->isAbleTo('snrStaff')) {
session()->put('impersonating_user', Auth::id());
Auth::onceUsingId(session('impersonate'));
}

return $next($request);
}
}
4 changes: 4 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace App\Providers;

use App\View\Composers\ImpersonationComposer;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;

Expand All @@ -24,6 +26,8 @@ public function boot(): void {
return toggleEnabled($toggle_name);
});

View::composer('inc.dashboard_head', ImpersonationComposer::class);

/**
* Paginate a standard Laravel Collection.
*
Expand Down
16 changes: 16 additions & 0 deletions app/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ public function getFullNameRatingAttribute() {
return $this->full_name . ' - ' . $this->rating_short;
}

public function getImpersonationNameAttribute() {
$roles = array_reduce($this->roles->toArray(), function ($role_string, $role) {
return $role_string . $role['name'] . ', ';
}, '');

if ($this->visitor) {
$roles = 'visitor';
}

if ($roles != '') {
$roles = ' (' . trim($roles, ', ') . ')';
}

return $this->backwards_name . ' ' . $this->id . ' - ' . $this->rating_short . $roles;
}

public static $RatingShort = [
0 => 'N/A',
1 => 'OBS', 2 => 'S1',
Expand Down
32 changes: 32 additions & 0 deletions app/View/Composers/ImpersonationComposer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\View\Composers;

use App\User;
use Auth;
use Illuminate\View\View;

class ImpersonationComposer {
/**
* Create a new profile composer.
*/
public function __construct(
) {
}

/**
* Bind data to the view.
*/
public function compose(View $view): void {
if (toggleEnabled('impersonation')) {
$users = null;
$is_impersonating = session()->has('impersonate');

if (Auth::user()->isAbleTo('snrStaff')) {
$users = User::where('status', 1)->orderBy('lname', 'ASC')->get()->pluck('impersonation_name', 'id');
}

$view->with('users', $users)->with('is_impersonating', $is_impersonating);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void {
Schema::table('audits', function ($table) {
$table->integer('impersonated_by_id')->nullable();

$table->foreign('impersonated_by_id')->references('id')->on('roster')->nullOnDelete();
});
}

/**
* Reverse the migrations.
*/
public function down(): void {
Schema::table('audits', function ($table) {
$table->dropColumn('impersonated_by_id');
});
}
};
46 changes: 25 additions & 21 deletions resources/views/inc/dashboard_head.blade.php
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container-fluid">
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container-fluid">
<a class="navbar-brand" href="/dashboard">
@include('inc.logo', ['color' => 'black'])
</a>
<div class="d-flex justify-content-start ms-5 collapse navbar-collapse">

{{ html()->form()->route('searchAirport')->class(['row','row-cols-lg-auto'])->open() }}
<div class="col-12 input-group">
{{ html()->text('apt', null)->placeholder('Search Airport ICAO')->class(['form-control']) }}
&nbsp;
<button class="btn btn-success" type="submit">Search</button>
</div>
<ul class="navbar-nav me-auto align-items-center">
{{ html()->form()->route('searchAirport')->class(['form-inline'])->open() }}
<div class="col-12 input-group">
{{ html()->text('apt', null)->placeholder('Search Airport ICAO')->class(['form-control']) }}
&nbsp;
<button class="btn btn-success" type="submit">Search</button>
</div>
{{ html()->form()->close() }}
</ul>
<ul class="navbar-nav ml-auto align-items-center">
<a class="nav-link {{ Nav::isRoute('controller_dash_home') }}" href="/dashboard">Dashboard Home</a>
@if(toggleEnabled('impersonation') && $is_impersonating)
<a class="nav-link" href="/dashboard/admin/impersonation/stop">End Impersonation</a>
@endif
@if(toggleEnabled('impersonation') && Auth::user()->isAbleTo('snrStaff'))
{{ html()->form()->route('startImpersonation')->class(['form-inline'])->open() }}
{{ html()->select('user_id', $users, Auth::id())->class(['form-select'])->attributes(['onchange' => 'this.form.submit()'])->disabled($is_impersonating) }}
{{ html()->form()->close() }}
</div>

<ul class="navbar-nav ms-auto">
<a class="nav-link {{ Nav::isRoute('controller_dash_home') }}" href="/dashboard">Dashboard Home</a>
<li class="nav-item dropdown">
<a class="nav-link" style="pointer-events:none">{{ Auth::user()->full_name }} - {{ Auth::user()->rating_short }}</a>
</li>
</ul>
</div>
</div>
</nav>
@else
<a class="nav-link disabled">{{ Auth::user()->full_name }} - {{ Auth::user()->rating_short }}</a>
@endif
</ul>
</div>
</nav>

Loading