Merge remote-tracking branch 'origin/develop'

This commit is contained in:
snipe 2024-09-18 13:48:09 +01:00
commit a807646d39
30 changed files with 1243 additions and 59 deletions

View file

@ -188,10 +188,6 @@ class AssetMaintenancesController extends Controller
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot delete a maintenance for that asset'));
}
$assetMaintenance->delete();
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.delete.success')));

View file

@ -220,7 +220,6 @@ class LicensesController extends Controller
*/
public function destroy($id) : JsonResponse
{
//
$license = License::findOrFail($id);
$this->authorize('delete', $license);

View file

@ -4,6 +4,7 @@ namespace App\Models;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Validation\Rule;
use Watson\Validating\ValidatingTrait;
@ -16,6 +17,7 @@ use Watson\Validating\ValidatingTrait;
class PredefinedKit extends SnipeModel
{
protected $presenter = \App\Presenters\PredefinedKitPresenter::class;
use HasFactory;
use Presentable;
protected $table = 'kits';

View file

@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\PredefinedKit>
*/
class PredefinedKitFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->words(3, true),
];
}
}

View file

@ -141,6 +141,11 @@ class UserFactory extends Factory
return $this->appendPermission(['assets.view.requestable' => '1']);
}
public function deleteAssetModels()
{
return $this->appendPermission(['models.delete' => '1']);
}
public function viewAccessories()
{
return $this->appendPermission(['accessories.view' => '1']);
@ -201,6 +206,11 @@ class UserFactory extends Factory
return $this->appendPermission(['consumables.checkout' => '1']);
}
public function deleteDepartments()
{
return $this->appendPermission(['departments.delete' => '1']);
}
public function viewDepartments()
{
return $this->appendPermission(['departments.view' => '1']);
@ -241,11 +251,6 @@ class UserFactory extends Factory
return $this->appendPermission(['components.view' => '1']);
}
public function createCompanies()
{
return $this->appendPermission(['companies.create' => '1']);
}
public function createComponents()
{
return $this->appendPermission(['components.create' => '1']);
@ -271,6 +276,16 @@ class UserFactory extends Factory
return $this->appendPermission(['components.checkout' => '1']);
}
public function createCompanies()
{
return $this->appendPermission(['companies.create' => '1']);
}
public function deleteCompanies()
{
return $this->appendPermission(['companies.delete' => '1']);
}
public function viewUsers()
{
return $this->appendPermission(['users.view' => '1']);
@ -291,6 +306,16 @@ class UserFactory extends Factory
return $this->appendPermission(['users.delete' => '1']);
}
public function deleteCategories()
{
return $this->appendPermission(['categories.delete' => '1']);
}
public function deleteLocations()
{
return $this->appendPermission(['locations.delete' => '1']);
}
public function canEditOwnLocation()
{
return $this->appendPermission(['self.edit_location' => '1']);
@ -306,6 +331,41 @@ class UserFactory extends Factory
return $this->appendPermission(['import' => '1']);
}
public function deleteCustomFields()
{
return $this->appendPermission(['customfields.delete' => '1']);
}
public function deleteCustomFieldsets()
{
return $this->appendPermission(['customfields.delete' => '1']);
}
public function deleteDepreciations()
{
return $this->appendPermission(['depreciations.delete' => '1']);
}
public function deleteManufacturers()
{
return $this->appendPermission(['manufacturers.delete' => '1']);
}
public function deletePredefinedKits()
{
return $this->appendPermission(['kits.delete' => '1']);
}
public function deleteStatusLabels()
{
return $this->appendPermission(['statuslabels.delete' => '1']);
}
public function deleteSuppliers()
{
return $this->appendPermission(['suppliers.delete' => '1']);
}
private function appendPermission(array $permission)
{
return $this->state(function ($currentState) use ($permission) {

View file

@ -40,18 +40,18 @@ Form::macro('countries', function ($name = 'country', $selected = null, $class =
foreach ($countries_array as $abbr => $country) {
// We have to handle it this way to handle deprecication warnings since you can't strtoupper on null
// We have to handle it this way to handle deprecation warnings since you can't strtoupper on null
if ($abbr!='') {
$abbr = strtoupper($abbr);
}
// Loop through the countries configured in the localization file
$select .= '<option value="'.$abbr.'" selected="selected" role="option" '.(($selected == $abbr) ? ' selected="selected" role="option" aria-selected="true"' : ' aria-selected="false"').'>'.$country.'</option> ';
$select .= '<option value="' . $abbr . '" role="option" ' . (($selected == $abbr) ? ' selected="selected" aria-selected="true"' : ' aria-selected="false"') . '>' . $country . '</option> ';
}
// If the country value doesn't exist in the array, add it as a new option and select it so we don't drop that data
if (!in_array($selected, $countries_array)) {
if (!array_key_exists($selected, $countries_array)) {
$select .= '<option value="' . $selected . '" selected="selected" role="option" aria-selected="true">' . $selected .' *</option> ';
}

View file

@ -301,7 +301,7 @@
e.preventDefault();
var auto_tag = $("#asset_tag").val().replace(/[^\d]/g, '');
var auto_tag = $("#asset_tag").val().replace(/^{{ preg_quote(App\Models\Setting::getSettings()->auto_increment_prefix) }}/g, '');
var box_html = '';
const zeroPad = (num, places) => String(num).padStart(places, '0');

View file

@ -0,0 +1,8 @@
<?php
namespace Tests\Concerns;
interface TestsFullMultipleCompaniesSupport
{
public function testAdheresToFullMultipleCompaniesSupportScoping();
}

View file

@ -0,0 +1,8 @@
<?php
namespace Tests\Concerns;
interface TestsPermissionsRequirement
{
public function testRequiresPermission();
}

View file

@ -0,0 +1,77 @@
<?php
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteAccessoriesTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$accessory = Accessory::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.accessories.destroy', $accessory))
->assertForbidden();
$this->assertNotSoftDeleted($accessory);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryA = Accessory::factory()->for($companyA)->create();
$accessoryB = Accessory::factory()->for($companyB)->create();
$accessoryC = Accessory::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteAccessories()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteAccessories()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.accessories.destroy', $accessoryB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.accessories.destroy', $accessoryA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.accessories.destroy', $accessoryC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($accessoryA);
$this->assertNotSoftDeleted($accessoryB);
$this->assertSoftDeleted($accessoryC);
}
public function testCannotDeleteAccessoryThatHasCheckouts()
{
$accessory = Accessory::factory()->checkedOutToUser()->create();
$this->actingAsForApi(User::factory()->deleteAccessories()->create())
->deleteJson(route('api.accessories.destroy', $accessory))
->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($accessory);
}
public function testCanDeleteAccessory()
{
$accessory = Accessory::factory()->create();
$this->actingAsForApi(User::factory()->deleteAccessories()->create())
->deleteJson(route('api.accessories.destroy', $accessory))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($accessory);
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\User;
use Tests\TestCase;
class DeleteAccessoryTest extends TestCase
{
public function testPermissionRequiredToDeleteAccessory()
{
$accessory = Accessory::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.accessories.destroy', $accessory))
->assertForbidden();
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Tests\Feature\AssetMaintenances\Api;
use App\Models\AssetMaintenance;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteAssetMaintenancesTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$assetMaintenance = AssetMaintenance::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.maintenances.destroy', $assetMaintenance))
->assertForbidden();
$this->assertNotSoftDeleted($assetMaintenance);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$assetMaintenanceA = AssetMaintenance::factory()->create();
$assetMaintenanceB = AssetMaintenance::factory()->create();
$assetMaintenanceC = AssetMaintenance::factory()->create();
$assetMaintenanceA->asset->update(['company_id' => $companyA->id]);
$assetMaintenanceB->asset->update(['company_id' => $companyB->id]);
$assetMaintenanceC->asset->update(['company_id' => $companyB->id]);
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->editAssets()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->editAssets()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.maintenances.destroy', $assetMaintenanceB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.maintenances.destroy', $assetMaintenanceA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.maintenances.destroy', $assetMaintenanceC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($assetMaintenanceA);
$this->assertNotSoftDeleted($assetMaintenanceB);
$this->assertSoftDeleted($assetMaintenanceC);
}
public function testCanDeleteAssetMaintenance()
{
$assetMaintenance = AssetMaintenance::factory()->create();
$this->actingAsForApi(User::factory()->editAssets()->create())
->deleteJson(route('api.maintenances.destroy', $assetMaintenance))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($assetMaintenance);
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace Tests\Feature\AssetModels\Api;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteAssetModelsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$assetModel = AssetModel::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.models.destroy', $assetModel))
->assertForbidden();
$this->assertNotSoftDeleted($assetModel);
}
public function testCannotDeleteAssetModelThatStillHasAssociatedAssets()
{
$assetModel = Asset::factory()->create()->model;
$this->actingAsForApi(User::factory()->deleteAssetModels()->create())
->deleteJson(route('api.models.destroy', $assetModel))
->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($assetModel);
}
public function testCanDeleteAssetModel()
{
$assetModel = AssetModel::factory()->create();
$this->actingAsForApi(User::factory()->deleteAssetModels()->create())
->deleteJson(route('api.models.destroy', $assetModel))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($assetModel);
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace Tests\Feature\Assets\Api;
use App\Models\Asset;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteAssetsTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$asset = Asset::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.assets.destroy', $asset))
->assertForbidden();
$this->assertNotSoftDeleted($asset);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$assetA = Asset::factory()->for($companyA)->create();
$assetB = Asset::factory()->for($companyB)->create();
$assetC = Asset::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteAssets()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteAssets()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.assets.destroy', $assetB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.assets.destroy', $assetA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.assets.destroy', $assetC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($assetA);
$this->assertNotSoftDeleted($assetB);
$this->assertSoftDeleted($assetC);
}
public function testCannotDeleteAssetThatIsCheckedOut()
{
$this->markTestSkipped('This behavior is not functioning yet.');
}
public function testCanDeleteAsset()
{
$asset = Asset::factory()->create();
$this->actingAsForApi(User::factory()->deleteAssets()->create())
->deleteJson(route('api.assets.destroy', $asset))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($asset);
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace Tests\Feature\Categories\Api;
use App\Models\Asset;
use App\Models\Category;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteCategoriesTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$category = Category::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.categories.destroy', $category))
->assertForbidden();
$this->assertNotSoftDeleted($category);
}
public function testCannotDeleteCategoryThatStillHasAssociatedItems()
{
$asset = Asset::factory()->create();
$category = $asset->model->category;
$this->actingAsForApi(User::factory()->deleteCategories()->create())
->deleteJson(route('api.categories.destroy', $category))
->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($category);
}
public function testCanDeleteCategory()
{
$category = Category::factory()->create();
$this->actingAsForApi(User::factory()->deleteCategories()->create())
->deleteJson(route('api.categories.destroy', $category))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($category);
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Tests\Feature\Companies\Api;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteCompaniesTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$company = Company::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.companies.destroy', $company))
->assertForbidden();
$this->assertDatabaseHas('companies', ['id' => $company->id]);
}
public function testCannotDeleteCompanyThatHasAssociatedItems()
{
$companyWithAssets = Company::factory()->hasAssets()->create();
$companyWithAccessories = Company::factory()->hasAccessories()->create();
$companyWithConsumables = Company::factory()->hasConsumables()->create();
$companyWithComponents = Company::factory()->hasComponents()->create();
$companyWithUsers = Company::factory()->hasUsers()->create();
$actor = $this->actingAsForApi(User::factory()->deleteCompanies()->create());
$actor->deleteJson(route('api.companies.destroy', $companyWithAssets))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.companies.destroy', $companyWithAccessories))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.companies.destroy', $companyWithConsumables))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.companies.destroy', $companyWithComponents))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.companies.destroy', $companyWithUsers))->assertStatusMessageIs('error');
$this->assertDatabaseHas('companies', ['id' => $companyWithAssets->id]);
$this->assertDatabaseHas('companies', ['id' => $companyWithAccessories->id]);
$this->assertDatabaseHas('companies', ['id' => $companyWithConsumables->id]);
$this->assertDatabaseHas('companies', ['id' => $companyWithComponents->id]);
$this->assertDatabaseHas('companies', ['id' => $companyWithUsers->id]);
}
public function testCanDeleteCompany()
{
$company = Company::factory()->create();
$this->actingAsForApi(User::factory()->deleteCompanies()->create())
->deleteJson(route('api.companies.destroy', $company))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('companies', ['id' => $company->id]);
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace Tests\Feature\Components\Api;
use App\Models\Company;
use App\Models\Component;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteComponentsTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$component = Component::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.components.destroy', $component))
->assertForbidden();
$this->assertNotSoftDeleted($component);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$componentA = Component::factory()->for($companyA)->create();
$componentB = Component::factory()->for($companyB)->create();
$componentC = Component::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteComponents()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteComponents()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.components.destroy', $componentB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.components.destroy', $componentA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.components.destroy', $componentC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($componentA);
$this->assertNotSoftDeleted($componentB);
$this->assertSoftDeleted($componentC);
}
public function testCanDeleteComponents()
{
$component = Component::factory()->create();
$this->actingAsForApi(User::factory()->deleteComponents()->create())
->deleteJson(route('api.components.destroy', $component))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($component);
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace Tests\Feature\Consumables\Api;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteConsumablesTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$consumable = Consumable::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.consumables.destroy', $consumable))
->assertForbidden();
$this->assertNotSoftDeleted($consumable);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$consumableA = Consumable::factory()->for($companyA)->create();
$consumableB = Consumable::factory()->for($companyB)->create();
$consumableC = Consumable::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteConsumables()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteConsumables()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.consumables.destroy', $consumableB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.consumables.destroy', $consumableA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.consumables.destroy', $consumableC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($consumableA);
$this->assertNotSoftDeleted($consumableB);
$this->assertSoftDeleted($consumableC);
}
public function testCanDeleteConsumables()
{
$consumable = Consumable::factory()->create();
$this->actingAsForApi(User::factory()->deleteConsumables()->create())
->deleteJson(route('api.consumables.destroy', $consumable))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($consumable);
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace Tests\Feature\CustomFields\Api;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteCustomFieldsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customField = CustomField::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.customfields.destroy', $customField))
->assertForbidden();
$this->assertDatabaseHas('custom_fields', ['id' => $customField->id]);
}
public function testCustomFieldsCannotBeDeletedIfTheyHaveAssociatedFieldsets()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customField = CustomField::factory()->create();
$customFieldset = CustomFieldset::factory()->create();
$customField->fieldset()->attach($customFieldset, ['order' => 1, 'required' => 'false']);
$this->actingAsForApi(User::factory()->deleteCustomFields()->create())
->deleteJson(route('api.customfields.destroy', $customField))
->assertStatusMessageIs('error');
$this->assertDatabaseHas('custom_fields', ['id' => $customField->id]);
}
public function testCustomFieldsCanBeDeleted()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customField = CustomField::factory()->create();
$this->actingAsForApi(User::factory()->deleteCustomFields()->create())
->deleteJson(route('api.customfields.destroy', $customField))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('custom_fields', ['id' => $customField->id]);
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace Tests\Feature\CustomFieldsets\Api;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteCustomFieldsetsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customFieldset = CustomFieldset::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.fieldsets.destroy', $customFieldset))
->assertForbidden();
$this->assertDatabaseHas('custom_fieldsets', ['id' => $customFieldset->id]);
}
public function testCannotDeleteCustomFieldsetWithAssociatedFields()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customField = CustomField::factory()->create();
$customFieldset = CustomFieldset::factory()->create();
$customField->fieldset()->attach($customFieldset, ['order' => 1, 'required' => 'false']);
$this->actingAsForApi(User::factory()->deleteCustomFieldsets()->create())
->deleteJson(route('api.fieldsets.destroy', $customFieldset))
->assertStatusMessageIs('error');
$this->assertDatabaseHas('custom_fieldsets', ['id' => $customFieldset->id]);
}
public function testCannotDeleteCustomFieldsetWithAssociatedModels()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customFieldset = CustomFieldset::factory()->hasModels()->create();
$this->actingAsForApi(User::factory()->deleteCustomFieldsets()->create())
->deleteJson(route('api.fieldsets.destroy', $customFieldset))
->assertStatusMessageIs('error');
$this->assertDatabaseHas('custom_fieldsets', ['id' => $customFieldset->id]);
}
public function testCanDeleteCustomFieldsets()
{
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
$customFieldset = CustomFieldset::factory()->create();
$this->actingAsForApi(User::factory()->deleteCustomFieldsets()->create())
->deleteJson(route('api.fieldsets.destroy', $customFieldset))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('custom_fieldsets', ['id' => $customFieldset->id]);
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace Tests\Feature\Departments\Api;
use App\Models\Company;
use App\Models\Department;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteDepartmentsTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$department = Department::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.departments.destroy', $department))
->assertForbidden();
$this->assertDatabaseHas('departments', ['id' => $department->id]);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$departmentA = Department::factory()->for($companyA)->create();
$departmentB = Department::factory()->for($companyB)->create();
$departmentC = Department::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteDepartments()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteDepartments()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.departments.destroy', $departmentB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.departments.destroy', $departmentA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.departments.destroy', $departmentC))
->assertStatusMessageIs('success');
$this->assertDatabaseHas('departments', ['id' => $departmentA->id]);
$this->assertDatabaseHas('departments', ['id' => $departmentB->id]);
$this->assertDatabaseMissing('departments', ['id' => $departmentC->id]);
}
public function testCannotDeleteDepartmentThatStillHasUsers()
{
$department = Department::factory()->hasUsers()->create();
$this->actingAsForApi(User::factory()->deleteDepartments()->create())
->deleteJson(route('api.departments.destroy', $department))
->assertStatusMessageIs('error');
$this->assertDatabaseHas('departments', ['id' => $department->id]);
}
public function testCanDeleteDepartment()
{
$department = Department::factory()->create();
$this->actingAsForApi(User::factory()->deleteDepartments()->create())
->deleteJson(route('api.departments.destroy', $department))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('departments', ['id' => $department->id]);
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Tests\Feature\Depreciations\Api;
use App\Models\Depreciation;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteDepreciationsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$depreciation = Depreciation::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.depreciations.destroy', $depreciation))
->assertForbidden();
$this->assertDatabaseHas('depreciations', ['id' => $depreciation->id]);
}
public function testCannotDeleteDepreciationThatHasAssociatedModels()
{
$depreciation = Depreciation::factory()->hasModels()->create();
$this->actingAsForApi(User::factory()->deleteDepreciations()->create())
->deleteJson(route('api.depreciations.destroy', $depreciation))
->assertStatusMessageIs('error');
$this->assertDatabaseHas('depreciations', ['id' => $depreciation->id]);
}
public function testCanDeleteDepreciation()
{
$depreciation = Depreciation::factory()->create();
$this->actingAsForApi(User::factory()->deleteDepreciations()->create())
->deleteJson(route('api.depreciations.destroy', $depreciation))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('depreciations', ['id' => $depreciation->id]);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Tests\Feature\Groups\Api;
use App\Models\Group;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteGroupsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$group = Group::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.groups.destroy', $group))
->assertForbidden();
$this->assertDatabaseHas('permission_groups', ['id' => $group->id]);
}
public function testCanDeleteGroup()
{
$group = Group::factory()->create();
// only super admins can delete groups
$this->actingAsForApi(User::factory()->superuser()->create())
->deleteJson(route('api.groups.destroy', $group))
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('permission_groups', ['id' => $group->id]);
}
}

