3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-02-04 18:05:26 +00:00

Added uploaded files API controllers and presenters

Signed-off-by: snipe <snipe@snipe.net>
This commit is contained in:
snipe
2025-06-27 11:37:31 +01:00
parent 6f45ec655f
commit d8e7123576
19 changed files with 1857 additions and 215 deletions

View File

@ -116,9 +116,17 @@ class Handler extends ExceptionHandler
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
default:
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
}
}
// This handles API validation exceptions that happen at the Form Request level, so they
// never even get to the controller where we normally nicely format JSON responses
if ($e instanceof ValidationException) {
$response = $this->invalidJson($request, $e);
return response()->json(Helper::formatStandardApiResponse('error', null, $e->errors()), 200);
}
}

View File

@ -48,6 +48,7 @@ class StorageHelper
'avif',
'webp',
'png',
'gif',
];
@ -59,6 +60,18 @@ class StorageHelper
}
public static function getFiletype($file_with_path) {
// The file exists and is allowed to be displayed inline
if (Storage::exists($file_with_path)) {
return pathinfo($file_with_path, PATHINFO_EXTENSION);
}
return null;
}
/**
* Decide whether to show the file inline or download it.
*/

View File

@ -0,0 +1,244 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
use App\Http\Transformers\UploadedFilesTransformer;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\License;
use App\Models\Location;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
class UploadedFilesController extends Controller
{
static $map_object_type = [
'accessories' => Accessory::class,
'assets' => Asset::class,
'components' => Component::class,
'consumables' => Consumable::class,
'licenses' => License::class,
'locations' => Location::class,
'models' => AssetModel::class,
'users' => User::class,
];
static $map_storage_path = [
'accessories' => 'private_uploads/accessories/',
'assets' => 'private_uploads/assets/',
'components' => 'private_uploads/components/',
'consumables' => 'private_uploads/consumables/',
'licenses' => 'private_uploads/licenses/',
'locations' => 'private_uploads/locations/',
'models' => 'private_uploads/assetmodels/',
'users' => 'private_uploads/users/',
];
static $map_file_prefix= [
'accessories' => 'accessory',
'assets' => 'asset',
'components' => 'component',
'consumables' => 'consumable',
'licenses' => 'license',
'locations' => 'location',
'models' => 'model',
'users' => 'user',
];
/**
* List the files for an object.
*
* @since [v7.0.12]
* @author [r-xyz]
*/
public function index(Request $request, $object_type, $id) : JsonResponse | array
{
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
}
// Columns allowed for sorting
$allowed_columns =
[
'id',
'filename',
'action_type',
'note',
'created_at',
];
$uploads = $object->uploads();
$offset = ($request->input('offset') > $object->count()) ? $object->count() : abs($request->input('offset'));
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'action_logs.created_at';
// Text search on action_logs fields
// We could use the normal Actionlogs text scope, but it's a very heavy query since it's searcghing across all relations
// And we generally won't need that here
if ($request->filled('search')) {
$uploads->where(function ($query) use ($request) {
$query->where('filename', 'LIKE', '%' . $request->input('search') . '%')
->orWhere('note', 'LIKE', '%' . $request->input('search') . '%');
});
}
$uploads = $uploads->skip($offset)->take($limit)->orderBy($sort, $order)->get();
return (new UploadedFilesTransformer())->transformFiles($uploads, $uploads->count());
}
/**
* Accepts a POST to upload a file to the server.
*
* @param \App\Http\Requests\UploadFileRequest $request
* @param int $assetModelId
* @since [v7.0.12]
* @author [r-xyz]
*/
public function store(UploadFileRequest $request, $object_type, $id) : JsonResponse
{
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
}
// If the file storage directory doesn't exist, create it
if (! Storage::exists(self::$map_storage_path[$object_type])) {
Storage::makeDirectory(self::$map_storage_path[$object_type], 775);
}
if ($request->hasFile('file')) {
// Loop over the attached files and add them to the object
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile(self::$map_storage_path[$object_type],self::$map_file_prefix[$object_type].'-'.$object->id, $file);
$files[] = $file_name;
$object->logUpload($file_name, $request->get('notes'));
}
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
->where('item_type', '=', self::$map_object_type[$object_type])
->where('item_id', '=', $id)->whereIn('filename', $files)
->get();
return response()->json(Helper::formatStandardApiResponse('success', (new UploadedFilesTransformer())->transformFiles($files, count($files)), trans_choice('general.file_upload_status.upload.success', count($files))));
}
// No files were submitted
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.nofiles')));
}
/**
* Check for permissions and display the file.
*
* @param AssetModel $model
* @param int $fileId
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
* @since [v7.0.12]
* @author [r-xyz]
*/
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
{
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
}
// Check that the file being requested exists for the asset
if (! $log = Actionlog::whereNotNull('filename')
->where('item_type', AssetModel::class)
->where('item_id', $object->id)->find($file_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_id')), 200);
}
if (! Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.file_not_found'), 200));
}
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download(self::$map_storage_path[$object_type].'/'.$log->filename, $log->filename, $headers);
}
return StorageHelper::downloader(self::$map_storage_path[$object_type].'/'.$log->filename);
}
/**
* Delete the associated file
*
* @param AssetModel $model
* @param int $fileId
* @since [v7.0.12]
* @author [r-xyz]
*/
public function destroy($object_type, $id, $file_id) : JsonResponse
{
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('update', self::$map_object_type[$object_type]);
if (!$object) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
}
// Check for the file
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
->where('item_id', $object->id)->first();
if ($log) {
// Check the file actually exists, and delete it
if (Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) {
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
}
// Delete the record of the file
if ($log->delete()) {
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
}
}
// The file doesn't seem to really exist, so report an error
return response()->json(Helper::formatStandardApiResponse('error', null, trans_choice('general.file_upload_status.delete.error', 1)), 500);
}
}

