This commit is contained in:
Masroor Ehsan 2024-12-30 21:22:15 +06:00
parent 0c2dcc62cb
commit 105bea6e15
9 changed files with 171 additions and 21 deletions

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Guest;
use App\Http\Controllers\HashidControllerBase;
use App\Models\SharedStudy;
class ViewSharedStudyController extends HashidControllerBase
{
public function show()
{
$this->decodeKeys();
$share = SharedStudy::findOrFail($this->key);
abort_if($share->hasExpired(), 404);
if ($share->isPasswordProtected()) {
return view('guest.shared-study.auth', compact('share'));
}
return view('guest.shared-study.show', compact('share'));
}
public function auth(SharedStudyPasswordRequest $request)
{
$this->decodeKeys();
$share = SharedStudy::findOrFail($this->key);
abort_if(! $share->attempt($request->password), 403);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers;
use Throwable;
use function Sentry\captureException;
abstract class HashidActionControllerBase extends Controller
{
protected ?int $key = null;
protected ?string $hashid = null;
public function __invoke()
{
$this->hashid = request('hashid');
try {
$this->key = unhash_it($this->hashid);
} catch (Throwable $exception) {
captureException($exception);
abort(404);
}
return $this->handle();
}
abstract protected function handle();
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Requests\Guest;
use Illuminate\Foundation\Http\FormRequest;
class SharedStudyPasswordRequest extends FormRequest
{
public function rules(): array
{
return [
'password' => 'required|string|min:4',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@ -29,4 +29,27 @@ protected function casts(): array
'access_flags' => StudyAccessFlags::class, 'access_flags' => StudyAccessFlags::class,
]; ];
} }
public function isPasswordProtected(): bool
{
return ! blank($this->access_password);
}
public function attempt(string $password): bool
{
if (! $this->isPasswordProtected()) {
return true;
}
return strcmp($this->access_password, $password) === 0;
}
public function hasExpired(): bool
{
if (blank($this->expires_at)) {
return false;
}
return $this->expires_at->isPast();
}
} }

View File

@ -1,7 +1,7 @@
<?php <?php
if (! function_exists('hash_it')) { if (! function_exists('_h')) {
function hash_it(int $key): string function _h(int $key): string
{ {
return Hashids::encode($key); return Hashids::encode($key);
} }

View File

@ -12,17 +12,50 @@
<table class="min-w-full divide-y divide-gray-200"> <table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50"> <thead class="bg-gray-50">
<tr> <tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Accession Number</th> <th scope="col"
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Patient ID</th> class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Patient Name</th> Accession Number
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Patient Sex</th> </th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Patient Birth Date</th> <th scope="col"
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Modality</th> class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Study Date</th> Patient ID
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Receive Date</th> </th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Series</th> <th scope="col"
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Institute Name</th> class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">&nbsp;</th> Patient Name
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Patient Sex
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Patient Birth Date
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Modality
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Study
Date
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Receive Date
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Series
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Institute Name
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
&nbsp;
</th>
</tr> </tr>
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody class="bg-white divide-y divide-gray-200">
@ -30,29 +63,38 @@
<tr> <tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->accession_number }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->accession_number }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_id }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_id }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"><a href="{{ route('studies.details', hash_it($study->id)) }}">{{ $study->patient_name }}</a></td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"><a
href="{{ route('studies.details', _h($study->id)) }}">{{ $study->patient_name }}</a>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_sex }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_sex }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_birthdate }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->patient_birthdate }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->study_modality }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->study_modality }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->study_date }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->study_date }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->receive_date }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->receive_date }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->image_count }} / {{ $study->series_count }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->image_count }}
/ {{ $study->series_count }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->institution_name }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $study->institution_name }}</td>
<td> <td>
<a target="_blank" href="{{ \App\Services\Pacs\PacsUrlGen::stoneViewer($study->study_instance_uid) }}" >St</a> <a target="_blank"
href="{{ \App\Services\Pacs\PacsUrlGen::stoneViewer($study->study_instance_uid) }}">St</a>
| |
<a target="_blank" href="{{ \App\Services\Pacs\PacsUrlGen::ohifViewer($study->study_instance_uid) }}">OHF</a> <a target="_blank"
href="{{ \App\Services\Pacs\PacsUrlGen::ohifViewer($study->study_instance_uid) }}">OHF</a>
@if($study->image_count > 1 && $study->study_modality != 'CR') @if($study->image_count > 1 && $study->study_modality != 'CR')
| |
<a target="_blank" href="{{ \App\Services\Pacs\PacsUrlGen::ohifViewerMpr($study->study_instance_uid) }}">MPR</a> <a target="_blank"
href="{{ \App\Services\Pacs\PacsUrlGen::ohifViewerMpr($study->study_instance_uid) }}">MPR</a>
| |
<a target="_blank" class="btn" href="{{ \App\Services\Pacs\PacsUrlGen::ohifSegmentation($study->study_instance_uid) }}">SEG</a> <a target="_blank" class="btn"
href="{{ \App\Services\Pacs\PacsUrlGen::ohifSegmentation($study->study_instance_uid) }}">SEG</a>
@endif @endif
| |
<a target="_blank" class="btn" href="{{ \App\Services\Pacs\PacsUrlGen::archive($study->orthanc_uid) }}">ZIP</a> <a target="_blank" class="btn"
href="{{ \App\Services\Pacs\PacsUrlGen::archive($study->orthanc_uid) }}">ZIP</a>
| |
<a target="_blank" class="btn" href="{{ route('radiologist.report-write', $study->id) }}">TXT</a> <a target="_blank" class="btn"
href="{{ route('radiologist.report-write', $study->id) }}">TXT</a>
</td> </td>
</tr> </tr>

View File

@ -1,5 +1,6 @@
<?php <?php
use App\Http\Controllers\Guest\ViewSharedStudyController;
use App\Http\Controllers\Radiologist\ReportWriteController; use App\Http\Controllers\Radiologist\ReportWriteController;
use App\Http\Controllers\Staff\StudiesController; use App\Http\Controllers\Staff\StudiesController;
use App\Http\Controllers\System\SyncOrthancController; use App\Http\Controllers\System\SyncOrthancController;
@ -33,4 +34,9 @@
}); });
Route::group(['prefix' => 'shares', 'as' => 'shares.'], function () {
Route::get('study/{hashid}', [ViewSharedStudyController::class, 'show'])->name('show');
Route::post('auth/{hashid}', [ViewSharedStudyController::class, 'auth'])->name('auth');
});
Route::view('/ck', 'ck'); Route::view('/ck', 'ck');