View file

@ -0,0 +1,90 @@
<?php
namespace Tests\Feature\Licenses\Api;
use App\Models\Company;
use App\Models\License;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteLicensesTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$license = License::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.licenses.destroy', $license))
->assertForbidden();
$this->assertNotSoftDeleted($license);
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$licenseA = License::factory()->for($companyA)->create();
$licenseB = License::factory()->for($companyB)->create();
$licenseC = License::factory()->for($companyB)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->deleteLicenses()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->deleteLicenses()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->deleteJson(route('api.licenses.destroy', $licenseB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->deleteJson(route('api.licenses.destroy', $licenseA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superUser)
->deleteJson(route('api.licenses.destroy', $licenseC))
->assertStatusMessageIs('success');
$this->assertNotSoftDeleted($licenseA);
$this->assertNotSoftDeleted($licenseB);
$this->assertSoftDeleted($licenseC);
}
public function testLicenseCannotBeDeletedIfStillAssigned()
{
$license = License::factory()->create(['seats' => 2]);
$license->freeSeat()->update(['assigned_to' => User::factory()->create()->id]);
$this->actingAsForApi(User::factory()->deleteLicenses()->create())
->deleteJson(route('api.licenses.destroy', $license))
->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($license);
}
public function testCanDeleteLicense()
{
$license = License::factory()->create();
$this->actingAsForApi(User::factory()->deleteLicenses()->create())
->deleteJson(route('api.licenses.destroy', $license))
->assertStatusMessageIs('success');
$this->assertSoftDeleted($license);
}
public function testLicenseSeatsAreDeletedWhenLicenseIsDeleted()
{
$license = License::factory()->create(['seats' => 2]);
$this->assertTrue($license->fresh()->licenseseats->isNotEmpty(), 'License seats not created like expected');
$this->actingAsForApi(User::factory()->deleteLicenses()->create())
->deleteJson(route('api.licenses.destroy', $license));
$this->assertTrue($license->fresh()->licenseseats->isEmpty());
}
}

View file

@ -5,10 +5,21 @@ namespace Tests\Feature\Locations\Api;
use App\Models\Asset;
use App\Models\Location;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteLocationsTest extends TestCase
class DeleteLocationsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$location = Location::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.locations.destroy', $location))
->assertForbidden();
$this->assertNotSoftDeleted($location);
}
public function testErrorReturnedViaApiIfLocationDoesNotExist()
{
@ -90,4 +101,15 @@ class DeleteLocationsTest extends TestCase
->json();
}
public function testCanDeleteLocation()
{
$location = Location::factory()->create();
$this->actingAsForApi(User::factory()->deleteLocations()->create())
->deleteJson(route('api.locations.destroy', $location->id))
->assertOk()
->assertStatusMessageIs('success');
$this->assertSoftDeleted($location);
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace Tests\Feature\Manufacturers\Api;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Manufacturer;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteManufacturersTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$manufacturer = Manufacturer::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.manufacturers.destroy', $manufacturer))
->assertForbidden();
$this->assertNotSoftDeleted($manufacturer);
}
public function testCannotDeleteManufacturerWithAssociatedData()
{
$manufacturerWithAccessories = Manufacturer::factory()->hasAccessories()->create();
$manufacturerWithConsumables = Manufacturer::factory()->hasConsumables()->create();
$manufacturerWithLicenses = Manufacturer::factory()->hasLicenses()->create();
$manufacturerWithAssets = Manufacturer::factory()->hasAssets()->create();
$model = AssetModel::factory()->create(['manufacturer_id' => $manufacturerWithAssets->id]);
Asset::factory()->create(['model_id' => $model->id]);
$this->assertGreaterThan(0, $manufacturerWithAccessories->accessories->count(), 'Precondition failed: Manufacturer has no accessories');
$this->assertGreaterThan(0, $manufacturerWithAssets->assets->count(), 'Precondition failed: Manufacturer has no assets');
$this->assertGreaterThan(0, $manufacturerWithConsumables->consumables->count(), 'Precondition failed: Manufacturer has no consumables');
$this->assertGreaterThan(0, $manufacturerWithLicenses->licenses->count(), 'Precondition failed: Manufacturer has no licenses');
$actor = $this->actingAsForApi(User::factory()->deleteManufacturers()->create());
$actor->deleteJson(route('api.manufacturers.destroy', $manufacturerWithAccessories))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.manufacturers.destroy', $manufacturerWithAssets))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.manufacturers.destroy', $manufacturerWithConsumables))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.manufacturers.destroy', $manufacturerWithLicenses))->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($manufacturerWithAssets);
$this->assertNotSoftDeleted($manufacturerWithAccessories);
$this->assertNotSoftDeleted($manufacturerWithConsumables);
$this->assertNotSoftDeleted($manufacturerWithLicenses);
}
public function testCanDeleteManufacturer()
{
$manufacturer = Manufacturer::factory()->create();
$this->actingAsForApi(User::factory()->deleteManufacturers()->create())
->deleteJson(route('api.manufacturers.destroy', $manufacturer))
->assertOk()
->assertStatusMessageIs('success');
$this->assertSoftDeleted($manufacturer);
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace Tests\Feature\PredefinedKits\Api;
use App\Models\PredefinedKit;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeletePredefinedKitsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$predefinedKit = PredefinedKit::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.kits.destroy', $predefinedKit))
->assertForbidden();
$this->assertDatabaseHas('kits', ['id' => $predefinedKit->id]);
}
public function testCanDeletePredefinedKits()
{
$predefinedKit = PredefinedKit::factory()->create();
$this->actingAsForApi(User::factory()->deletePredefinedKits()->create())
->deleteJson(route('api.kits.destroy', $predefinedKit))
->assertOk()
->assertStatusMessageIs('success');
$this->assertDatabaseMissing('kits', ['id' => $predefinedKit->id]);
}
public function testAssociatedDataDetachedWhenPredefinedKitDeleted()
{
$predefinedKit = PredefinedKit::factory()
->hasAccessories()
->hasConsumables()
->hasLicenses()
->hasModels()
->create();
$this->assertGreaterThan(0, $predefinedKit->accessories->count(), 'Precondition failed: PredefinedKit has no accessories');
$this->assertGreaterThan(0, $predefinedKit->consumables->count(), 'Precondition failed: PredefinedKit has no consumables');
$this->assertGreaterThan(0, $predefinedKit->licenses->count(), 'Precondition failed: PredefinedKit has no licenses');
$this->assertGreaterThan(0, $predefinedKit->models->count(), 'Precondition failed: PredefinedKit has no models');
$this->actingAsForApi(User::factory()->deletePredefinedKits()->create())
->deleteJson(route('api.kits.destroy', $predefinedKit))
->assertStatusMessageIs('success');
$this->assertEquals(0, DB::table('kits_accessories')->where('kit_id', $predefinedKit->id)->count());
$this->assertEquals(0, DB::table('kits_consumables')->where('kit_id', $predefinedKit->id)->count());
$this->assertEquals(0, DB::table('kits_licenses')->where('kit_id', $predefinedKit->id)->count());
$this->assertEquals(0, DB::table('kits_models')->where('kit_id', $predefinedKit->id)->count());
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace Tests\Feature\StatusLabels\Api;
use App\Models\Statuslabel;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteStatusLabelsTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$statusLabel = Statuslabel::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.statuslabels.destroy', $statusLabel))
->assertForbidden();
$this->assertNotSoftDeleted($statusLabel);
}
public function testCannotDeleteStatusLabelWhileStillAssociatedToAssets()
{
$statusLabel = Statuslabel::factory()->hasAssets()->create();
$this->assertGreaterThan(0, $statusLabel->assets->count(), 'Precondition failed: StatusLabel has no assets');
$this->actingAsForApi(User::factory()->deleteStatusLabels()->create())
->deleteJson(route('api.statuslabels.destroy', $statusLabel))
->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($statusLabel);
}
public function testCanDeleteStatusLabel()
{
$statusLabel = Statuslabel::factory()->create();
$this->actingAsForApi(User::factory()->deleteStatusLabels()->create())
->deleteJson(route('api.statuslabels.destroy', $statusLabel))
->assertOk()
->assertStatusMessageIs('success');
$this->assertSoftDeleted($statusLabel);
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Tests\Feature\Suppliers\Api;
use App\Models\AssetMaintenance;
use App\Models\Supplier;
use App\Models\User;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteSuppliersTest extends TestCase implements TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$supplier = Supplier::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.suppliers.destroy', $supplier))
->assertForbidden();
$this->assertNotSoftDeleted($supplier);
}
public function testCannotDeleteSupplierWithDataStillAssociated()
{
$supplierWithAsset = Supplier::factory()->hasAssets()->create();
$supplierWithAssetMaintenance = Supplier::factory()->has(AssetMaintenance::factory(), 'asset_maintenances')->create();
$supplierWithLicense = Supplier::factory()->hasLicenses()->create();
$actor = $this->actingAsForApi(User::factory()->deleteSuppliers()->create());
$actor->deleteJson(route('api.suppliers.destroy', $supplierWithAsset))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.suppliers.destroy', $supplierWithAssetMaintenance))->assertStatusMessageIs('error');
$actor->deleteJson(route('api.suppliers.destroy', $supplierWithLicense))->assertStatusMessageIs('error');
$this->assertNotSoftDeleted($supplierWithAsset);
$this->assertNotSoftDeleted($supplierWithAssetMaintenance);
$this->assertNotSoftDeleted($supplierWithLicense);
}
public function testCanDeleteSupplier()
{
$supplier = Supplier::factory()->create();
$this->actingAsForApi(User::factory()->deleteSuppliers()->create())
->deleteJson(route('api.suppliers.destroy', $supplier))
->assertOk()
->assertStatusMessageIs('success');
$this->assertSoftDeleted($supplier);
}
}

