diff --git a/app/Console/Commands/GeneratePersonalAccessToken.php b/app/Console/Commands/GeneratePersonalAccessToken.php new file mode 100644 index 000000000..098d9678a --- /dev/null +++ b/app/Console/Commands/GeneratePersonalAccessToken.php @@ -0,0 +1,97 @@ +validation = $validation; + $this->tokenRepository = $tokenRepository; + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + + $accessTokenName = $this->option('name'); + if ($accessTokenName=='') { + $accessTokenName = 'CLI Auth Token'; + } + + if ($this->option('user_id')=='') { + return $this->error('ERROR: user_id cannot be blank.'); + } + + if ($user = User::find($this->option('user_id'))) { + + $createAccessToken = $user->createToken($accessTokenName)->accessToken; + + if ($this->option('key-only')) { + $this->info($createAccessToken); + + } else { + + $this->warn('Your API Token has been created. Be sure to copy this token now, as it will not be accessible again.'); + + if ($token = DB::table('oauth_access_tokens')->where('user_id', '=', $user->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first()) { + $this->info('API Token ID: '.$token->id); + } + + $this->info('API Token User: '.$user->present()->fullName.' ('.$user->username.')'); + $this->info('API Token Name: '.$accessTokenName); + $this->info('API Token: '.$createAccessToken); + } + } else { + return $this->error('ERROR: Invalid user. API key was not created.'); + } + + + + + } +} diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index 931056286..164928aab 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -32,6 +32,28 @@ class CategoriesController extends Controller $categories = $categories->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $categories->where('name', '=', $request->input('name')); + } + + if ($request->filled('category_type')) { + $categories->where('category_type', '=', $request->input('category_type')); + } + + if ($request->filled('use_default_eula')) { + $categories->where('use_default_eula', '=', $request->input('use_default_eula')); + } + + if ($request->filled('require_acceptance')) { + $categories->where('require_acceptance', '=', $request->input('require_acceptance')); + } + + if ($request->filled('checkin_email')) { + $categories->where('checkin_email', '=', $request->input('checkin_email')); + } + + + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($categories) && ($request->get('offset') > $categories->count())) ? $categories->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/CompaniesController.php b/app/Http/Controllers/Api/CompaniesController.php index 8efe9f1c7..11f584567 100644 --- a/app/Http/Controllers/Api/CompaniesController.php +++ b/app/Http/Controllers/Api/CompaniesController.php @@ -43,6 +43,11 @@ class CompaniesController extends Controller $companies->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $companies->where('name', '=', $request->input('name')); + } + + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($companies) && ($request->get('offset') > $companies->count())) ? $companies->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index a3938bd39..e72e17eb2 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -51,6 +51,10 @@ class ComponentsController extends Controller $components = $components->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $components->where('name', '=', $request->input('name')); + } + if ($request->filled('company_id')) { $components->where('company_id', '=', $request->input('company_id')); } diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 7792663ef..a3aa09736 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -55,6 +55,10 @@ class ConsumablesController extends Controller $consumables = $consumables->TextSearch(e($request->input('search'))); } + if ($request->filled('name')) { + $consumables->where('name', '=', $request->input('name')); + } + if ($request->filled('company_id')) { $consumables->where('company_id', '=', $request->input('company_id')); } diff --git a/app/Http/Controllers/Api/DepartmentsController.php b/app/Http/Controllers/Api/DepartmentsController.php index 314de2aa5..09e367736 100644 --- a/app/Http/Controllers/Api/DepartmentsController.php +++ b/app/Http/Controllers/Api/DepartmentsController.php @@ -42,6 +42,22 @@ class DepartmentsController extends Controller $departments = $departments->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $departments->where('name', '=', $request->input('name')); + } + + if ($request->filled('company_id')) { + $departments->where('company_id', '=', $request->input('company_id')); + } + + if ($request->filled('manager_id')) { + $departments->where('manager_id', '=', $request->input('manager_id')); + } + + if ($request->filled('location_id')) { + $departments->where('location_id', '=', $request->input('location_id')); + } + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($departments) && ($request->get('offset') > $departments->count())) ? $departments->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/GroupsController.php b/app/Http/Controllers/Api/GroupsController.php index 5a3fe0642..2c3776062 100644 --- a/app/Http/Controllers/Api/GroupsController.php +++ b/app/Http/Controllers/Api/GroupsController.php @@ -28,6 +28,10 @@ class GroupsController extends Controller $groups = $groups->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $groups->where('name', '=', $request->input('name')); + } + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($groups) && ($request->get('offset') > $groups->count())) ? $groups->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index fa16f8dbb..176033453 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -53,6 +53,30 @@ class LocationsController extends Controller $locations = $locations->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $locations->where('locations.name', '=', $request->input('name')); + } + + if ($request->filled('address')) { + $locations->where('locations.address', '=', $request->input('address')); + } + + if ($request->filled('address2')) { + $locations->where('locations.address2', '=', $request->input('address2')); + } + + if ($request->filled('city')) { + $locations->where('locations.city', '=', $request->input('city')); + } + + if ($request->filled('zip')) { + $locations->where('locations.zip', '=', $request->input('zip')); + } + + if ($request->filled('country')) { + $locations->where('locations.country', '=', $request->input('country')); + } + $offset = (($locations) && (request('offset') > $locations->count())) ? $locations->count() : request('offset', 0); // Check to make sure the limit is not higher than the max allowed diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index b1a411fc5..e88ef5fed 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -37,6 +37,26 @@ class ManufacturersController extends Controller $manufacturers = $manufacturers->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $manufacturers->where('name', '=', $request->input('name')); + } + + if ($request->filled('url')) { + $manufacturers->where('url', '=', $request->input('url')); + } + + if ($request->filled('support_url')) { + $manufacturers->where('support_url', '=', $request->input('support_url')); + } + + if ($request->filled('support_phone')) { + $manufacturers->where('support_phone', '=', $request->input('support_phone')); + } + + if ($request->filled('support_email')) { + $manufacturers->where('support_email', '=', $request->input('support_email')); + } + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($manufacturers) && ($request->get('offset') > $manufacturers->count())) ? $manufacturers->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/ProfileController.php b/app/Http/Controllers/Api/ProfileController.php index 8a06a268d..691efda98 100644 --- a/app/Http/Controllers/Api/ProfileController.php +++ b/app/Http/Controllers/Api/ProfileController.php @@ -5,10 +5,37 @@ namespace App\Http\Controllers\Api; use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\CheckoutRequest; -use Auth; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; +use Illuminate\Http\Request; +use Laravel\Passport\TokenRepository; +use Illuminate\Contracts\Validation\Factory as ValidationFactory; +use Gate; +use DB; class ProfileController extends Controller { + + /** + * The token repository implementation. + * + * @var \Laravel\Passport\TokenRepository + */ + protected $tokenRepository; + + /** + * Create a controller instance. + * + * @param \Laravel\Passport\TokenRepository $tokenRepository + * @param \Illuminate\Contracts\Validation\Factory $validation + * @return void + */ + public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation) + { + $this->validation = $validation; + $this->tokenRepository = $tokenRepository; + } + /** * Display a listing of requested assets. * @@ -42,4 +69,90 @@ class ProfileController extends Controller return $results; } + + + /** + * Delete an API token + * + * @author [A. Gianotto] [] + * @since [v6.0.5] + * + * @return \Illuminate\Http\Response + */ + public function createApiToken(Request $request) { + + if (!Gate::allows('self.api')) { + abort(403); + } + + $accessTokenName = $request->input('name', 'Auth Token'); + + if ($accessToken = Auth::user()->createToken($accessTokenName)->accessToken) { + + // Get the ID so we can return that with the payload + $token = DB::table('oauth_access_tokens')->where('user_id', '=', Auth::user()->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first(); + $accessTokenData['id'] = $token->id; + $accessTokenData['token'] = $accessToken; + $accessTokenData['name'] = $accessTokenName; + return response()->json(Helper::formatStandardApiResponse('success', $accessTokenData, 'Personal access token '.$accessTokenName.' created successfully')); + } + return response()->json(Helper::formatStandardApiResponse('error', null, 'Token could not be created.')); + + } + + + /** + * Delete an API token + * + * @author [A. Gianotto] [] + * @since [v6.0.5] + * + * @return \Illuminate\Http\Response + */ + public function deleteApiToken($tokenId) { + + if (!Gate::allows('self.api')) { + abort(403); + } + + $token = $this->tokenRepository->findForUser( + $tokenId, Auth::user()->getAuthIdentifier() + ); + + if (is_null($token)) { + return new Response('', 404); + } + + $token->revoke(); + + return new Response('', Response::HTTP_NO_CONTENT); + + } + + + /** + * Show user's API tokens + * + * @author [A. Gianotto] [] + * @since [v6.0.5] + * + * @return \Illuminate\Http\Response + */ + public function showApiTokens(Request $request) { + + if (!Gate::allows('self.api')) { + abort(403); + } + + $tokens = $this->tokenRepository->forUser(Auth::user()->getAuthIdentifier()); + $token_values = $tokens->load('client')->filter(function ($token) { + return $token->client->personal_access_client && ! $token->revoked; + })->values(); + + return response()->json(Helper::formatStandardApiResponse('success', $token_values, null)); + + } + + + } diff --git a/app/Http/Controllers/Api/SettingsController.php b/app/Http/Controllers/Api/SettingsController.php index 9444b5980..62380b221 100644 --- a/app/Http/Controllers/Api/SettingsController.php +++ b/app/Http/Controllers/Api/SettingsController.php @@ -2,6 +2,9 @@ namespace App\Http\Controllers\Api; +use App\Helpers\Helper; +use App\Helpers\StorageHelper; +use App\Http\Transformers\DatatablesTransformer; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use App\Models\Ldap; @@ -265,4 +268,52 @@ class SettingsController extends Controller return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total); } + + + public function listBackups() { + $settings = Setting::getSettings(); + $path = 'app/backups'; + $backup_files = Storage::files($path); + $files_raw = []; + $count = 0; + + if (count($backup_files) > 0) { + + for ($f = 0; $f < count($backup_files); $f++) { + + // Skip dotfiles like .gitignore and .DS_STORE + if ((substr(basename($backup_files[$f]), 0, 1) != '.')) { + $file_timestamp = Storage::lastModified($backup_files[$f]); + + $files_raw[] = [ + 'filename' => basename($backup_files[$f]), + 'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])), + 'modified_value' => $file_timestamp, + 'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp), + + ]; + $count++; + } + + + } + } + + $files = array_reverse($files_raw); + return (new DatatablesTransformer)->transformDatatables($files, $count); + + } + + + public function downloadBackup($file) { + + $path = 'app/backups'; + if (Storage::exists($path.'/'.$file)) { + $headers = ['ContentType' => 'application/zip']; + return Storage::download($path.'/'.$file, $file, $headers); + } else { + return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found')); + } + + } } \ No newline at end of file diff --git a/app/Http/Controllers/Api/StatuslabelsController.php b/app/Http/Controllers/Api/StatuslabelsController.php index f94600e1d..b2522a8a5 100644 --- a/app/Http/Controllers/Api/StatuslabelsController.php +++ b/app/Http/Controllers/Api/StatuslabelsController.php @@ -30,6 +30,10 @@ class StatuslabelsController extends Controller $statuslabels = $statuslabels->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $statuslabels->where('name', '=', $request->input('name')); + } + // if a status_type is passed, filter by that if ($request->filled('status_type')) { diff --git a/app/Http/Controllers/Api/SuppliersController.php b/app/Http/Controllers/Api/SuppliersController.php index 40ff9e8bd..f73f15049 100644 --- a/app/Http/Controllers/Api/SuppliersController.php +++ b/app/Http/Controllers/Api/SuppliersController.php @@ -34,6 +34,46 @@ class SuppliersController extends Controller $suppliers = $suppliers->TextSearch($request->input('search')); } + if ($request->filled('name')) { + $suppliers->where('name', '=', $request->input('name')); + } + + if ($request->filled('address')) { + $suppliers->where('address', '=', $request->input('address')); + } + + if ($request->filled('address2')) { + $suppliers->where('address2', '=', $request->input('address2')); + } + + if ($request->filled('city')) { + $suppliers->where('city', '=', $request->input('city')); + } + + if ($request->filled('zip')) { + $suppliers->where('zip', '=', $request->input('zip')); + } + + if ($request->filled('country')) { + $suppliers->where('country', '=', $request->input('country')); + } + + if ($request->filled('fax')) { + $suppliers->where('fax', '=', $request->input('fax')); + } + + if ($request->filled('email')) { + $suppliers->where('email', '=', $request->input('email')); + } + + if ($request->filled('url')) { + $suppliers->where('url', '=', $request->input('url')); + } + + if ($request->filled('notes')) { + $suppliers->where('notes', '=', $request->input('notes')); + } + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($suppliers) && ($request->get('offset') > $suppliers->count())) ? $suppliers->count() : $request->get('offset', 0); diff --git a/routes/api.php b/routes/api.php index 29af43568..3c0ab53c7 100644 --- a/routes/api.php +++ b/routes/api.php @@ -48,6 +48,27 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi ] )->name('api.assets.requestable'); + Route::post('personal-access-tokens', + [ + Api\ProfileController::class, + 'createApiToken' + ] + )->name('api.personal-access-token.create'); + + Route::get('personal-access-tokens', + [ + Api\ProfileController::class, + 'showApiTokens' + ] + )->name('api.personal-access-token.index'); + + Route::delete('personal-access-tokens/{tokenId}', + [ + Api\ProfileController::class, + 'deleteApiToken' + ] + )->name('api.personal-access-token.delete'); + }); // end account group @@ -765,6 +786,20 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi ] )->name('api.settings.mailtest'); + Route::get('backups', + [ + Api\SettingsController::class, + 'listBackups' + ] + )->name('api.settings.backups.index'); + + Route::get('backups/download/{file}', + [ + Api\SettingsController::class, + 'downloadBackup' + ] + )->name('api.settings.backups.download'); + }); Route::resource('settings',