View File

@ -6,6 +6,7 @@ use App\Http\Traits\ConvertsBase64ToFiles;
use enshrined\svgSanitize\Sanitizer;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use \App\Helpers\Helper;
class UploadFileRequest extends Request
{
@ -27,44 +28,62 @@ class UploadFileRequest extends Request
*/
public function rules()
{
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
$max_file_size = Helper::file_upload_max_size();
return [
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp,avif|max:'.$max_file_size,
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp,avif|max:'.$max_file_size,
];
}
/**
* Sanitizes (if needed) and Saves a file to the appropriate location
* Returns the 'short' (storage-relative) filename
*
* TODO - this has a lot of similarities to UploadImageRequest's handleImage; is there
* a way to merge them or extend one into the other?
*/
public function handleFile(string $dirname, string $name_prefix, $file): string
{
$extension = $file->getClientOriginalExtension();
$file_name = $name_prefix.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$file->guessExtension();
$file_name = $name_prefix.'-'.str_random(8).'-'.str_replace(' ', '-', $file->getClientOriginalName());
// Check for SVG and sanitize it
if ($file->getMimeType() === 'image/svg+xml') {
Log::debug('This is an SVG');
Log::debug($file_name);
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
try {
Storage::put($dirname.$file_name, $cleanSVG);
} catch (\Exception $e) {
Log::debug('Upload no workie :( ');
Log::debug($e);
}
$uploaded_file = $this->handleSVG($file);
} else {
$put_results = Storage::put($dirname.$file_name, file_get_contents($file));
$uploaded_file = file_get_contents($file);
}
try {
Storage::put($dirname.$file_name, $uploaded_file);
} catch (\Exception $e) {
Log::debug($e);
}
return $file_name;
}
}
public function handleSVG($file) {
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
return $sanitizer->sanitize($dirtySVG);
}
/**
* Get the validation error messages that apply to the request, but
* replace the attribute name with the name of the file that was attempted and failed
* to make it clearer to the user which file is the bad one.
* @return array
*/
public function attributes(): array
{
$attributes = [];
if ($this->file) {
for ($i = 0; $i < count($this->file); $i++) {
$attributes['file.'.$i] = $this->file[$i]->getClientOriginalName();
}
}
return $attributes;
}
}

