Merge remote-tracking branch 'origin/develop'

This commit is contained in:
snipe
2025-10-08 05:13:14 +01:00
7 changed files with 71 additions and 13 deletions

View File

@@ -116,6 +116,22 @@ class AssetsController extends Controller
'asset_eol_date',
'requestable',
'jobtitle',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'model',
'location',
'rtd_location',
'category',
'status_label',
'manufacturer',
'supplier',
'jobtitle',
'assigned_to',
'created_by',
];
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
@@ -132,6 +148,7 @@ class AssetsController extends Controller
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
}
$assets = Asset::select('assets.*')

View File

@@ -26,6 +26,7 @@ class StoreAssetRequest extends ImageUploadRequest
public function prepareForValidation(): void
{
parent::prepareForValidation(); // call ImageUploadRequest thing
// Guard against users passing in an array for company_id instead of an integer.
// If the company_id is not an integer then we simply use what was
// provided to be caught by model level validation later.

View File

@@ -2,6 +2,7 @@
namespace App\Http\Traits;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
@@ -38,20 +39,13 @@ trait ConvertsBase64ToFiles
if (!$base64Contents) {
return;
}
// autogenerate filenames
if ($filename == 'auto'){
$header = explode(';', $base64Contents, 2)[0];
// Grab the image type from the header while we're at it.
$filename = $key . '.' . substr($header, strpos($header, '/')+1);
}
// Generate a temporary path to store the Base64 contents
$tempFilePath = tempnam(sys_get_temp_dir(), $filename);
// Store the contents using a stream, or by decoding manually
// Store the contents using a stream, or throw an Error (which doesn't do anything?)
if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) {
$source = fopen($base64Contents, 'r');
$source = fopen($base64Contents, 'r'); // PHP has special processing for "data:" URL's
$destination = fopen($tempFilePath, 'w');
stream_copy_to_stream($source, $destination);
@@ -59,7 +53,8 @@ trait ConvertsBase64ToFiles
fclose($source);
fclose($destination);
} else {
file_put_contents($tempFilePath, base64_decode($base64Contents, true));
// TODO - to get a better error message here, can we maybe do something with modifying the errorBag?
throw new ValidationException("Need Base64 URL starting with 'data:'"); // This doesn't actually throw?
}
$uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true);

View File

@@ -493,6 +493,10 @@ class Actionlog extends SnipeModel
return 'private_uploads/eula-pdfs/'.$this->filename;
}
if ($this->action_type == 'audit') {
return 'private_uploads/audits/'.$this->filename;
}
switch ($this->item_type) {
case Accessory::class:
return 'private_uploads/accessories/'.$this->filename;

View File

@@ -1881,16 +1881,32 @@ class Asset extends Depreciable
);
}
if ($fieldname =='assigned_to') {
if ($fieldname == 'assigned_to') {
$query->whereHasMorph(
'assignedTo', [User::class], function ($query) use ($search_val) {
$query->where(
function ($query) use ($search_val) {
$query->where('users.first_name', 'LIKE', '%'.$search_val.'%')
->orWhere('users.last_name', 'LIKE', '%'.$search_val.'%');
->orWhere('users.last_name', 'LIKE', '%'.$search_val.'%')
->orWhere('users.username', 'LIKE', '%'.$search_val.'%');
}
);
}
)->orWhereHasMorph(
'assignedTo', [Location::class], function ($query) use ($search_val) {
$query->where('locations.name', 'LIKE', '%'.$search_val.'%');
}
)->orWhereHasMorph(
'assignedTo', [Asset::class], function ($query) use ($search_val) {
$query->where(
function ($query) use ($search_val) {
// Don't use the asset table prefix here because it will pull from the original asset,
// not the subselect we're doing here to get the assigned asset
$query->where('name', 'LIKE', '%'.$search_val.'%')
->orWhere('asset_tag', 'LIKE', '%'.$search_val.'%');
}
);
}
);
}

View File

@@ -1391,7 +1391,7 @@
<th data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">{{ trans('admin/hardware/table.icon') }}</th>
<th data-visible="true" data-field="created_at" data-sortable="true" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
<th data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.created_by') }}</th>
<th class="col-sm-2" data-field="file" data-sortable="true" data-visible="false" data-formatter="fileUploadNameFormatter">{{ trans('general.file_name') }}</th>
<th class="col-sm-2" data-field="file" data-sortable="true" data-visible="false" data-formatter="fileNameFormatter">{{ trans('general.file_name') }}</th>
<th data-field="note">{{ trans('general.notes') }}</th>
<th data-visible="false" data-field="file" data-visible="false" data-formatter="fileDownloadButtonsFormatter">{{ trans('general.download') }}</th>
<th data-field="log_meta" data-visible="true" data-formatter="changeLogFormatter">{{ trans('admin/hardware/table.changed')}}</th>

View File

@@ -11,6 +11,7 @@ use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Storage;
use Illuminate\Testing\Fluent\AssertableJson;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
@@ -831,4 +832,28 @@ class StoreAssetTest extends TestCase
$asset = Asset::findOrFail($response['payload']['id']);
$this->assertEquals('This is encrypted field', Crypt::decrypt($asset->{$field->db_column_name()}));
}
public function testBase64AssetImages()
{
$status = Statuslabel::factory()->readyToDeploy()->create();
$model = AssetModel::factory()->create();
$superuser = User::factory()->superuser()->create();
$response = $this->actingAsForApi($superuser)
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'asset_tag' => '1234',
'image' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsAQMAAADXeXeBAAAABlBMVEX+AAD///+KQee0AAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH5QQbCAoNcoiTQAAAACZJREFUaN7twTEBAAAAwqD1T20JT6AAAAAAAAAAAAAAAAAAAICnATvEAAEnf54JAAAAAElFTkSuQmCC'
])
->assertStatusMessageIs('success')
->assertOk()
->json();
$asset = Asset::findOrFail($response['payload']['id']);
$this->assertEquals($asset->asset_tag, '1234');
$image_data = Storage::disk('public')->get(app('assets_upload_path') . e($asset->image));
//$this->assertEquals('3d67fb99a0b6926e350f7b71397525d7a6b936c1', sha1($image_data)); //this doesn't work because the image gets resized - use the resized hash instead
$this->assertEquals('db2e13ba04318c99058ca429d67777322f48566b', sha1($image_data));
}
}