View file

@ -6,11 +6,22 @@ use App\Models\Company;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class DeleteUserTest extends TestCase
class DeleteUsersTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$user = User::factory()->create();
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.users.destroy', $user))
->assertForbidden();
$this->assertNotSoftDeleted($user);
}
public function testErrorReturnedViaApiIfUserDoesNotExist()
{
@ -33,7 +44,6 @@ class DeleteUserTest extends TestCase
->json();
}
public function testDisallowUserDeletionViaApiIfStillManagingPeople()
{
$manager = User::factory()->create();
@ -78,26 +88,19 @@ class DeleteUserTest extends TestCase
->json();
}
public function testDeniedPermissionsForDeletingUserViaApi()
public function testUsersCannotDeleteThemselves()
{
$this->actingAsForApi(User::factory()->create())
->deleteJson(route('api.users.destroy', User::factory()->create()))
->assertStatus(403)
->json();
}
public function testSuccessPermissionsForDeletingUserViaApi()
{
$this->actingAsForApi(User::factory()->deleteUsers()->create())
->deleteJson(route('api.users.destroy', User::factory()->create()))
$user = User::factory()->deleteUsers()->create();
$this->actingAsForApi($user)
->deleteJson(route('api.users.destroy', $user))
->assertOk()
->assertStatus(200)
->assertStatusMessageIs('success')
->assertStatusMessageIs('error')
->json();
}
public function testPermissionsForDeletingIfNotInSameCompanyAndNotSuperadmin()
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
$this->settings->enableMultipleFullCompanySupport();
@ -136,20 +139,17 @@ class DeleteUserTest extends TestCase
$userFromA->refresh();
$this->assertNotNull($userFromA->deleted_at);
}
public function testUsersCannotDeleteThemselves()
public function testCanDeleteUser()
{
$user = User::factory()->deleteUsers()->create();
$this->actingAsForApi($user)
$user = User::factory()->create();
$this->actingAsForApi(User::factory()->deleteUsers()->create())
->deleteJson(route('api.users.destroy', $user))
->assertOk()
->assertStatus(200)
->assertStatusMessageIs('error')
->json();
->assertStatusMessageIs('success');
$this->assertSoftDeleted($user);
}
}