View File

@ -4,6 +4,10 @@ namespace App\Http\Transformers;
class DatatablesTransformer
{
/**
* Transform data for bootstrap tables and API responses for lists of things
**/
public function transformDatatables($objects, $total = null)
{
(isset($total)) ? $objects_array['total'] = $total : $objects_array['total'] = count($objects);
@ -11,4 +15,15 @@ class DatatablesTransformer
return $objects_array;
}
}
/**
* Transform data for returning the status of items within a bulk action
**/
public function transformBulkResponseWithStatusAndObjects($objects, $total)
{
(isset($total)) ? $objects_array['total'] = $total : $objects_array['total'] = count($objects);
$objects_array['rows'] = $objects;
return $objects_array;
}
}

View File

@ -3,10 +3,10 @@
namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Helpers\StorageHelper;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
class UploadedFilesTransformer
@ -26,23 +26,26 @@ class UploadedFilesTransformer
{
$snipeModel = $file->item_type;
// This will be used later as we extend out this transformer to handle more types of uploads
if ($file->item_type == Asset::class) {
$file_url = route('show/assetfile', [$file->item_id, $file->id]);
}
$array = [
'id' => (int) $file->id,
'icon' => Helper::filetype_icon($file->filename),
'name' => e($file->filename),
'item' => ($file->item_type) ? [
'id' => (int) $file->item_id,
'type' => strtolower(class_basename($file->item_type)),
] : null,
'filename' => e($file->filename),
'url' => $file_url,
'filetype' => StorageHelper::getFiletype($file->uploads_file_path()),
'url' => $file->uploads_file_url(),
'note' => ($file->note) ? e($file->note) : null,
'created_by' => ($file->adminuser) ? [
'id' => (int) $file->adminuser->id,
'name'=> e($file->adminuser->present()->fullName),
] : null,
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($file->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
'inline' => StorageHelper::allowSafeInline($file->uploads_file_path()),
'exists_on_disk' => (Storage::exists($file->uploads_file_path()) ? true : false),
];
$permissions_array['available_actions'] = [
@ -53,4 +56,5 @@ class UploadedFilesTransformer
return $array;
}
}
}

View File

