Added #18767 - uploads for companies and departments
This commit is contained in:
@@ -9,7 +9,6 @@ use App\Models\Actionlog;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace App\Http\Controllers;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Department;
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
@@ -46,6 +48,8 @@ abstract class Controller extends BaseController
|
||||
|
||||
public static $map_object_type = [
|
||||
'accessories' => Accessory::class,
|
||||
'companies' => Company::class,
|
||||
'departments' => Department::class,
|
||||
'maintenances' => Maintenance::class,
|
||||
'assets' => Asset::class,
|
||||
'audits' => Asset::class,
|
||||
@@ -64,6 +68,8 @@ abstract class Controller extends BaseController
|
||||
'maintenances' => 'private_uploads/maintenances/',
|
||||
'assets' => 'private_uploads/assets/',
|
||||
'audits' => 'private_uploads/audits/',
|
||||
'departments' => 'private_uploads/departments/',
|
||||
'companies' => 'private_uploads/companies/',
|
||||
'components' => 'private_uploads/components/',
|
||||
'consumables' => 'private_uploads/consumables/',
|
||||
'hardware' => 'private_uploads/assets/',
|
||||
@@ -79,6 +85,8 @@ abstract class Controller extends BaseController
|
||||
'maintenances' => 'maintenance',
|
||||
'assets' => 'asset',
|
||||
'audits' => 'audits',
|
||||
'companies' => 'company',
|
||||
'departments' => 'department',
|
||||
'components' => 'component',
|
||||
'consumables' => 'consumable',
|
||||
'hardware' => 'asset',
|
||||
|
||||
@@ -423,40 +423,23 @@ class Actionlog extends SnipeModel
|
||||
/**
|
||||
* Calculate the date of the next audit
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @return Datetime | string
|
||||
*
|
||||
* @since [v4.0]
|
||||
*
|
||||
* @return \Datetime
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function calcNextAuditDate($monthInterval = 12, $asset = null)
|
||||
{
|
||||
$last_audit_date = Carbon::parse($this->created_at);
|
||||
// If there is an asset-specific next date already given,
|
||||
if (($asset) && ($asset->next_audit_date)) {
|
||||
return \Carbon::parse($asset->next_audit_date);
|
||||
return Carbon::parse($asset->next_audit_date);
|
||||
}
|
||||
|
||||
return \Carbon::parse($last_audit_date)->addMonths($monthInterval)->toDateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets action logs in chronological order, excluding uploads
|
||||
*
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
*
|
||||
* @since v1.0
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getListingOfActionLogsChronologicalOrder()
|
||||
{
|
||||
return $this->all()
|
||||
->where('action_type', '!=', 'uploaded')
|
||||
->orderBy('item_id', 'asc')
|
||||
->orderBy('created_at', 'asc')
|
||||
->get();
|
||||
return Carbon::parse($last_audit_date)->addMonths($monthInterval)->toDateString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines what the type of request is so we can log it to the action_log
|
||||
@@ -553,8 +536,12 @@ class Actionlog extends SnipeModel
|
||||
return 'private_uploads/assets/'.$this->filename;
|
||||
case AssetModel::class:
|
||||
return 'private_uploads/models/'.$this->filename;
|
||||
case Company::class:
|
||||
return 'private_uploads/companies/' . $this->filename;
|
||||
case Consumable::class:
|
||||
return 'private_uploads/consumables/'.$this->filename;
|
||||
case Department::class:
|
||||
return 'private_uploads/departments/' . $this->filename;
|
||||
case Component::class:
|
||||
return 'private_uploads/components/'.$this->filename;
|
||||
case License::class:
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Loggable;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\CompanyPresenter;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -22,6 +25,9 @@ final class Company extends SnipeModel
|
||||
{
|
||||
use CompanyableTrait;
|
||||
use HasFactory;
|
||||
use HasUploads;
|
||||
use SoftDeletes;
|
||||
use Loggable;
|
||||
|
||||
protected $table = 'companies';
|
||||
|
||||
|
||||
@@ -4,11 +4,14 @@ namespace App\Models;
|
||||
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Loggable;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\DepartmentPresenter;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
@@ -17,6 +20,9 @@ class Department extends SnipeModel
|
||||
{
|
||||
use CompanyableTrait;
|
||||
use HasFactory;
|
||||
use HasUploads;
|
||||
use Loggable;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* Whether the model should inject it's identifier to the unique
|
||||
|
||||
@@ -112,6 +112,24 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
return 'locations/';
|
||||
});
|
||||
|
||||
// Companies
|
||||
app()->singleton('companies_upload_path', function () {
|
||||
return 'companies/';
|
||||
});
|
||||
|
||||
app()->singleton('companies_upload_url', function () {
|
||||
return 'companies/';
|
||||
});
|
||||
|
||||
// Departments
|
||||
app()->singleton('departments_upload_path', function () {
|
||||
return 'departments/';
|
||||
});
|
||||
|
||||
app()->singleton('departments_upload_url', function () {
|
||||
return 'departments/';
|
||||
});
|
||||
|
||||
// Users
|
||||
app()->singleton('users_upload_path', function () {
|
||||
return 'avatars/';
|
||||
@@ -157,6 +175,7 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
return 'companies/';
|
||||
});
|
||||
|
||||
|
||||
// Accessories paths and URLs
|
||||
app()->singleton('accessories_upload_path', function () {
|
||||
return 'accessories/';
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('companies', function (Blueprint $table) {
|
||||
$table->softDeletes();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
@@ -16,15 +16,22 @@
|
||||
<x-page-column class="col-md-9 main-panel">
|
||||
<x-tabs>
|
||||
<x-slot:tabnav>
|
||||
<x-tabs.user-tab count="{{ $company->users->count() }}"/>
|
||||
<x-tabs.asset-tab count="{{ $company->assets()->AssetsForShow()->count() }}"/>
|
||||
<x-tabs.license-tab count="{{ $company->licenses->count() }}"/>
|
||||
<x-tabs.accessory-tab count="{{ $company->accessories->count() }}"/>
|
||||
<x-tabs.consumable-tab count="{{ $company->consumables->count() }}"/>
|
||||
<x-tabs.component-tab count="{{ $company->components->count() }}"/>
|
||||
<x-tabs.user-tab count="{{ $company->users->count() }}"/>
|
||||
<x-tabs.files-tab count="{{ $company->uploads()->count() }}"/>
|
||||
<x-tabs.upload-tab :item="$company"/>
|
||||
</x-slot:tabnav>
|
||||
|
||||
<x-slot:tabpanes>
|
||||
<!-- start users tab pane -->
|
||||
<x-tabs.pane name="users">
|
||||
<x-table.users name="users" :route="route('api.users.index', ['company_id' => $company->id])"/>
|
||||
</x-tabs.pane>
|
||||
<!-- end users tab pane -->
|
||||
|
||||
<!-- start assets tab pane -->
|
||||
<x-tabs.pane name="assets">
|
||||
@@ -55,11 +62,11 @@
|
||||
<x-table.components name="components" :route="route('api.components.index', ['company_id' => $company->id])"/>
|
||||
</x-tabs.pane>
|
||||
|
||||
<!-- start users tab pane -->
|
||||
<x-tabs.pane name="users">
|
||||
<x-table.users name="users" :route="route('api.users.index', ['company_id' => $company->id])"/>
|
||||
<!-- start files tab pane -->
|
||||
<x-tabs.pane name="files">
|
||||
<x-table.files object_type="companies" :object="$company"/>
|
||||
</x-tabs.pane>
|
||||
<!-- end users tab pane -->
|
||||
<!-- end files tab pane -->
|
||||
|
||||
</x-slot:tabpanes>
|
||||
|
||||
@@ -81,6 +88,11 @@
|
||||
</x-container>
|
||||
|
||||
|
||||
@can('update', Company::class)
|
||||
@section('moar_scripts')
|
||||
@include ('modals.upload-file', ['item_type' => 'companies', 'item_id' => $company->id])
|
||||
@endsection
|
||||
@endcan
|
||||
|
||||
@stop
|
||||
@section('moar_scripts')
|
||||
|
||||
@@ -16,42 +16,51 @@
|
||||
@section('content')
|
||||
<x-container columns="2">
|
||||
<x-page-column class="col-md-9 main-panel">
|
||||
<x-box>
|
||||
<x-tabs>
|
||||
<x-slot:tabnav>
|
||||
<x-tabs.user-tab count="{{ $department->users->count() }}"/>
|
||||
<x-tabs.files-tab count="{{ $department->uploads()->count() }}"/>
|
||||
<x-tabs.upload-tab :item="$department"/>
|
||||
</x-slot:tabnav>
|
||||
|
||||
<x-slot:bulkactions>
|
||||
<x-table.bulk-users />
|
||||
</x-slot:bulkactions>
|
||||
<x-slot:tabpanes>
|
||||
<!-- start users tab pane -->
|
||||
<x-tabs.pane name="users">
|
||||
<x-table.users name="users" :route="route('api.users.index', ['department+id' => $department->id])"/>
|
||||
</x-tabs.pane>
|
||||
<!-- end users tab pane -->
|
||||
|
||||
<x-table
|
||||
show_column_search="true"
|
||||
show_advanced_search="true"
|
||||
fixed_right_number="1"
|
||||
fixed_number="2"
|
||||
buttons="licenseButtons"
|
||||
api_url="{{ route('api.users.index', ['department_id' => $department->id]) }}"
|
||||
:presenter="\App\Presenters\UserPresenter::dataTableLayout()"
|
||||
export_filename="export-{{ str_slug($department->name) }}-users-{{ date('Y-m-d') }}"
|
||||
/>
|
||||
</x-box>
|
||||
<!-- start files tab pane -->
|
||||
<x-tabs.pane name="files">
|
||||
<x-table.files object_type="departments" :object="$department"/>
|
||||
</x-tabs.pane>
|
||||
<!-- end files tab pane -->
|
||||
|
||||
</x-slot:tabpanes>
|
||||
|
||||
</x-tabs>
|
||||
|
||||
</x-page-column>
|
||||
|
||||
<x-page-column class="col-md-3">
|
||||
<x-box class="side-box expanded">
|
||||
<x-info-panel :infoPanelObj="$department" img_path="{{ app('users_upload_url') }}">
|
||||
<x-info-panel :infoPanelObj="$department" img_path="{{ app('departments_upload_url') }}">
|
||||
|
||||
<x-slot:buttons>
|
||||
<x-button.edit :item="$department" :route="route('departments.edit', $department->id)" />
|
||||
<x-button.delete :item="$department" />
|
||||
<x-button.edit :item="$department" :route="route('departments.edit', $department->id)"/>
|
||||
<x-button.delete :item="$department"/>
|
||||
</x-slot:buttons>
|
||||
|
||||
</x-info-panel>
|
||||
</x-box>
|
||||
</x-page-column>
|
||||
|
||||
|
||||
</x-container>
|
||||
|
||||
@can('update', Department::class)
|
||||
@section('moar_scripts')
|
||||
@include ('modals.upload-file', ['item_type' => 'departments', 'item_id' => $department->id])
|
||||
@endsection
|
||||
@endcan
|
||||
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<x-tabs.files-tab count="{{ $location->uploads()->count() }}"/>
|
||||
<x-tabs.history-tab count="{{ $location->history()->count() }}" :model="$location"/>
|
||||
<x-tabs.upload-tab count="{{ $location->uploads()->count() }}" :item="$location"/>
|
||||
<x-tabs.upload-tab :item="$location"/>
|
||||
|
||||
</x-slot:tabnav>
|
||||
|
||||
|
||||
+4
-4
@@ -1352,7 +1352,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
|
||||
'index',
|
||||
]
|
||||
)->name('api.files.index')
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users']);
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users|companies|departments']);
|
||||
|
||||
// Get a file
|
||||
Route::get('{object_type}/{id}/files/{file_id}',
|
||||
@@ -1361,7 +1361,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
|
||||
'show',
|
||||
]
|
||||
)->name('api.files.show')
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users']);
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users|companies|departments']);
|
||||
|
||||
// Upload files(s)
|
||||
Route::post('{object_type}/{id}/files',
|
||||
@@ -1370,7 +1370,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
|
||||
'store',
|
||||
]
|
||||
)->name('api.files.store')
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users']);
|
||||
->where(['object_type' => 'accessories|audits|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users|companies|departments']);
|
||||
|
||||
// Delete files(s)
|
||||
Route::delete('{object_type}/{id}/files/{file_id}/delete',
|
||||
@@ -1379,6 +1379,6 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu
|
||||
'destroy',
|
||||
]
|
||||
)->name('api.files.destroy')
|
||||
->where(['object_type' => 'accessories|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users']);
|
||||
->where(['object_type' => 'accessories|assets|components|consumables|hardware|licenses|locations|maintenances|models|suppliers|users|companies|departments']);
|
||||
|
||||
}); // end API routes
|
||||
|
||||
+3
-3
@@ -738,7 +738,7 @@ Route::group(['middleware' => 'web'], function () {
|
||||
'show'
|
||||
]
|
||||
)->name('ui.files.show')
|
||||
->where(['object_type' => 'assets|audits|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components']);
|
||||
->where(['object_type' => 'assets|audits|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components|companies|departments']);
|
||||
|
||||
// Upload files(s)
|
||||
Route::post('{object_type}/{id}/files',
|
||||
@@ -747,7 +747,7 @@ Route::group(['middleware' => 'web'], function () {
|
||||
'store'
|
||||
]
|
||||
)->name('ui.files.store')
|
||||
->where(['object_type' => 'assets|audits|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components']);
|
||||
->where(['object_type' => 'assets|audits|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components|companies|departments']);
|
||||
|
||||
// Delete files(s)
|
||||
Route::delete('{object_type}/{id}/files/{file_id}/delete',
|
||||
@@ -756,7 +756,7 @@ Route::group(['middleware' => 'web'], function () {
|
||||
'destroy'
|
||||
]
|
||||
)->name('ui.files.destroy')
|
||||
->where(['object_type' => 'assets|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components']);
|
||||
->where(['object_type' => 'assets|maintenances|hardware|models|users|locations|accessories|consumables|licenses|suppliers|components|companies|departments']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -51,7 +51,7 @@ class DeleteCompaniesTest extends TestCase implements TestsPermissionsRequiremen
|
||||
->deleteJson(route('api.companies.destroy', $company))
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertDatabaseMissing('companies', ['id' => $company->id]);
|
||||
$this->assertSoftDeleted($company);
|
||||
}
|
||||
|
||||
public function test_adheres_to_full_multiple_companies_support_scoping()
|
||||
|
||||
@@ -50,7 +50,7 @@ class DeleteDepartmentsTest extends TestCase implements TestsFullMultipleCompani
|
||||
|
||||
$this->assertDatabaseHas('departments', ['id' => $departmentA->id]);
|
||||
$this->assertDatabaseHas('departments', ['id' => $departmentB->id]);
|
||||
$this->assertDatabaseMissing('departments', ['id' => $departmentC->id]);
|
||||
$this->assertSoftDeleted($departmentC);
|
||||
}
|
||||
|
||||
public function test_cannot_delete_department_that_still_has_users()
|
||||
@@ -72,6 +72,6 @@ class DeleteDepartmentsTest extends TestCase implements TestsFullMultipleCompani
|
||||
->deleteJson(route('api.departments.destroy', $department))
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertDatabaseMissing('departments', ['id' => $department->id]);
|
||||
$this->assertSoftDeleted($department);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user