Merge branch 'main' of github.com:masroore/radsparc-web

# Conflicts:
#	composer.lock
This commit is contained in:
Dr Masroor Ehsan 2024-12-30 07:47:45 +06:00
commit fb85254d01
23 changed files with 177 additions and 11220 deletions

View File

@ -3,7 +3,7 @@ APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_TIMEZONE=UTC APP_TIMEZONE=UTC
APP_URL=http://localhost APP_URL=http://radsparc.test
APP_PORT=80 APP_PORT=80
APP_LOCALE=en APP_LOCALE=en
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
@ -21,14 +21,14 @@ LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug LOG_LEVEL=debug
DB_CONNECTION=sqlite DB_CONNECTION=pgsql
# DB_HOST=127.0.0.1 DB_HOST=pgsql
# DB_PORT=3306 DB_PORT=5432
# DB_DATABASE=laravel DB_DATABASE=radsphere
# DB_USERNAME=root DB_USERNAME=sail
# DB_PASSWORD= DB_PASSWORD=secret
SESSION_DRIVER=database SESSION_DRIVER=redis
SESSION_LIFETIME=120 SESSION_LIFETIME=120
SESSION_ENCRYPT=false SESSION_ENCRYPT=false
SESSION_PATH=/ SESSION_PATH=/
@ -38,13 +38,13 @@ BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local FILESYSTEM_DISK=local
QUEUE_CONNECTION=database QUEUE_CONNECTION=database
CACHE_STORE=database CACHE_STORE=redis
CACHE_PREFIX= CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1 MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1 REDIS_HOST=redis
REDIS_PASSWORD=null REDIS_PASSWORD=null
REDIS_PORT=6379 REDIS_PORT=6379

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ yarn-error.log
/.nova /.nova
/.vscode /.vscode
/.zed /.zed
*.lock

View File

@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StudyHistoryRequest extends FormRequest
{
public function rules(): array
{
return [
'study_id' => ['required', 'exists:studies'],
'user_id' => ['required', 'exists:users'],
'clinical_history' => ['nullable'],
'surgical_history' => ['nullable'],
'lab_results' => ['nullable'],
'clinical_diagnosis' => ['nullable'],
];
}
public function authorize(): bool
{
return true;
}
}

10
app/Models/BaseModel.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
abstract class BaseModel extends Model
{
protected $guarded = ['id'];
}

View File