@ -69,8 +69,8 @@ class Actionlog extends SnipeModel
*/
protected $searchableRelations = [
'company' => ['name'],
'adminuser' => ['first_name','last_name','username', 'email', 'employee_num'],
'user' => ['first_name','last_name','username', 'email', 'employee_num'],
'adminuser' => ['first_name','last_name','username', 'email'],
'user' => ['first_name','last_name','username', 'email'],
'assets' => ['asset_tag','name', 'serial', 'order_number', 'notes', 'purchase_date'],
'assets.model' => ['name', 'model_number', 'eol', 'notes'],
'assets.model.category' => ['name', 'notes'],
@ -113,13 +113,7 @@ class Actionlog extends SnipeModel
} elseif (auth()->user() && auth()->user()->company) {
$actionlog->company_id = auth()->user()->company_id;
}
if ($actionlog->action_date == '') {
$actionlog->action_date = Carbon::now();
}
});
}
@ -251,8 +245,8 @@ class Actionlog extends SnipeModel
public function uploads()
{
return $this->morphTo('item')
->where('action_type', '=', 'uploaded')
->withTrashed();
->where('action_type', '=', 'uploaded')
->withTrashed();
}
/**
@ -277,7 +271,7 @@ class Actionlog extends SnipeModel
public function adminuser()
{
return $this->belongsTo(User::class, 'created_by')
->withTrashed();
->withTrashed();
}
/**
@ -382,7 +376,7 @@ class Actionlog extends SnipeModel
if ($this->created_at > $override_default_next) {
$next_audit_days = '-'.$next_audit_days;
}
return $next_audit_days;
}
@ -414,10 +408,10 @@ class Actionlog extends SnipeModel
public function getListingOfActionLogsChronologicalOrder()
{
return $this->all()
->where('action_type', '!=', 'uploaded')
->orderBy('item_id', 'asc')
->orderBy('created_at', 'asc')
->get();
->where('action_type', '!=', 'uploaded')
->orderBy('item_id', 'asc')
->orderBy('created_at', 'asc')
->get();
}
/**
@ -440,7 +434,7 @@ class Actionlog extends SnipeModel
return 'api';
}
// This is probably NOT an API call
// This is probably NOT an API call
if (request()->filled('_token')) {
return 'gui';
}
@ -450,6 +444,62 @@ class Actionlog extends SnipeModel
}
public function uploads_file_url()
{
switch ($this->item_type) {
case Accessory::class:
return route('show.accessoryfile', [$this->item_id, $this->id]);
case Asset::class:
return route('show/assetfile', [$this->item_id, $this->id]);
case AssetModel::class:
return route('show/modelfile', [$this->item_id, $this->id]);
case Consumable::class:
return route('show/locationsfile', [$this->item_id, $this->id]);
case Component::class:
return route('show.componentfile', [$this->item_id, $this->id]);
case License::class:
return route('show.licensefile', [$this->item_id, $this->id]);
case Location::class:
return route('show/locationsfile', [$this->item_id, $this->id]);
case User::class:
return route('show/userfile', [$this->item_id, $this->id]);
default:
return null;
}
}
public function uploads_file_path()
{
switch ($this->item_type) {
case Accessory::class:
return 'private_uploads/accessories/'.$this->filename;
case Asset::class:
return 'private_uploads/assets/'.$this->filename;
case AssetModel::class:
return 'private_uploads/assetmodels/'.$this->filename;
case Consumable::class:
return 'private_uploads/consumables/'.$this->filename;
case Component::class:
return 'private_uploads/components/'.$this->filename;
case License::class:
return 'private_uploads/licenses/'.$this->filename;
case Location::class:
return 'private_uploads/locations/'.$this->filename;
case User::class:
return 'private_uploads/users/'.$this->filename;
default:
return null;
}
}
// Manually sets $this->source for determineActionSource()
public function setActionSource($source = null): void
{
@ -460,4 +510,4 @@ class Actionlog extends SnipeModel
{
return $query->leftJoin('users as admin_sort', 'action_logs.created_by', '=', 'admin_sort.id')->select('action_logs.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
}
}
}

View File

@ -29,7 +29,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
use CompanyableTrait;
protected $presenter = \App\Presenters\UserPresenter::class;
use SoftDeletes, ValidatingTrait;
use SoftDeletes, ValidatingTrait, Loggable;
use Authenticatable, Authorizable, CanResetPassword, HasApiTokens;
use UniqueUndeletedTrait;
use Notifiable;

View File

@ -0,0 +1,101 @@
<?php
namespace App\Presenters;
/**
* Class AccessoryPresenter
*/
class UploadsPresenter extends Presenter
{
/**
* Json Column Layout for bootstrap table
* @return string
*/
public static function dataTableLayout($object)
{
if ($object =='assets') {
$object = 'hardware';
}
$layout = [
[
'field' => 'id',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.id'),
'visible' => false,
],
[
'field' => 'icon',
'searchable' => false,
'sortable' => false,
'switchable' => false,
'title' => trans('general.type'),
'formatter' => 'iconFormatter',
],
[
'field' => 'image',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.image'),
'formatter' => 'inlineImageFormatter',
],
[
'field' => 'filename',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.file_name'),
'visible' => true,
'formatter' => 'fileUploadNameFormatter',
],
[
'field' => 'download',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.download'),
'visible' => true,
'formatter' => 'downloadOrOpenInNewWindowFormatter',
],
[
'field' => 'note',
'searchable' => true,
'sortable' => true,
'switchable' => true,
'title' => trans('general.notes'),
'visible' => true,
],
[
'field' => 'created_by',
'searchable' => false,
'sortable' => true,
'title' => trans('general.created_by'),
'visible' => false,
'formatter' => 'usersLinkObjFormatter',
],
[
'field' => 'created_at',
'searchable' => true,
'sortable' => true,
'switchable' => true,
'title' => trans('general.created_at'),
'visible' => false,
'formatter' => 'dateDisplayFormatter',
], [
'field' => 'available_actions',
'searchable' => false,
'sortable' => false,
'switchable' => false,
'title' => trans('table.actions'),
'formatter' => 'deleteUploadFormatter',
],
];
return json_encode($layout);
}
}

View File

@ -640,4 +640,24 @@ return [
],
],
'file_upload_status' => [
'upload' => [
'success' => 'File successfully uploaded |:count files successfully uploaded',
'error' => 'File upload failed |:count file uploads failed',
],
'delete' => [
'success' => 'File successfully deleted |:count files successfully deleted',
'error' => 'File deletion failed |:count file deletions failed',
],
'file_not_found' => 'The selected file was not found on server',
'invalid_id' => 'That file ID is invalid',
'invalid_object' => 'That object ID is invalid',
'nofiles' => 'No files were included for upload',
'confirm_delete' => 'Are you sure you want to delete this file?',
],
];

View File

@ -556,35 +556,6 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
]
)->name('api.assets.restore');
Route::post('{asset}/files',
[
Api\AssetFilesController::class,
'store'
]
)->name('api.assets.files.store');
Route::get('{asset}/files',
[
Api\AssetFilesController::class,
'list'
]
)->name('api.assets.files.index');
Route::get('{asset_id}/file/{file_id}',
[
Api\AssetFilesController::class,
'show'
]
)->name('api.assets.files.show');
Route::delete('{asset_id}/file/{file_id}',
[
Api\AssetFilesController::class,
'destroy'
]
)->name('api.assets.files.destroy');
/** Begin assigned routes */
Route::get('{asset}/assigned/assets',
@ -853,33 +824,6 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
]
)->name('api.models.restore');
Route::post('{model_id}/files',
[
Api\AssetModelFilesController::class,
'store'
]
)->name('api.models.files.store');
Route::get('{model_id}/files',
[
Api\AssetModelFilesController::class,
'list'
]
)->name('api.models.files.index');
Route::get('{model_id}/file/{file_id}',
[
Api\AssetModelFilesController::class,
'show'
]
)->name('api.models.files.show');
Route::delete('{model_id}/file/{file_id}',
[
Api\AssetModelFilesController::class,
'destroy'
]
)->name('api.models.files.destroy');
});
Route::resource('models',
@ -1144,12 +1088,6 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
]
)->name('api.users.licenselist');
Route::post('{user}/upload',
[
Api\UsersController::class,
'postUpload'
]
)->name('api.users.uploads');
Route::post('{user}/restore',
[
@ -1365,5 +1303,44 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
])->name('api.assets.labels');
// end generate label routes
/**
* Uploaded files API routes
*/
// List files
Route::get('{object_type}/{id}/files',
[
Api\UploadedFilesController::class,
'index'
]
)->name('api.files.index')
->where(['object_type' => 'assets|models|users|locations|accessories|consumables|licenses|components']);
// Get a file
Route::get('{object_type}/{id}/files/{file_id}',
[
Api\UploadedFilesController::class,
'show'
]
)->name('api.files.show')
->where(['object_type' => 'assets|models|users|locations|accessories|consumables|licenses|components']);
// Upload files(s)
Route::post('{object_type}/{id}/files',
[
Api\UploadedFilesController::class,
'store'
]
)->name('api.files.store')
->where(['object_type' => 'assets|models|users|locations|accessories|consumables|licenses|components']);
// Delete files(s)
Route::delete('{object_type}/{id}/files/{file_id}/delete',
[
Api\UploadedFilesController::class,
'destroy'
]
)->name('api.files.destroy')
->where(['object_type' => 'assets|models|users|locations|accessories|consumables|licenses|components']);
}); // end API routes

View File

@ -0,0 +1,194 @@
<?php
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class AccessoryFilesTest extends TestCase
{
public function testAccessoryApiAcceptsFileUpload()
{
// Upload a file to a model
// Create a model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'accessories', 'id' => $accessory->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testAccessoryApiListsFiles()
{
// List all files on a model
// Create a model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'accessories', 'id' => $accessory->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testAccessoryFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $accessory->id]))
->assertStatus(404);
}
public function testAccessoryFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'accessories', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testAccessoryApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'accessories', 'id' => $accessory->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'accessories', 'id' => $accessory->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'accessories', 'id' => $accessory->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
->get(
route('api.files.show', [
'object_type' => 'accessories',
'id' => $accessory->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testAccessoryApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$accessory = Accessory::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'accessories', 'id' => $accessory->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'accessories', 'id' => $accessory->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.files.destroy', [
'object_type' => 'accessories',
'id' => $accessory->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}

View File

@ -14,39 +14,74 @@ class AssetModelFilesTest extends TestCase
// Upload a file to a model
// Create a model to work with
$model = AssetModel::factory()->count(1)->create();
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.models.files.store', ['model_id' => $model[0]["id"]]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
route('api.files.store', ['object_type' => 'models', 'id' => $model->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testAssetModelApiListsFiles()
{
// List all files on a model
// Create an model to work with
$model = AssetModel::factory()->count(1)->create();
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.models.files.index', ['model_id' => $model[0]["id"]]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
route('api.files.index', ['object_type' => 'models', 'id' => $model->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testAssetModelFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $model->id]))
->assertStatus(404);
}
public function testAssetModelFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'models', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testAssetModelApiDownloadsFile()
@ -54,40 +89,40 @@ class AssetModelFilesTest extends TestCase
// Download a file from a model
// Create a model to work with
$model = AssetModel::factory()->count(1)->create();
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.models.files.store', ['model_id' => $model[0]["id"]]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
route('api.files.store', ['object_type' => 'models', 'id' => $model->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.models.files.store', ['model_id' => $model[0]["id"]]), [
route('api.files.store', ['object_type' => 'models', 'id' => $model->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.models.files.index', ['model_id' => $model[0]["id"]]))
route('api.files.index', ['object_type' => 'models', 'id' => $model->id]))
->assertOk()
->assertJsonStructure([
'total',
@ -98,26 +133,24 @@ class AssetModelFilesTest extends TestCase
'url',
'created_by',
'created_at',
'updated_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note','')
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
// Get the file
$this->actingAsForApi($user)
->get(
route('api.models.files.show', [
'model_id' => $model[0]["id"],
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
route('api.files.show', [
'object_type' => 'models',
'id' => $model->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testAssetModelApiDeletesFile()
@ -125,36 +158,37 @@ class AssetModelFilesTest extends TestCase
// Delete a file from a model
// Create a model to work with
$model = AssetModel::factory()->count(1)->create();
$model = AssetModel::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.models.files.store', ['model_id' => $model[0]["id"]]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
route('api.files.store', ['object_type' => 'models', 'id' => $model->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.models.files.index', ['model_id' => $model[0]["id"]]))
->assertOk();
route('api.files.index', ['object_type' => 'models', 'id' => $model->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.models.files.destroy', [
'model_id' => $model[0]["id"],
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
route('api.files.destroy', [
'object_type' => 'models',
'id' => $model->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
'status',
'messages',
]);
}
}
}

View File

@ -14,7 +14,7 @@ class AssetFilesTest extends TestCase
// Upload a file to an asset
// Create an asset to work with
$asset = Asset::factory()->count(1)->create();
$asset = Asset::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
@ -22,30 +22,30 @@ class AssetFilesTest extends TestCase
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.assets.files.store', $asset), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
route('api.files.store', ['object_type' => 'assets', 'id' => $asset->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testAssetApiListsFiles()
{
// List all files on an asset
// Create an asset to work with
$asset = Asset::factory()->count(1)->create();
$asset = Asset::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(route('api.assets.files.index', $asset))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
->getJson(route('api.files.index', ['object_type' => 'assets', 'id' => $asset->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testAssetApiDownloadsFile()
@ -53,21 +53,21 @@ class AssetFilesTest extends TestCase
// Download a file from an asset
// Create an asset to work with
$asset = Asset::factory()->count(1)->create();
$asset = Asset::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(route('api.assets.files.store', $asset), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->post(route('api.files.store', ['object_type' => 'assets', 'id' => $asset->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(route('api.assets.files.index', $asset))
->getJson(route('api.files.index', ['object_type' => 'assets', 'id' => $asset->id]))
->assertOk();
}
@ -76,7 +76,7 @@ class AssetFilesTest extends TestCase
// Delete a file from an asset
// Create an asset to work with
$asset = Asset::factory()->count(1)->create();
$asset = Asset::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
@ -84,16 +84,16 @@ class AssetFilesTest extends TestCase
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.assets.files.store', $asset), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
route('api.files.store', ['object_type' => 'assets', 'id' => $asset->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.assets.files.index', $asset))
->assertOk();
route('api.files.index', ['object_type' => 'assets', 'id' => $asset->id]))
->assertOk();
}
}
}

View File

@ -0,0 +1,192 @@
<?php
namespace Tests\Feature\Components\Api;
use App\Models\Component;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class ComponentFileTest extends TestCase
{
public function testComponentApiAcceptsFileUpload()
{
// Create a model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'components', 'id' => $component->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testComponentApiListsFiles()
{
// List all files on a model
// Create a model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'components', 'id' => $component->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testComponentFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $component->id]))
->assertStatus(404);
}
public function testComponentFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'components', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testComponentApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'components', 'id' => $component->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'components', 'id' => $component->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'components', 'id' => $component->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
->get(
route('api.files.show', [
'object_type' => 'components',
'id' => $component->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testComponentApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$component = Component::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'components', 'id' => $component->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'components', 'id' => $component->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.files.destroy', [
'object_type' => 'components',
'id' => $component->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}

View File

@ -0,0 +1,194 @@
<?php
namespace Tests\Feature\Consumables\Api;
use App\Models\Consumable;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class ConsumableFileTest extends TestCase
{
public function testConsumableApiAcceptsFileUpload()
{
// Upload a file to a model
// Create a model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'consumables', 'id' => $consumable->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testConsumableApiListsFiles()
{
// List all files on a model
// Create a model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'consumables', 'id' => $consumable->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testConsumableFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $consumable->id]))
->assertStatus(404);
}
public function testConsumableFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'consumables', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testConsumableApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'consumables', 'id' => $consumable->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'consumables', 'id' => $consumable->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'consumables', 'id' => $consumable->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
->get(
route('api.files.show', [
'object_type' => 'consumables',
'id' => $consumable->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testConsumableApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$consumable = Consumable::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'consumables', 'id' => $consumable->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'consumables', 'id' => $consumable->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.files.destroy', [
'object_type' => 'consumables',
'id' => $consumable->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}

View File

@ -0,0 +1,194 @@
<?php
namespace Tests\Feature\Licenses\Api;
use App\Models\License;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class LicenseUploadTest extends TestCase
{
public function testLicenseApiAcceptsFileUpload()
{
// Upload a file to a model
// Create a model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'licenses', 'id' => $license->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testLicenseApiListsFiles()
{
// List all files on a model
// Create an model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'licenses', 'id' => $license->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testLicenseFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $license->id]))
->assertStatus(404);
}
public function testLicenseFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'licenses', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testLicenseApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'licenses', 'id' => $license->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'licenses', 'id' => $license->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'licenses', 'id' => $license->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
->get(
route('api.files.show', [
'object_type' => 'licenses',
'id' => $license->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testLicenseApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$license = License::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'licenses', 'id' => $license->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'licenses', 'id' => $license->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.files.destroy', [
'object_type' => 'licenses',
'id' => $license->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}

View File

@ -0,0 +1,192 @@
<?php
namespace Tests\Feature\Locations\Api;
use App\Models\Location;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class LocationFileTest extends TestCase
{
public function testLocationApiAcceptsFileUpload()
{
// Create a model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'locations', 'id' => $location->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testLocationApiListsFiles()
{
// List all files on a model
// Create a model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'locations', 'id' => $location->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testLocationFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $location->id]))
->assertStatus(404);
}
public function testLocationFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'locations', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testLocationApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'locations', 'id' => $location->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'locations', 'id' => $location->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'locations', 'id' => $location->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($user)
->get(
route('api.files.show', [
'object_type' => 'locations',
'id' => $location->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testLocationApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$location = Location::factory()->create();
// Create a superuser to run this as
$user = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($user)
->post(
route('api.files.store', ['object_type' => 'locations', 'id' => $location->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($user)
->getJson(
route('api.files.index', ['object_type' => 'locations', 'id' => $location->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($user)
->delete(
route('api.files.destroy', [
'object_type' => 'locations',
'id' => $location->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}

View File

@ -0,0 +1,191 @@
<?php
namespace Tests\Feature\Users\Api;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class UserFileTest extends TestCase
{
public function testUserApiAcceptsFileUpload()
{
// Create a model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($admin)
->post(
route('api.files.store', ['object_type' => 'users', 'id' => $user->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
}
public function testUserApiListsFiles()
{
// List all files on a model
// Create a model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($admin)
->getJson(
route('api.files.index', ['object_type' => 'users', 'id' => $user->id]))
->assertOk()
->assertJsonStructure([
'rows',
'total',
]);
}
public function testUserFailsIfInvalidTypePassedInUrl()
{
// List all files on a model
// Create an model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($admin)
->getJson(
route('api.files.index', ['object_type' => 'shibboleeeeeet', 'id' => $user->id]))
->assertStatus(404);
}
public function testUserFailsIfInvalidIdPassedInUrl()
{
// List all files on a model
// Create an model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
// List the files
$this->actingAsForApi($admin)
->getJson(
route('api.files.index', ['object_type' => 'users', 'id' => 100000]))
->assertOk()
->assertStatusMessageIs('error');
}
public function testUserApiDownloadsFile()
{
// Download a file from a model
// Create a model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
// Upload a file
$this->actingAsForApi($admin)
->post(
route('api.files.store', ['object_type' => 'users', 'id' => $user->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// Upload a file with notes
$this->actingAsForApi($admin)
->post(
route('api.files.store', ['object_type' => 'users', 'id' => $user->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)],
'notes' => 'manual'
])
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
// List the files to get the file ID
$result = $this->actingAsForApi($admin)
->getJson(
route('api.files.index', ['object_type' => 'users', 'id' => $user->id]))
->assertOk()
->assertJsonStructure([
'total',
'rows'=>[
'*' => [
'id',
'filename',
'url',
'created_by',
'created_at',
'deleted_at',
'note',
'available_actions'
]
]
])
->assertJsonPath('rows.0.note',null)
->assertJsonPath('rows.1.note','manual');
// Get the file
$this->actingAsForApi($admin)
->get(
route('api.files.show', [
'object_type' => 'users',
'id' => $user->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk();
}
public function testUserApiDeletesFile()
{
// Delete a file from a model
// Create a model to work with
$user = User::factory()->create();
// Create a superuser to run this as
$admin = User::factory()->superuser()->create();
//Upload a file
$this->actingAsForApi($admin)
->post(
route('api.files.store', ['object_type' => 'users', 'id' => $user->id]), [
'file' => [UploadedFile::fake()->create("test.jpg", 100)]
])
->assertOk();
// List the files to get the file ID
$result = $this->actingAsForApi($admin)
->getJson(
route('api.files.index', ['object_type' => 'users', 'id' => $user->id]))
->assertOk();
// Delete the file
$this->actingAsForApi($admin)
->delete(
route('api.files.destroy', [
'object_type' => 'users',
'id' => $user->id,
'file_id' => $result->decodeResponseJson()->json()["rows"][0]["id"],
]))
->assertOk()
->assertJsonStructure([
'status',
'messages',
]);
}
}