@ -3,9 +3,8 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Institute extends Model class Institute extends BaseModel
{ {
use HasFactory; use HasFactory;

View File

@ -4,9 +4,10 @@
use App\Models\Enums\ReportStatus; use App\Models\Enums\ReportStatus;
use App\Models\Enums\StudyLevelStatus; use App\Models\Enums\StudyLevelStatus;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
class Study extends Model class Study extends BaseModel
{ {
protected $casts = [ protected $casts = [
'is_locked' => 'boolean', 'is_locked' => 'boolean',
@ -15,5 +16,18 @@ class Study extends Model
'report_status' => ReportStatus::class, 'report_status' => ReportStatus::class,
]; ];
protected $guarded = ['id']; public function history(): HasOne
{
return $this->hasOne(StudyHistory::class);
}
public function attachments(): HasMany
{
return $this->hasMany(StudyAttachment::class);
}
public function reports(): HasMany
{
return $this->hasMany(StudyReport::class);
}
} }

View File

@ -2,6 +2,4 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; class StudyAttachment extends BaseModel {}
class StudyAttachment extends Model {}

View File

@ -2,6 +2,4 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; class StudyDeleteRequest extends BaseModel {}
class StudyDeleteRequest extends Model {}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class StudyHistory extends BaseModel
{
public function study(): BelongsTo
{
return $this->belongsTo(Study::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

View File

@ -2,6 +2,4 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; class StudyNote extends BaseModel {}
class StudyNote extends Model {}

View File

@ -2,10 +2,9 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
class StudyReport extends Model class StudyReport extends BaseModel
{ {
public function study(): BelongsTo public function study(): BelongsTo
{ {

View File

@ -2,6 +2,17 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Template extends Model {} class Template extends BaseModel
{
public function owner(): BelongsTo
{
return $this->belongsTo(User::class, 'owner_id');
}
public function category(): BelongsTo
{
return $this->belongsTo(TemplateCategory::class, 'category_id');
}
}

View File

@ -2,6 +2,4 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; class TemplateCategory extends BaseModel {}
class TemplateCategory extends Model {}

View File

@ -12,6 +12,24 @@
/** @psalm-type Int32BitMask = int<0, 2147483647> */ /** @psalm-type Int32BitMask = int<0, 2147483647> */
trait BitmaskFunctionality trait BitmaskFunctionality
{ {
/** @param Int32BitMask $value */
public static function hasCase(int $value): bool
{
return self::tryFrom($value) !== null;
}
/** @return Int32BitMask */
public static function build(self ...$bits): int
{
return self::set(0, ...$bits);
}
/** @return Int32BitMask */
public static function set(int $value, self ...$bits): int
{
return $value | self::mask(...$bits);
}
/** @return Int32BitMask */ /** @return Int32BitMask */
public static function mask(self ...$bits): int public static function mask(self ...$bits): int
{ {
@ -22,39 +40,6 @@ public static function mask(self ...$bits): int
return array_reduce($bits, static fn (?int $sum, self $case) => ($sum ?? 0) | $case->value); return array_reduce($bits, static fn (?int $sum, self $case) => ($sum ?? 0) | $case->value);
} }
/** @param Int32BitMask $value */
public static function hasCase(int $value): bool
{
return self::tryFrom($value) !== null;
}
/** @param Int32BitMask $value */
public static function valueToString(int $value): string
{
return '0b'.substr(chunk_split(sprintf('%\'032b', $value), 4, '_'), 0, -1);
}
public function toString(): string
{
return self::valueToString($this->value);
}
/** @return Int32BitMask */
public static function build(self ...$bits): int
{
return self::set(0, ...$bits);
}
/** @param Int32BitMask $value */
/** @return Int32BitMask */
public static function set(int $value, self ...$bits): int
{
return $value | self::mask(...$bits);
}
/** @param Int32BitMask $value */
/** @return Int32BitMask */ /** @return Int32BitMask */
public static function clear(int $value, self ...$bits): int public static function clear(int $value, self ...$bits): int
{ {
@ -70,10 +55,6 @@ public static function toggle(int $value, self ...$bits): int
} }
/** @param Int32BitMask $value */ /** @param Int32BitMask $value */
public static function on(int $value, self $bit): bool
{
return ($value & $bit->value) === $bit->value;
}
/** @param Int32BitMask $value */ /** @param Int32BitMask $value */
public static function off(int $value, self $bit): bool public static function off(int $value, self $bit): bool
@ -81,6 +62,8 @@ public static function off(int $value, self $bit): bool
return ($value & $bit->value) === 0; return ($value & $bit->value) === 0;
} }
/** @param Int32BitMask $value */
/** @param Int32BitMask $value */ /** @param Int32BitMask $value */
public static function any(int $value, self ...$bits): bool public static function any(int $value, self ...$bits): bool
{ {
@ -123,4 +106,21 @@ public static function parse(int $value): array
{ {
return array_filter(self::cases(), static fn (self $case) => self::on($value, $case)); return array_filter(self::cases(), static fn (self $case) => self::on($value, $case));
} }
/** @param Int32BitMask $value */
public static function on(int $value, self $bit): bool
{
return ($value & $bit->value) === $bit->value;
}
public function toString(): string
{
return self::valueToString($this->value);
}
/** @param Int32BitMask $value */
public static function valueToString(int $value): string
{
return '0b'.substr(chunk_split(sprintf('%\'032b', $value), 4, '_'), 0, -1);
}
} }

View File

@ -3,6 +3,7 @@
namespace App\Models; namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail; // use Illuminate\Contracts\Auth\MustVerifyEmail;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
@ -15,7 +16,7 @@ class User extends Authenticatable
{ {
use HasApiTokens; use HasApiTokens;
/** @use HasFactory<\Database\Factories\UserFactory> */ /** @use HasFactory<UserFactory> */
use HasFactory; use HasFactory;
use HasProfilePhoto; use HasProfilePhoto;

View File

@ -95,7 +95,7 @@ private function prepareData(mixed $study): array
'institution_name' => $inst_name, 'institution_name' => $inst_name,
'institute_id' => $inst_id, 'institute_id' => $inst_id,
'patient_uuid' => $study['ParentPatient'], 'patient_uid' => $study['ParentPatient'],
'patient_id' => data_get($study, 'PatientMainDicomTags.PatientID'), 'patient_id' => data_get($study, 'PatientMainDicomTags.PatientID'),
'patient_name' => data_get($study, 'PatientMainDicomTags.PatientName'), 'patient_name' => data_get($study, 'PatientMainDicomTags.PatientName'),
'patient_sex' => data_get($study, 'PatientMainDicomTags.PatientSex'), 'patient_sex' => data_get($study, 'PatientMainDicomTags.PatientSex'),

View File

@ -17,6 +17,7 @@
"laravel/tinker": "^2.9", "laravel/tinker": "^2.9",
"league/url": "^3.3", "league/url": "^3.3",
"livewire/livewire": "^3.0", "livewire/livewire": "^3.0",
"phpoffice/phpword": "^1.3",
"propaganistas/laravel-phone": "^5.3", "propaganistas/laravel-phone": "^5.3",
"rap2hpoutre/fast-excel": "^5.5", "rap2hpoutre/fast-excel": "^5.5",
"spatie/laravel-permission": "^6.10", "spatie/laravel-permission": "^6.10",
@ -31,7 +32,7 @@
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
"laravel/pail": "^1.1", "laravel/pail": "^1.1",
"laravel/pint": "^1.13", "laravel/pint": "^1.13",
"laravel/sail": "^1.26", "laravel/sail": "^1.39",
"mockery/mockery": "^1.6", "mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.1", "nunomaduro/collision": "^8.1",
"pestphp/pest": "^3.7", "pestphp/pest": "^3.7",

11143
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ public function up(): void
$table->boolean('is_locked')->default(true); $table->boolean('is_locked')->default(true);
$table->unsignedTinyInteger('study_priority')->default(0); $table->unsignedTinyInteger('study_priority')->default(0);
$table->string('patient_id')->nullable(); $table->string('patient_id')->nullable();
$table->string('patient_uuid')->nullable(); $table->string('patient_uid')->nullable();
$table->string('patient_name'); $table->string('patient_name');
$table->string('patient_sex')->nullable(); $table->string('patient_sex')->nullable();
$table->date('patient_birthdate')->nullable(); $table->date('patient_birthdate')->nullable();
@ -35,6 +35,7 @@ public function up(): void
$table->string('operators_name')->nullable(); $table->string('operators_name')->nullable();
$table->string('manufacturer')->nullable(); $table->string('manufacturer')->nullable();
$table->string('manufacturer_model_name')->nullable(); $table->string('manufacturer_model_name')->nullable();
$table->string('software_versions')->nullable();
$table->string('referring_physician_name')->nullable(); $table->string('referring_physician_name')->nullable();
$table->string('study_modality', 4)->nullable(); $table->string('study_modality', 4)->nullable();

View File

@ -12,8 +12,8 @@ public function up(): void
{ {
Schema::create('study_notes', function (Blueprint $table) { Schema::create('study_notes', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignIdFor(Study::class)->constrained()->onDelete('cascade'); $table->foreignIdFor(Study::class)->constrained()->cascadeOnDelete();
$table->foreignIdFor(User::class)->nullable()->constrained()->onDelete('cascade'); $table->foreignIdFor(User::class)->nullable()->constrained()->cascadeOnDelete();
$table->string('title')->nullable(); $table->string('title')->nullable();
$table->longText('content'); $table->longText('content');
$table->timestamps(); $table->timestamps();

View File

@ -14,8 +14,9 @@ public function up(): void
Schema::create('study_reports', function (Blueprint $table) { Schema::create('study_reports', function (Blueprint $table) {
$table->id(); $table->id();
$table->unsignedTinyInteger('report_status')->default(ReportStatus::Pending->value); $table->unsignedTinyInteger('report_status')->default(ReportStatus::Pending->value);
$table->foreignIdFor(Study::class)->index()->constrained()->onDelete('cascade'); $table->foreignIdFor(Study::class)->index()->constrained()->cascadeOnDelete();
$table->foreignIdFor(User::class)->index()->constrained()->onDelete('cascade'); $table->foreignIdFor(User::class, 'radiologist_id')->index()->constrained()->cascadeOnDelete();
$table->string('report_title')->nullable();
$table->string('file_path'); $table->string('file_path');
$table->string('pdf_path')->nullable(); $table->string('pdf_path')->nullable();
$table->timestamps(); $table->timestamps();

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('study_histories', function (Blueprint $table) {
$table->id();
$table->foreignId('study_id')->index()->constrained('studies')->cascadeOnDelete();
$table->foreignId('user_id')->constrained('users');
$table->text('clinical_history')->nullable();
$table->text('surgical_history')->nullable();
$table->text('lab_results')->nullable();
$table->text('clinical_diagnosis')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('study_histories');
}
};

2
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "radsparc", "name": "html",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {