Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 664c793eff | |||
|
|
a4aab54735 | ||
| c9bd6664f2 | |||
|
|
59721337a8 | ||
|
|
c348af2484 | ||
|
|
e3c7bf711c | ||
|
|
7cb2f798d0 | ||
|
|
21521b384e | ||
|
|
0a2add800e | ||
|
|
fdbef3a5e8 | ||
|
|
becbf8aee2 | ||
|
|
df2f91cc57 | ||
|
|
1968c14f68 | ||
|
|
1e958c9dd7 | ||
|
|
8bd31cf54f | ||
|
|
6fae6928e7 | ||
|
|
a6c79c72b5 | ||
|
|
e9fa45a808 | ||
|
|
1007515faa | ||
|
|
33fe30b443 | ||
|
|
63f2ac25c9 | ||
|
|
3d88868da1 | ||
|
|
f7ae8ea294 | ||
|
|
b5c115a67e | ||
|
|
c76630a5ea | ||
|
|
5678255090 | ||
|
|
a2bff61998 | ||
|
|
f362bdd32f | ||
|
|
a25194dc07 | ||
|
|
b185a60b53 |
@@ -21,7 +21,8 @@ class PermissionExport implements WithColumnFormatting, WithHeadings, FromCollec
|
||||
}
|
||||
|
||||
public function map($row): array{
|
||||
$role = $row->roles->pluck('name')->toArray();
|
||||
// Convert the array to a collection before using pluck
|
||||
$role = collect($row->roles)->pluck('name')->toArray();
|
||||
return [
|
||||
$row->id,
|
||||
$row->name,
|
||||
|
||||
66
app/Exports/PositionExport.php
Normal file
66
app/Exports/PositionExport.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Modules\Usermanagement\Models\Position;
|
||||
|
||||
class PositionExport implements WithColumnFormatting, WithHeadings, FromCollection, WithMapping
|
||||
{
|
||||
protected $search;
|
||||
|
||||
public function __construct($search = null)
|
||||
{
|
||||
$this->search = $search;
|
||||
}
|
||||
|
||||
public function collection()
|
||||
{
|
||||
$query = Position::query();
|
||||
|
||||
if (!empty($this->search)) {
|
||||
$search = $this->search;
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->whereRaw('LOWER(code) LIKE ?', ['%' . strtolower($search) . '%'])
|
||||
->orWhereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%'])
|
||||
->orWhereRaw('CAST(level AS TEXT) LIKE ?', ['%' . $search . '%']);
|
||||
});
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function map($row): array
|
||||
{
|
||||
return [
|
||||
$row->id,
|
||||
$row->code,
|
||||
$row->name,
|
||||
$row->level,
|
||||
$row->created_at
|
||||
];
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'ID',
|
||||
'Code',
|
||||
'Name',
|
||||
'Tingkat Jabatan',
|
||||
'Created At'
|
||||
];
|
||||
}
|
||||
|
||||
public function columnFormats(): array
|
||||
{
|
||||
return [
|
||||
'A' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'D' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'E' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,15 @@ use Modules\Usermanagement\Models\Role;
|
||||
class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection, withMapping
|
||||
{
|
||||
public function collection(){
|
||||
return Role::all();
|
||||
return Role::with('position')->get();
|
||||
}
|
||||
|
||||
public function map($row): array{
|
||||
return [
|
||||
$row->id,
|
||||
$row->name,
|
||||
$row->position ? $row->position->name : '-',
|
||||
$row->position ? $row->position->level : '-',
|
||||
$row->created_at
|
||||
];
|
||||
}
|
||||
@@ -25,6 +27,8 @@ class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
return [
|
||||
'ID',
|
||||
'Role',
|
||||
'Position',
|
||||
'Tingkat Jabatan',
|
||||
'Created At'
|
||||
];
|
||||
}
|
||||
@@ -32,7 +36,8 @@ class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
public function columnFormats(): array{
|
||||
return [
|
||||
'A' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'C' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
'D' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'E' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,21 @@ use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
|
||||
class UsersExport implements WithColumnFormatting, WithHeadings, FromCollection, withMapping
|
||||
class UsersExport implements WithColumnFormatting, WithHeadings, FromCollection, WithMapping
|
||||
{
|
||||
protected $search;
|
||||
|
||||
public function __construct($search = null)
|
||||
{
|
||||
$this->search = $search;
|
||||
}
|
||||
|
||||
public function collection(){
|
||||
return User::all();
|
||||
return User::query()
|
||||
->when($this->search, function ($query) {
|
||||
$query->whereAny(['name','email'],'like','%'.$this->search.'%');
|
||||
})
|
||||
->get();
|
||||
}
|
||||
|
||||
public function map($row): array{
|
||||
@@ -21,7 +32,8 @@ class UsersExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
$row->name,
|
||||
$row->email,
|
||||
$row->nik,
|
||||
$row->branch->name,
|
||||
$row->branch?->name,
|
||||
$row->roles?->pluck('name')->implode(', '),
|
||||
$row->created_at
|
||||
];
|
||||
}
|
||||
@@ -32,6 +44,7 @@ class UsersExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
'Email',
|
||||
'NIK',
|
||||
'Branch',
|
||||
'Roles',
|
||||
'Created At'
|
||||
];
|
||||
}
|
||||
@@ -39,7 +52,7 @@ class UsersExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
public function columnFormats(): array{
|
||||
return [
|
||||
'A' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'F' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
'G' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
30
app/Helpers/RolePermission.php
Normal file
30
app/Helpers/RolePermission.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
if (!function_exists('check_permission')) {
|
||||
function check_permission(string $permission, bool $abort = true): bool
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (!$user || !$user->can($permission)) {
|
||||
if ($abort) {
|
||||
abort(403, 'Unauthorized');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('user_has_role')) {
|
||||
function user_has_role(array $roles): bool
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (!$user) return false;
|
||||
|
||||
return $user->roles->pluck('name')->intersect($roles)->isNotEmpty();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,24 @@
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public $user;
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UsersController constructor.
|
||||
*
|
||||
* Initializes the user property with the authenticated user.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Mengatur middleware auth
|
||||
$this->middleware('auth');
|
||||
|
||||
// Mengatur user setelah middleware auth dijalankan
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = Auth::user();
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
@@ -34,8 +51,8 @@
|
||||
public function index()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
abort(403, 'Sorry! You are not allowed to view permissions.');
|
||||
}
|
||||
|
||||
// Return the view for displaying the permissions
|
||||
@@ -53,8 +70,8 @@
|
||||
public function store(PermissionRequest $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to store permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.store')) {
|
||||
//abort(403, 'Sorry! You are not allowed to store permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create permissions.');
|
||||
}
|
||||
|
||||
$validate = $request->validated();
|
||||
@@ -70,7 +87,8 @@
|
||||
$group_name . '.delete',
|
||||
$group_name . '.export',
|
||||
$group_name . '.authorize',
|
||||
$group_name . '.report'
|
||||
$group_name . '.report',
|
||||
$group_name . '.restore'
|
||||
];
|
||||
|
||||
foreach ($data as $permission) {
|
||||
@@ -97,24 +115,14 @@
|
||||
public function create()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to create permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.create')) {
|
||||
//abort(403, 'Sorry! You are not allowed to create permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create permissions.');
|
||||
}
|
||||
|
||||
// Return the view for creating a new role
|
||||
return view('usermanagement::permissions.create');
|
||||
}
|
||||
|
||||
public function show($id){
|
||||
// Check if the authenticated user has the required permission to view permissions
|
||||
if (is_null($this->user) ||!$this->user->can('permissions.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view permissions.');
|
||||
}
|
||||
|
||||
// Return the view for editing the role
|
||||
return view('usermanagement::permissions.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
@@ -126,8 +134,8 @@
|
||||
public function edit($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to edit permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.edit')) {
|
||||
//abort(403, 'Sorry! You are not allowed to edit permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to edit permissions.');
|
||||
}
|
||||
|
||||
$permission = PermissionGroup::find($id);
|
||||
@@ -150,8 +158,8 @@
|
||||
public function update(PermissionRequest $request, $id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to update permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.update')) {
|
||||
//abort(403, 'Sorry! You are not allowed to update permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update permissions.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
@@ -173,7 +181,8 @@
|
||||
$group_name . '.delete',
|
||||
$group_name . '.export',
|
||||
$group_name . '.authorize',
|
||||
$group_name . '.report'
|
||||
$group_name . '.report',
|
||||
$group_name . '.restore'
|
||||
];
|
||||
|
||||
$i = 0;
|
||||
@@ -202,8 +211,8 @@
|
||||
public function destroy($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to delete permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.delete')) {
|
||||
//abort(403, 'Sorry! You are not allowed to delete permissions.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.delete')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to delete permissions.','success' => false]);
|
||||
}
|
||||
|
||||
$permission = PermissionGroup::find($id);
|
||||
@@ -214,7 +223,7 @@
|
||||
}
|
||||
|
||||
// Redirect back to the permissions index with a success message
|
||||
echo json_encode(['message' => 'Permission deleted successfully.', 'success' => true]);
|
||||
return response()->json(['message' => 'Permission deleted successfully.','success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +237,7 @@
|
||||
public function restore($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to restore permissions
|
||||
if (is_null($this->user) || !$this->user->can('permissions.restore')) {
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.restore')) {
|
||||
abort(403, 'Sorry! You are not allowed to restore permissions.');
|
||||
}
|
||||
|
||||
@@ -257,8 +266,8 @@
|
||||
*/
|
||||
public function dataForDatatables(Request $request)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('permissions.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to view permissions.','success' => false]);
|
||||
}
|
||||
|
||||
// Retrieve data from the database
|
||||
@@ -267,9 +276,7 @@
|
||||
// Apply search filter if provided
|
||||
if ($request->has('search') && !empty($request->get('search'))) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'LIKE', "%$search%");
|
||||
});
|
||||
$query->where('name', 'like', '%' . $search . '%');
|
||||
}
|
||||
|
||||
// Apply sorting if provided
|
||||
@@ -294,14 +301,11 @@
|
||||
// Get the filtered count of records
|
||||
$filteredRecords = $query->count();
|
||||
|
||||
|
||||
// Get the data for the current page
|
||||
$permissions = $query->get();
|
||||
$data = $query->get();
|
||||
|
||||
|
||||
$permissions = $permissions->map(function ($permission) {
|
||||
$data = $data->map(function ($permission) {
|
||||
$permission->roles = $permission->roles($permission);
|
||||
|
||||
return $permission;
|
||||
});
|
||||
|
||||
@@ -319,12 +323,17 @@
|
||||
'pageCount' => $pageCount,
|
||||
'page' => $currentPage,
|
||||
'totalCount' => $totalRecords,
|
||||
'data' => $permissions,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to export permissions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.export')) {
|
||||
abort(403, 'Sorry! You are not allowed to export permissions.');
|
||||
}
|
||||
|
||||
return Excel::download(new PermissionExport, 'permissions.xlsx');
|
||||
}
|
||||
}
|
||||
|
||||
291
app/Http/Controllers/PositionsController.php
Normal file
291
app/Http/Controllers/PositionsController.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Usermanagement\Exports\PositionExport;
|
||||
use Modules\Usermanagement\Http\Requests\PositionRequest;
|
||||
use Modules\Usermanagement\Models\Position;
|
||||
|
||||
/**
|
||||
* Class PositionsController
|
||||
*
|
||||
* This controller is responsible for managing positions within the application.
|
||||
*
|
||||
* @package Modules\Usermanagement\Http\Controllers
|
||||
*/
|
||||
class PositionsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UsersController constructor.
|
||||
*
|
||||
* Initializes the user property with the authenticated user.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Mengatur middleware auth
|
||||
$this->middleware('auth');
|
||||
|
||||
// Mengatur user setelah middleware auth dijalankan
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = Auth::user();
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
abort(403, 'Sorry! You are not allowed to view positions.');
|
||||
}
|
||||
|
||||
// Fetch all positions from the database
|
||||
$positions = Position::all();
|
||||
|
||||
// Return the view for displaying the positions
|
||||
return view('usermanagement::positions.index', compact('positions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Modules\Usermanagement\Http\Requests\PositionRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(PositionRequest $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to store positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create positions.');
|
||||
}
|
||||
|
||||
// Get validated data
|
||||
$validated = $request->validated();
|
||||
|
||||
try {
|
||||
// If no errors, save the position to the database
|
||||
$position = Position::create($validated);
|
||||
|
||||
// Redirect to the positions index page with a success message
|
||||
return redirect()->route('users.positions.index')
|
||||
->with('success', 'Position created successfully.');
|
||||
} catch (Exception $e) {
|
||||
// If an error occurs, redirect back with an error message
|
||||
return redirect()->back()
|
||||
->with('error', 'An error occurred while creating the position: ' . $e->getMessage())
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to create positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create positions.');
|
||||
}
|
||||
|
||||
// Return the view for creating a new position
|
||||
return view('usermanagement::positions.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to edit positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to edit positions.');
|
||||
}
|
||||
|
||||
// Find the position by ID
|
||||
$position = Position::findOrFail($id);
|
||||
|
||||
// Return the view for editing the position
|
||||
return view('usermanagement::positions.create', compact('position'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Modules\Usermanagement\Http\Requests\PositionRequest $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(PositionRequest $request, $id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to update positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update positions.');
|
||||
}
|
||||
|
||||
// Find the position by ID
|
||||
$position = Position::findOrFail($id);
|
||||
|
||||
// Get validated data
|
||||
$validated = $request->validated();
|
||||
|
||||
try {
|
||||
// If no errors, update the position in the database
|
||||
$position->update($validated);
|
||||
|
||||
// Redirect to the positions index page with a success message
|
||||
return redirect()->route('users.positions.index')
|
||||
->with('success', 'Position updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
// If an error occurs, redirect back with an error message
|
||||
return redirect()->back()
|
||||
->with('error', 'An error occurred while updating the position: ' . $e->getMessage())
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to delete positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.delete')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to delete positions.','success' => false]);
|
||||
}
|
||||
|
||||
// Find the position by ID
|
||||
$position = Position::findOrFail($id);
|
||||
|
||||
// Check if the position has associated roles
|
||||
if ($position->roles()->count() > 0) {
|
||||
return redirect()->route('users.positions.index')
|
||||
->with('error', 'Cannot delete position because it has associated roles.');
|
||||
}
|
||||
|
||||
try {
|
||||
// If no errors, delete the position from the database
|
||||
$position->delete();
|
||||
|
||||
// Redirect to the positions index page with a success message
|
||||
return redirect()->route('users.positions.index')
|
||||
->with('success', 'Position deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
// If an error occurs, redirect back with an error message
|
||||
return redirect()->route('users.positions.index')
|
||||
->with('error', 'An error occurred while deleting the position: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process support datatables ajax request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function dataForDatatables(Request $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to view positions.','success' => false]);
|
||||
}
|
||||
|
||||
// Retrieve data from the database
|
||||
$query = Position::query();
|
||||
|
||||
// Apply search filter if provided
|
||||
if ($request->has('search') && !empty($request->get('search'))) {
|
||||
$search = $request->get('search');
|
||||
$query->whereAny(['code', 'name', 'level'], 'like', '%' . $search . '%');
|
||||
}
|
||||
|
||||
// Apply sorting if provided
|
||||
if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
|
||||
$order = $request->get('sortOrder');
|
||||
$column = $request->get('sortField');
|
||||
$query->orderBy($column, $order);
|
||||
}
|
||||
|
||||
// Get the total count of records
|
||||
$totalRecords = $query->count();
|
||||
|
||||
// Apply pagination if provided
|
||||
if ($request->has('page') && $request->has('size')) {
|
||||
$page = $request->get('page');
|
||||
$size = $request->get('size');
|
||||
$offset = ($page - 1) * $size; // Calculate the offset
|
||||
|
||||
$query->skip($offset)->take($size);
|
||||
}
|
||||
|
||||
// Get the filtered count of records
|
||||
$filteredRecords = $query->count();
|
||||
|
||||
// Get the data for the current page
|
||||
$data = $query->get();
|
||||
|
||||
// Calculate the page count
|
||||
$size = $request->get('size', 10); // Default to 10 if not set
|
||||
$pageCount = $size > 0 ? ceil($totalRecords / $size) : 0;
|
||||
|
||||
// Calculate the current page number
|
||||
$currentPage = $request->get('page', 1); // Default to page 1 if not set
|
||||
|
||||
// Return the response data as a JSON object
|
||||
return response()->json([
|
||||
'draw' => $request->get('draw'),
|
||||
'recordsTotal' => $totalRecords,
|
||||
'recordsFiltered' => $filteredRecords,
|
||||
'pageCount' => $pageCount,
|
||||
'page' => $currentPage,
|
||||
'totalCount' => $totalRecords,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export positions to Excel.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function export(Request $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to export positions
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.export')) {
|
||||
abort(403, 'Sorry! You are not allowed to export positions.');
|
||||
}
|
||||
|
||||
// Get search parameter from request
|
||||
$search = $request->get('search');
|
||||
|
||||
return Excel::download(new PositionExport($search), 'positions.xlsx');
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,9 @@
|
||||
use Modules\Usermanagement\Http\Requests\RoleRequest;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Modules\Usermanagement\Models\Position;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class RolesController
|
||||
@@ -24,20 +26,24 @@
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public $user;
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UsersController constructor.
|
||||
*
|
||||
* Initializes the user property with the authenticated user.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Mengatur middleware auth
|
||||
$this->middleware('auth');
|
||||
|
||||
// Mengatur user setelah middleware auth dijalankan
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = Auth::guard('web')->user();
|
||||
$this->user = Auth::user();
|
||||
return $next($request);
|
||||
});
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
@@ -48,8 +54,8 @@
|
||||
public function index()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view roles.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
abort(403, 'Sorry! You are not allowed to view roles.');
|
||||
}
|
||||
|
||||
// Fetch all roles from the database
|
||||
@@ -70,14 +76,14 @@
|
||||
public function store(RoleRequest $request)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to store roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.store')) {
|
||||
//abort(403, 'Sorry! You are not allowed to store roles.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to store roles.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
|
||||
if($validated){
|
||||
try{
|
||||
if ($validated) {
|
||||
try {
|
||||
// If no errors, save the role to the database
|
||||
$role = Role::create($validated);
|
||||
|
||||
@@ -85,18 +91,22 @@
|
||||
$permissions = Permission::whereIn('id', $permissions)->pluck('name')->toArray();
|
||||
if (!empty($permissions)) {
|
||||
$role = Role::find($role->id);
|
||||
try{
|
||||
try {
|
||||
$role->syncPermissions($permissions);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode(['message' => $e->getMessage(), 'success']);exit;
|
||||
} catch (Exception $e) {
|
||||
return redirect()
|
||||
->route('users.roles.index')
|
||||
->with('error', 'Failed to sync permissions: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect back to the roles index with a success message
|
||||
return redirect()->route('users.roles.index')->with('success', 'Role created successfully.');
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
// Redirect back to the roles index with an error message
|
||||
return redirect()->route('users.roles.index')->with('error', 'Failed to create role. Please try again.');
|
||||
return redirect()
|
||||
->route('users.roles.index')
|
||||
->with('error', 'Failed to create role. Please try again.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,37 +120,14 @@
|
||||
public function create()
|
||||
{
|
||||
// Check if the authenticated user has the required permission to create roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.create')) {
|
||||
//abort(403, 'Sorry! You are not allowed to create roles.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create roles.');
|
||||
}
|
||||
|
||||
$permissiongroups = PermissionGroup::all();
|
||||
$positions = Position::all();
|
||||
// Return the view for creating a new role
|
||||
return view('usermanagement::roles.create',compact('permissiongroups'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to view roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.view')) {
|
||||
abort(403, 'Sorry! You are not allowed to view roles.');
|
||||
}
|
||||
|
||||
// Fetch the specified role from the database
|
||||
$role = Role::find($id);
|
||||
|
||||
|
||||
|
||||
// Return the view for displaying the role
|
||||
return view('usermanagement::roles.show', compact('role'));
|
||||
return view('usermanagement::roles.create', compact('permissiongroups', 'positions'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,16 +141,17 @@
|
||||
public function edit($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to edit roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.edit')) {
|
||||
//abort(403, 'Sorry! You are not allowed to edit roles.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to edit roles.');
|
||||
}
|
||||
|
||||
// Fetch the specified role from the database
|
||||
$role = Role::find($id);
|
||||
$permissions = Permission::all();
|
||||
$role = Role::find($id);
|
||||
$permissions = Permission::all();
|
||||
$permissiongroups = PermissionGroup::all();
|
||||
$positions = Position::all();
|
||||
// Return the view for editing the role
|
||||
return view('usermanagement::roles.create', compact('role','permissions','permissiongroups'));
|
||||
return view('usermanagement::roles.create', compact('role', 'permissions', 'permissiongroups', 'positions'));
|
||||
}
|
||||
|
||||
|
||||
@@ -180,13 +168,13 @@
|
||||
public function update(RoleRequest $request, $id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to update roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.update')) {
|
||||
//abort(403, 'Sorry! You are not allowed to update roles.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update roles.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
if($validated){
|
||||
try{
|
||||
if ($validated) {
|
||||
try {
|
||||
// If no errors, update the role in the database
|
||||
$role = Role::find($id);
|
||||
$role->update($request->all());
|
||||
@@ -195,19 +183,23 @@
|
||||
$permissions = Permission::whereIn('id', $permissions)->pluck('name')->toArray();
|
||||
if (!empty($permissions)) {
|
||||
$role = Role::find($role->id);
|
||||
try{
|
||||
try {
|
||||
$role->syncPermissions($permissions);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode(['message' => $e->getMessage(), 'success']);exit;
|
||||
} catch (Exception $e) {
|
||||
return redirect()
|
||||
->route('users.roles.index')
|
||||
->with('error', 'Failed to sync permissions: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Redirect back to the roles index with a success message
|
||||
return redirect()->route('users.roles.index')->with('success', 'Role updated successfully.');
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
// Redirect back to the roles index with an error message
|
||||
return redirect()->route('users.roles.index')->with('error', 'Failed to update role. Please try again.');
|
||||
return redirect()
|
||||
->route('users.roles.index')
|
||||
->with('error', 'Failed to update role. Please try again.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,21 +212,23 @@
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to delete roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.delete')) {
|
||||
//abort(403, 'Sorry! You are not allowed to delete roles.');
|
||||
// Check if the authenticated user has the required permission to delete currencies
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.delete')) {
|
||||
return response()->json(['success' => false, 'message' => 'Sorry! You are not allowed to delete roles.'], 403);
|
||||
}
|
||||
|
||||
// Fetch the specified role from the database
|
||||
$role = Role::find($id);
|
||||
try {
|
||||
// Delete from database
|
||||
$currency = Role::find($id);
|
||||
$currency->delete();
|
||||
|
||||
// Delete the role
|
||||
$role->delete();
|
||||
|
||||
// Redirect back to the roles index with a success message
|
||||
echo json_encode(['message' => 'Role deleted successfully.', 'success' => true]);
|
||||
return response()->json(['success' => true, 'message' => 'Role deleted successfully.']);
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['success' => false, 'message' => 'Failed to delete role.']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,7 +242,7 @@
|
||||
public function restore($id)
|
||||
{
|
||||
// Check if the authenticated user has the required permission to restore roles
|
||||
if (is_null($this->user) || !$this->user->can('roles.restore')) {
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.restore')) {
|
||||
abort(403, 'Sorry! You are not allowed to restore roles.');
|
||||
}
|
||||
|
||||
@@ -272,18 +266,25 @@
|
||||
*/
|
||||
public function dataForDatatables(Request $request)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('roles.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to view roles.','success' => false]);
|
||||
}
|
||||
|
||||
// Retrieve data from the database
|
||||
$query = Role::query();
|
||||
|
||||
if(!$this->user->hasRole('administrator')){
|
||||
$query->where('name', '!=', 'administrator');
|
||||
}
|
||||
|
||||
// Apply search filter if provided
|
||||
if ($request->has('search') && !empty($request->get('search'))) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'LIKE', "%$search%");
|
||||
$q->where('name', 'like', '%' . $search . '%')
|
||||
->orWhereHas('position', function ($query) use ($search) {
|
||||
$query->whereAny(['name', 'level'], 'like','%'.$search.'%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -291,11 +292,29 @@
|
||||
if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
|
||||
$order = $request->get('sortOrder');
|
||||
$column = $request->get('sortField');
|
||||
$query->orderBy($column, $order);
|
||||
|
||||
if ($column === 'position_name') {
|
||||
$query->leftJoin('positions', 'roles.position_id', '=', 'positions.id')
|
||||
->orderBy('positions.name', $order)
|
||||
->select('roles.*'); // Select only from roles table to avoid column conflicts
|
||||
} else if ($column === 'level') {
|
||||
$query->leftJoin('positions', 'roles.position_id', '=', 'positions.id')
|
||||
->orderBy('positions.level', $order)
|
||||
->select('roles.*'); // Select only from roles table to avoid column conflicts
|
||||
} else {
|
||||
if ($column === 'name') {
|
||||
$query->orderBy('roles.name', $order);
|
||||
} else {
|
||||
$query->orderBy($column, $order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the total count of records
|
||||
$totalRecords = $query->count();
|
||||
// Create a copy of the query for counting
|
||||
$countQuery = clone $query;
|
||||
|
||||
// Get the total count of records (without joins to avoid duplicates)
|
||||
$totalRecords = Role::count();
|
||||
|
||||
// Apply pagination if provided
|
||||
if ($request->has('page') && $request->has('size')) {
|
||||
@@ -306,17 +325,18 @@
|
||||
$query->skip($offset)->take($size);
|
||||
}
|
||||
|
||||
// Get the filtered count of records
|
||||
$filteredRecords = $query->count();
|
||||
// Get the filtered count of records - use distinct to avoid duplicates from joins
|
||||
$filteredRecords = $countQuery->distinct()->count('roles.id');
|
||||
|
||||
// Get the data for the current page
|
||||
$roles = $query->get();
|
||||
$data = $query->with('position')->get();
|
||||
|
||||
// Calculate the page count
|
||||
$pageCount = ceil($totalRecords/$request->get('size'));
|
||||
// Calculate the page count - ensure we don't divide by zero
|
||||
$pageSize = $request->get('size', 10); // Default to 10 if not provided
|
||||
$pageCount = $pageSize > 0 ? ceil($totalRecords / $pageSize) : 0;
|
||||
|
||||
// Calculate the current page number
|
||||
$currentPage = 0 + 1;
|
||||
$currentPage = $request->get('page') ?: 1;
|
||||
|
||||
// Return the response data as a JSON object
|
||||
return response()->json([
|
||||
@@ -326,12 +346,16 @@
|
||||
'pageCount' => $pageCount,
|
||||
'page' => $currentPage,
|
||||
'totalCount' => $totalRecords,
|
||||
'data' => $roles,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.export')) {
|
||||
abort(403, 'Sorry! You are not allowed to export roles.');
|
||||
}
|
||||
|
||||
return Excel::download(new RolesExport, 'roles.xlsx');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Lpj\Models\Branch;
|
||||
use Modules\Basicdata\Models\Branch;
|
||||
use Modules\Usermanagement\Exports\UsersExport;
|
||||
use Modules\Usermanagement\Http\Requests\User as UserRequest;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class UsersController
|
||||
@@ -22,23 +25,27 @@
|
||||
*/
|
||||
class UsersController extends Controller
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public $user;
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UsersController constructor.
|
||||
*
|
||||
* Initializes the user property with the authenticated user.
|
||||
*/
|
||||
// public function __construct()
|
||||
// {
|
||||
// $this->middleware(function ($request, $next) {
|
||||
// $this->user = Auth::guard('web')->user();
|
||||
// return $next($request);
|
||||
// });
|
||||
// }
|
||||
public function __construct()
|
||||
{
|
||||
// Mengatur middleware auth
|
||||
$this->middleware('auth');
|
||||
|
||||
// Mengatur user setelah middleware auth dijalankan
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = Auth::user();
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
@@ -48,8 +55,8 @@
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
abort(403, 'Sorry! You are not allowed to view users.');
|
||||
}
|
||||
|
||||
return view('usermanagement::users.index');
|
||||
@@ -65,23 +72,35 @@
|
||||
*/
|
||||
public function dataForDatatables(Request $request)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.view')) {
|
||||
//abort(403, 'Sorry! You are not allowed to view users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.read')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to view users.','success' => false]);
|
||||
}
|
||||
|
||||
// Retrieve data from the database
|
||||
$query = User::query();
|
||||
|
||||
if(!$this->user->hasRole('administrator')){
|
||||
$query->whereHas('roles', function($q){
|
||||
$q->where('name', '!=', 'administrator');
|
||||
});
|
||||
}
|
||||
|
||||
// Apply search filter if provided
|
||||
if ($request->has('search') && !empty($request->get('search'))) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q
|
||||
->where('name', 'LIKE', "%$search%")
|
||||
->orWhere('email', 'LIKE', "%$search%");
|
||||
});
|
||||
$query->whereAny(['name', 'email'], 'like', '%'.$search.'%');
|
||||
}
|
||||
|
||||
// Apply sorting if provided
|
||||
if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
|
||||
$order = $request->get('sortOrder');
|
||||
$column = $request->get('sortField');
|
||||
$query->orderBy($column, $order);
|
||||
}
|
||||
|
||||
// Get the total count of records
|
||||
$totalRecords = $query->count();
|
||||
|
||||
// Apply pagination if provided
|
||||
if ($request->has('page') && $request->has('size')) {
|
||||
$page = $request->get('page');
|
||||
@@ -91,21 +110,11 @@
|
||||
$query->skip($offset)->take($size);
|
||||
}
|
||||
|
||||
// Get the total count of records
|
||||
$totalRecords = $query->count();
|
||||
|
||||
// Apply pagination if provided
|
||||
if ($request->has('start') && $request->has('length')) {
|
||||
$start = $request->get('start');
|
||||
$length = $request->get('length');
|
||||
$query->skip($start)->take($length);
|
||||
}
|
||||
|
||||
// Get the filtered count of records
|
||||
$filteredRecords = $query->count();
|
||||
|
||||
// Get the data for the current page
|
||||
$users = $query->with('branch')->get();
|
||||
$data = $query->with(['branch', 'roles'])->get();
|
||||
|
||||
// Calculate the page count
|
||||
$pageCount = ceil($totalRecords / $request->get('size'));
|
||||
@@ -121,7 +130,7 @@
|
||||
'pageCount' => $pageCount,
|
||||
'page' => $currentPage,
|
||||
'totalCount' => $totalRecords,
|
||||
'data' => $users,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -135,61 +144,19 @@
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.edit')) {
|
||||
//abort(403, 'Sorry! You are not allowed to edit users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to edit users.');
|
||||
}
|
||||
|
||||
$user = User::find($id);
|
||||
$roles = Role::all();
|
||||
if(!$this->user->hasRole('administrator')){
|
||||
$roles = $roles->where('name', '!=', 'administrator');
|
||||
}
|
||||
$branches = Branch::all();
|
||||
return view('usermanagement::users.create', compact('user', 'roles', 'branches'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Modules\Usermanagement\Http\Requests\User $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function update(UserRequest $request, $id)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.update')) {
|
||||
//abort(403, 'Sorry! You are not allowed to update users.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
|
||||
if($validated) {
|
||||
try{
|
||||
$user = User::find($id);
|
||||
if ($request->hasFile('sign')) {
|
||||
$sign = $request->file('sign');
|
||||
|
||||
$signName = time() . '.' . $sign->getClientOriginalExtension();
|
||||
|
||||
$sign->storeAs(
|
||||
'public/signatures/' . $user->id . '/',
|
||||
$signName,
|
||||
);
|
||||
|
||||
$validated['sign'] = $signName;
|
||||
}
|
||||
$user->update($validated);
|
||||
if ($request->roles) {
|
||||
$user->roles()->detach();
|
||||
$user->assignRole($request->roles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return redirect()->back()->withErrors(['error' => 'Failed to update user. Please try again.']);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('users.index')->with('success', 'User updated successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
@@ -200,14 +167,14 @@
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.delete')) {
|
||||
//abort(403, 'Sorry! You are not allowed to delete users.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.delete')) {
|
||||
return response()->json(['message' => 'Sorry! You are not allowed to delete users.','success' => false]);
|
||||
}
|
||||
|
||||
$user = User::find($id);
|
||||
$user->delete();
|
||||
|
||||
echo json_encode(['message' => 'User deleted successfully.', 'success' => true]);
|
||||
return response()->json(['message' => 'User deleted successfully.', 'success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,7 +187,7 @@
|
||||
*/
|
||||
public function restore($id)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.restore')) {
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.restore')) {
|
||||
abort(403, 'Sorry! You are not allowed to restore users.');
|
||||
}
|
||||
|
||||
@@ -243,6 +210,10 @@
|
||||
*/
|
||||
public function store(UserRequest $request)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create a user.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
|
||||
if ($validated) {
|
||||
@@ -267,18 +238,28 @@
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('users.create')) {
|
||||
//abort(403, 'Sorry! You are not allowed to create a user.');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.create')) {
|
||||
abort(403, 'Sorry! You are not allowed to create a user.');
|
||||
}
|
||||
|
||||
$roles = Role::all();
|
||||
if(!$this->user->hasRole('administrator')){
|
||||
$roles = $roles->where('name', '!=', 'administrator');
|
||||
}
|
||||
$branches = Branch::all();
|
||||
return view('usermanagement::users.create', compact('roles', 'branches'));
|
||||
}
|
||||
|
||||
public function export()
|
||||
public function export(Request $request)
|
||||
{
|
||||
return Excel::download(new UsersExport, 'users.xlsx');
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.export')) {
|
||||
abort(403, 'Sorry! You are not allowed to export users.');
|
||||
}
|
||||
|
||||
// Get search parameter from request
|
||||
$search = $request->get('search');
|
||||
|
||||
return Excel::download(new UsersExport($search), 'users.xlsx');
|
||||
}
|
||||
|
||||
public function profile()
|
||||
@@ -287,4 +268,110 @@
|
||||
return view('usermanagement::users.profile', compact('user'));
|
||||
}
|
||||
|
||||
public function updateProfile(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
$validatedData = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|string|email|max:255|unique:users,email,' . $user->id,
|
||||
'sign' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
||||
]);
|
||||
|
||||
$user->name = $validatedData['name'];
|
||||
$user->email = $validatedData['email'];
|
||||
$user->nik = $validatedData['nik'];
|
||||
|
||||
if ($request->hasFile('sign')) {
|
||||
// Delete old e-sign if exists
|
||||
if ($user->sign) {
|
||||
Storage::disk('public')->delete('signatures/' . $user->id . '/' . $user->sign);
|
||||
}
|
||||
|
||||
$sign = $request->file('sign');
|
||||
$signName = time() . '.' . $sign->getClientOriginalExtension();
|
||||
|
||||
// Make sure the directory exists
|
||||
Storage::disk('public')->makeDirectory('signatures/' . $user->id);
|
||||
|
||||
// Store the file
|
||||
$sign->storeAs('signatures/' . $user->id, $signName, 'public');
|
||||
$user->sign = $signName;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
return redirect()->route('users.profile')->with('success', 'Profile updated successfully.');
|
||||
}
|
||||
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'current_password' => 'required',
|
||||
'password' => 'required|string|min:8|confirmed',
|
||||
], [
|
||||
'password_confirmation' => 'The new password confirmation does not match.',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()->withErrors($validator)->withInput();
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
if (!Hash::check($request->current_password, $user->password)) {
|
||||
return back()->withErrors(['current_password' => 'The current password is incorrect.']);
|
||||
}
|
||||
|
||||
$user->password = Hash::make($request->password);
|
||||
$user->save();
|
||||
|
||||
return redirect()->route('users.profile')->with('success', 'Password changed successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Modules\Usermanagement\Http\Requests\User $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function update(UserRequest $request, $id)
|
||||
{
|
||||
if (is_null($this->user) || !$this->user->can('usermanagement.update')) {
|
||||
abort(403, 'Sorry! You are not allowed to update users.');
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
|
||||
if ($validated) {
|
||||
try {
|
||||
$user = User::find($id);
|
||||
if ($request->hasFile('sign')) {
|
||||
$sign = $request->file('sign');
|
||||
|
||||
$signName = time() . '.' . $sign->getClientOriginalExtension();
|
||||
|
||||
$sign->storeAs(
|
||||
'public/signatures/' . $user->id . '/',
|
||||
$signName,
|
||||
);
|
||||
|
||||
$validated['sign'] = $signName;
|
||||
}
|
||||
$user->update($validated);
|
||||
if ($request->roles) {
|
||||
$user->roles()->detach();
|
||||
$user->assignRole($request->roles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return redirect()->back()->withErrors(['error' => 'Failed to update user. Please try again.']);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('users.index')->with('success', 'User updated successfully.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
39
app/Http/Requests/PositionRequest.php
Normal file
39
app/Http/Requests/PositionRequest.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class PositionRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|string',
|
||||
'level' => 'required|integer',
|
||||
];
|
||||
|
||||
if ($this->method() === 'PUT') {
|
||||
$rules['code'] = 'required|string|unique:positions,code,' . $this->id;
|
||||
} else {
|
||||
$rules['code'] = 'required|string|unique:positions,code';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
$rules = [
|
||||
'guard_names' => 'required|string|in:web,api',
|
||||
'position_id' => 'nullable|exists:positions,id',
|
||||
];
|
||||
|
||||
if ($this->method() === 'PUT') {
|
||||
@@ -41,6 +42,3 @@
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
use Wildside\Userstamps\Userstamps;
|
||||
use Mattiverse\Userstamps\Traits\Userstamps;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
namespace Modules\Usermanagement\Models;
|
||||
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
use Spatie\Permission\Models\Permission as SpatiePermission;
|
||||
|
||||
class Permission extends SpatiePermission
|
||||
{
|
||||
use LogsActivity;
|
||||
use LogsActivity, SoftDeletes;
|
||||
|
||||
/**
|
||||
* Retrieve the activity log options for this permission.
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
'slug'
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
if (!$model->slug) {
|
||||
$model->slug = \Str::slug($model->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all permissions associated with a given permission group ID.
|
||||
*
|
||||
|
||||
42
app/Models/Position.php
Normal file
42
app/Models/Position.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
|
||||
class Position extends Model
|
||||
{
|
||||
use SoftDeletes, LogsActivity;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'name',
|
||||
'level',
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieve the activity log options for this position.
|
||||
*
|
||||
* @return LogOptions The activity log options.
|
||||
*/
|
||||
public function getActivitylogOptions(): LogOptions
|
||||
{
|
||||
return LogOptions::defaults()->logAll()->useLogName('User Management|Positions : ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the roles associated with this position.
|
||||
*/
|
||||
public function roles()
|
||||
{
|
||||
return $this->hasMany(Role::class);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,17 @@
|
||||
{
|
||||
use softDeletes, LogsActivity;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'guard_name',
|
||||
'position_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieve the activity log options for this role.
|
||||
*
|
||||
@@ -22,4 +33,11 @@
|
||||
return LogOptions::defaults()->logAll()->useLogName('User Management|Roles : ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position that owns the role.
|
||||
*/
|
||||
public function position()
|
||||
{
|
||||
return $this->belongsTo(Position::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Models;
|
||||
namespace Modules\Usermanagement\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Modules\Lpj\Models\Branch;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
use Wildside\Userstamps\Userstamps;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Modules\Basicdata\Models\Branch;
|
||||
use Modules\Adk\Models\Appointment;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
use Mattiverse\Userstamps\Traits\Userstamps;
|
||||
|
||||
/**
|
||||
* Class User
|
||||
*
|
||||
* This class extends the Laravel's Authenticatable class and represents a User in the application.
|
||||
* It includes traits for using factories, notifications, API tokens, and UUIDs.
|
||||
*
|
||||
* @property string $name The name of the user.
|
||||
* @property string $email The email of the user.
|
||||
* @property string $password The hashed password of the user.
|
||||
* @property string $remember_token The token used for "remember me" functionality.
|
||||
*
|
||||
* @package App\Models
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory, Notifiable, Userstamps, HasRoles, softDeletes;
|
||||
|
||||
protected $guard_name = ['web'];
|
||||
|
||||
/**
|
||||
* Class User
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* This class extends the Laravel's Authenticatable class and represents a User in the application.
|
||||
* It includes traits for using factories, notifications, API tokens, and UUIDs.
|
||||
* These are the attributes that can be set in bulk during a create or update operation.
|
||||
*
|
||||
* @property string $name The name of the user.
|
||||
* @property string $email The email of the user.
|
||||
* @property string $password The hashed password of the user.
|
||||
* @property string $remember_token The token used for "remember me" functionality.
|
||||
*
|
||||
* @package App\Models
|
||||
* @var array<int, string>
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'nik',
|
||||
'branch_id',
|
||||
'profile_photo_path',
|
||||
'last_login_at',
|
||||
'last_login_ip',
|
||||
'sign'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* These are the attributes that will be hidden when the model is converted to an array or JSON.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* This method defines how the attributes should be cast when accessed.
|
||||
* In this case, 'email_verified_at' is cast to 'datetime', 'password' is cast to 'hashed', and 'id' is cast to 'string'.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
use Notifiable, Userstamps, HasRoles, softDeletes;
|
||||
|
||||
protected $guard_name = ['web'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* These are the attributes that can be set in bulk during a create or update operation.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'nik',
|
||||
'branch_id',
|
||||
'profile_photo_path',
|
||||
'last_login_at',
|
||||
'last_login_ip',
|
||||
'sign'
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'id' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* These are the attributes that will be hidden when the model is converted to an array or JSON.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* This method defines how the attributes should be cast when accessed.
|
||||
* In this case, 'email_verified_at' is cast to 'datetime', 'password' is cast to 'hashed', and 'id' is cast to 'string'.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts()
|
||||
: array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'id' => 'string',
|
||||
];
|
||||
}
|
||||
|
||||
public function branch(){
|
||||
return $this->belongsTo(Branch::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function branch()
|
||||
{
|
||||
return $this->belongsTo(Branch::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Modules\Usermanagement\Database\Factories\UserFactory::new();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the appointments for the User
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function appointments()
|
||||
{
|
||||
return $this->hasMany(Appointment::class, 'admin_id');
|
||||
}
|
||||
}
|
||||
|
||||
34
database/factories/UserFactory.php
Normal file
34
database/factories/UserFactory.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = User::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->name(),
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => bcrypt('password'), // Default password for testing
|
||||
'remember_token' => Str::random(10),
|
||||
'nik' => $this->faker->unique()->numerify('##########'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Lpj\Models\Branch;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Basicdata\Models\Branch;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('nik')->nullable()->after('email');
|
||||
$table->foreignIdFor(Branch::class)->nullable()->after('nik')->constrained('branches');
|
||||
});
|
||||
}
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up()
|
||||
: void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('nik')->nullable()->after('email');
|
||||
$table->foreignIdFor(Branch::class)->nullable()->after('nik')->constrained('branches');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('nik');
|
||||
$table->dropForeign(['branch_id']);
|
||||
$table->dropColumn('branch_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down()
|
||||
: void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('nik');
|
||||
$table->dropForeign(['branch_id']);
|
||||
$table->dropColumn('branch_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('positions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('code')->unique();
|
||||
$table->string('name');
|
||||
$table->integer('level');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('positions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
|
||||
Schema::table($tableNames['roles'], function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('position_id')->nullable()->after('guard_name');
|
||||
$table->foreign('position_id')
|
||||
->references('id')
|
||||
->on('positions')
|
||||
->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
}
|
||||
|
||||
Schema::table($tableNames['roles'], function (Blueprint $table) {
|
||||
$table->dropForeign(['position_id']);
|
||||
$table->dropColumn('position_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -28,13 +28,7 @@
|
||||
public function data()
|
||||
{
|
||||
return [
|
||||
['name' => 'usermanagement'],
|
||||
['name' => 'basic-data'],
|
||||
['name' => 'permohonan'],
|
||||
['name' => 'admin'],
|
||||
['name' => 'senior-officer'],
|
||||
['name' => 'penilai'],
|
||||
['name' => 'surveyor']
|
||||
['name' => 'usermanagement']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
{
|
||||
$actions = [];
|
||||
// list of permission actions
|
||||
$crud = ['create', 'read', 'update', 'delete','export', 'authorize', 'report'];
|
||||
$crud = ['create', 'read', 'update', 'delete','export', 'authorize', 'report','restore'];
|
||||
|
||||
|
||||
foreach ($crud as $value) {
|
||||
|
||||
@@ -27,13 +27,7 @@
|
||||
public function data()
|
||||
{
|
||||
return [
|
||||
['name' => 'administrator'],
|
||||
['name' => 'admin'],
|
||||
['name' => 'senior-officer'],
|
||||
['name' => 'penilai'],
|
||||
['name' => 'surveyor'],
|
||||
['name' => 'pemohon-ao'],
|
||||
['name' => 'pemohon-eo']
|
||||
['name' => 'administrator']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Database\Seeders;
|
||||
namespace Modules\Usermanagement\Database\Seeders;
|
||||
|
||||
use Faker\Generator;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Modules\Usermanagement\Database\Seeders\RolesSeeder;
|
||||
|
||||
class UsersSeeder extends Seeder
|
||||
class UsersSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(Generator $faker)
|
||||
{
|
||||
$roles = Role::all();
|
||||
$roleSeeder = new RolesSeeder();
|
||||
$rolesData = $roleSeeder->data();
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$user = User::create([
|
||||
'name' => $role->name,
|
||||
'email' => $role->name . '@lpj.id',
|
||||
'password' => Hash::make('lpj'),
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
foreach ($rolesData as $roleData) {
|
||||
if ($roleData['name'] === 'administrator') {
|
||||
$user = User::firstOrCreate(
|
||||
['email' => $roleData['name'] . '@ag.co.id'],
|
||||
[
|
||||
'name' => $roleData['name'],
|
||||
'password' => Hash::make('bagbag'),
|
||||
'branch_id' => 1,
|
||||
'nik' => '000000',
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
$role = \Spatie\Permission\Models\Role::firstOrCreate(
|
||||
['name' => $roleData['name']],
|
||||
['guard_name' => 'web']
|
||||
);
|
||||
|
||||
$user->assignRole($role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
128
module.json
128
module.json
@@ -1,61 +1,73 @@
|
||||
{
|
||||
"name": "Usermanagement",
|
||||
"alias": "usermanagement",
|
||||
"database": "",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
"providers": [
|
||||
"Modules\\Usermanagement\\Providers\\UsermanagementServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"menu": {
|
||||
"main": [],
|
||||
"master": [],
|
||||
"system": [
|
||||
{
|
||||
"title": "User Management",
|
||||
"path": "users",
|
||||
"icon": "ki-filled ki-users text-lg",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"title": "Users",
|
||||
"path": "users",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Roles",
|
||||
"path": "users.roles",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Permissions",
|
||||
"path": "users.permissions",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
}
|
||||
"name": "Usermanagement",
|
||||
"alias": "usermanagement",
|
||||
"database": "",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
"providers": [
|
||||
"Modules\\Usermanagement\\Providers\\UsermanagementServiceProvider"
|
||||
],
|
||||
"files": [
|
||||
"app/Helpers/RolePermission.php"
|
||||
],
|
||||
"menu": {
|
||||
"main": [],
|
||||
"master": [],
|
||||
"system": [
|
||||
{
|
||||
"title": "User Management",
|
||||
"path": "users",
|
||||
"icon": "ki-filled ki-users text-lg text-primary",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"title": "Users",
|
||||
"path": "users",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Positions",
|
||||
"path": "users.positions",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Roles",
|
||||
"path": "users.roles",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Permissions",
|
||||
"path": "users.permissions",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="grid">
|
||||
<div class="card card-grid min-w-full" data-datatable="false" data-datatable-page-size="5" data-datatable-state-save="true" id="permissions-table" data-api-url="{{ route('users.permissions.datatables') }}">
|
||||
<div class="card-header py-5 flex-wrap">
|
||||
<div class="min-w-full card card-grid" data-datatable="false" data-datatable-page-size="5"
|
||||
data-datatable-state-save="true" id="permissions-table"
|
||||
data-api-url="{{ route('users.permissions.datatables') }}">
|
||||
<div class="flex-wrap py-5 card-header">
|
||||
<h3 class="card-title">
|
||||
List of Permissions
|
||||
</h3>
|
||||
@@ -19,62 +21,45 @@
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<select class="select select-sm w-28">
|
||||
<option value="1">
|
||||
Active
|
||||
</option>
|
||||
<option value="2">
|
||||
Disabled
|
||||
</option>
|
||||
<option value="2">
|
||||
Pending
|
||||
</option>
|
||||
</select>
|
||||
<select class="select select-sm w-28">
|
||||
<option value="desc">
|
||||
Latest
|
||||
</option>
|
||||
<option value="asc">
|
||||
Oldest
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline btn-primary">
|
||||
<i class="ki-filled ki-setting-4"> </i> <Filters></Filters>
|
||||
</button>
|
||||
<div class="flex flex-wrap gap-2.5 lg:gap-5">
|
||||
<div class="h-[24px] border border-r-gray-200"> </div>
|
||||
<a class="btn btn-sm btn-light" href="{{ route('users.permissions.export') }}"> Export to Excel </a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.permissions.create') }}"> Add Permission </a>
|
||||
<a class="btn btn-sm btn-light" href="{{ route('users.permissions.export') }}"> Export to Excel
|
||||
</a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.permissions.create') }}"> Add Permission
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="scrollable-x-auto">
|
||||
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm" data-datatable-table="true">
|
||||
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
|
||||
data-datatable-table="true">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox"/>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Permission </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="roles">
|
||||
<span class="sort"> <span class="sort-label"> Roles </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox" />
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Permission </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="roles">
|
||||
<span class="sort"> <span class="sort-label"> Roles </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
||||
<div class="flex gap-2 items-center">
|
||||
Show
|
||||
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per page
|
||||
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
|
||||
page
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex gap-4 items-center">
|
||||
<span data-datatable-info="true"> </span>
|
||||
<div class="pagination" data-datatable-pagination="true">
|
||||
</div>
|
||||
@@ -92,7 +77,7 @@
|
||||
function deleteData(data) {
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: "You won't be able to revert this!" ,
|
||||
text: "You won't be able to revert this!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
@@ -102,14 +87,14 @@
|
||||
if (result.isConfirmed) {
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax(`permissions/${data}`, {
|
||||
type: 'DELETE'
|
||||
}).then((response) => {
|
||||
swal.fire('Deleted!', 'User has been deleted.','success').then(() => {
|
||||
swal.fire('Deleted!', 'User has been deleted.', 'success').then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}).catch((error) => {
|
||||
@@ -124,7 +109,7 @@
|
||||
const element = document.querySelector('#permissions-table');
|
||||
const searchInput = document.getElementById('search');
|
||||
const apiUrl = element.getAttribute('data-api-url');
|
||||
const colors = ['','badge-primary', 'badge-success', 'badge-info', 'badge-danger', 'badge-warning', 'badge-dark'];
|
||||
const colors = ['', 'badge-primary', 'badge-success', 'badge-info', 'badge-danger', 'badge-warning', 'badge-dark'];
|
||||
|
||||
|
||||
const dataTableOptions = {
|
||||
@@ -147,12 +132,12 @@
|
||||
roles: {
|
||||
title: 'Roles',
|
||||
render: (item, data) => {
|
||||
const _render = data.roles.map((role) =>{
|
||||
const _render = data.roles.map((role) => {
|
||||
const randomColor = colors[Math.floor(Math.random() * colors.length)];
|
||||
return `<span class="badge ${randomColor} badge-sm">${role.name}</span>`;
|
||||
});
|
||||
});
|
||||
|
||||
return _render.join(' ');
|
||||
return _render.join(' ');
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -173,10 +158,10 @@
|
||||
|
||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||
// Custom search functionality
|
||||
searchInput.addEventListener('input', function () {
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchValue = this.value.trim();
|
||||
dataTable.search(searchValue, true);
|
||||
dataTable.goPage(1);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
68
resources/views/positions/create.blade.php
Normal file
68
resources/views/positions/create.blade.php
Normal file
@@ -0,0 +1,68 @@
|
||||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumbs')
|
||||
{{ Breadcrumbs::render(request()->route()->getName()) }}
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
|
||||
<form action="{{ isset($position->id) ? route('users.positions.update', $position->id) : route('users.positions.store') }}" method="POST" id="position_form">
|
||||
@csrf
|
||||
@if(isset($position->id))
|
||||
<input type="hidden" name="id" value="{{ $position->id }}">
|
||||
@method('PUT')
|
||||
@endif
|
||||
<div class="card pb-2.5">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
{{ isset($position->id) ? 'Edit' : 'Add' }} Position
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('users.positions.index') }}" class="btn btn-xs btn-info">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body grid gap-5">
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Code
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('code') border-danger @enderror" type="text" name="code" value="{{ $position->code ?? '' }}">
|
||||
@error('code')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Name
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('name') border-danger @enderror" type="text" name="name" value="{{ $position->name ?? '' }}">
|
||||
@error('name')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Level
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('level') border-danger @enderror" type="number" name="level" value="{{ $position->level ?? '' }}">
|
||||
@error('level')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
172
resources/views/positions/index.blade.php
Normal file
172
resources/views/positions/index.blade.php
Normal file
@@ -0,0 +1,172 @@
|
||||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumbs')
|
||||
{{ Breadcrumbs::render('users.positions') }}
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="grid">
|
||||
<div class="min-w-full card card-grid" data-datatable="false" data-datatable-page-size="5"
|
||||
data-datatable-state-save="true" id="positions-table" data-api-url="{{ route('users.positions.datatables') }}">
|
||||
<div class="flex-wrap py-5 card-header">
|
||||
<h3 class="card-title">
|
||||
List of Positions
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-2 lg:gap-5">
|
||||
<div class="flex">
|
||||
<label class="input input-sm"> <i class="ki-filled ki-magnifier"> </i>
|
||||
<input placeholder="Search positions" id="search" type="text" value="">
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5 lg:gap-5">
|
||||
<div class="h-[100%] border border-r-gray-200"> </div>
|
||||
<a class="btn btn-sm btn-light" id="export-btn" href="{{ route('users.positions.export') }}">
|
||||
Export to Excel </a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.positions.create') }}"> Add Position
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="scrollable-x-auto">
|
||||
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
|
||||
data-datatable-table="true">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox" />
|
||||
</th>
|
||||
<th class="min-w-[150px]" data-datatable-column="code">
|
||||
<span class="sort"> <span class="sort-label"> Code </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Name </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[100px]" data-datatable-column="level">
|
||||
<span class="sort"> <span class="sort-label"> Tingkat Jabatan </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div
|
||||
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
||||
<div class="flex gap-2 items-center">
|
||||
Show
|
||||
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
|
||||
page
|
||||
</div>
|
||||
<div class="flex gap-4 items-center">
|
||||
<span data-datatable-info="true"> </span>
|
||||
<div class="pagination" data-datatable-pagination="true">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script type="text/javascript">
|
||||
function deleteData(data) {
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: "You won't be able to revert this!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Yes, delete it!'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax(`positions/${data}`, {
|
||||
type: 'DELETE'
|
||||
}).then((response) => {
|
||||
swal.fire('Deleted!', 'Position has been deleted.', 'success').then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Error!', 'An error occurred while deleting the position.', 'error');
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
const element = document.querySelector('#positions-table');
|
||||
const searchInput = document.getElementById('search');
|
||||
|
||||
const apiUrl = element.getAttribute('data-api-url');
|
||||
const dataTableOptions = {
|
||||
apiEndpoint: apiUrl,
|
||||
pageSize: 5,
|
||||
columns: {
|
||||
select: {
|
||||
render: (item, data, context) => {
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.className = 'checkbox checkbox-sm';
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.value = data.id.toString();
|
||||
checkbox.setAttribute('data-datatable-row-check', 'true');
|
||||
return checkbox.outerHTML.trim();
|
||||
},
|
||||
},
|
||||
code: {
|
||||
title: 'Code',
|
||||
},
|
||||
name: {
|
||||
title: 'Name',
|
||||
},
|
||||
level: {
|
||||
title: 'Level',
|
||||
},
|
||||
actions: {
|
||||
title: 'Status',
|
||||
render: (item, data) => {
|
||||
return `<div class="flex flex-nowrap justify-center">
|
||||
<a class="btn btn-sm btn-icon btn-clear btn-info" href="positions/${data.id}/edit">
|
||||
<i class="ki-outline ki-notepad-edit"></i>
|
||||
</a>
|
||||
<a onclick="deleteData(${data.id})" class="delete btn btn-sm btn-icon btn-clear btn-danger">
|
||||
<i class="ki-outline ki-trash"></i>
|
||||
</a>
|
||||
</div>`;
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||
const exportBtn = document.getElementById('export-btn');
|
||||
const baseExportUrl = exportBtn.getAttribute('href');
|
||||
|
||||
// Custom search functionality
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchValue = this.value.trim();
|
||||
dataTable.search(searchValue, true);
|
||||
dataTable.goPage(1);
|
||||
|
||||
// Update export URL with search parameter
|
||||
if (searchValue) {
|
||||
exportBtn.setAttribute('href', `${baseExportUrl}?search=${encodeURIComponent(searchValue)}`);
|
||||
} else {
|
||||
exportBtn.setAttribute('href', baseExportUrl);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -6,81 +6,97 @@
|
||||
|
||||
@section('content')
|
||||
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
|
||||
@if(isset($role->id))
|
||||
<form action="{{ route('users.roles.update', $role->id) }}" method="POST" id="role_form">
|
||||
<form action="{{ isset($role->id) ? route('users.roles.update', $role->id) : route('users.roles.store') }}" method="POST" id="role_form">
|
||||
@csrf
|
||||
@if(isset($role->id))
|
||||
<input type="hidden" name="id" value="{{ $role->id }}">
|
||||
@method('PUT')
|
||||
@else
|
||||
<form method="POST" action="{{ route('users.roles.store') }}">
|
||||
@endif
|
||||
@csrf
|
||||
<div class="card pb-2.5">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
{{ isset($role->id) ? 'Edit' : 'Add' }} Role
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('users.roles.index') }}" class="btn btn-xs btn-info">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body grid gap-5">
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Name
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('name') border-danger @enderror" type="text" name="name" value="{{ $role->name ?? '' }}">
|
||||
@error('name')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Administrator/Superuser Access
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<label class="switch">
|
||||
<input name="check" id="select_all" type="checkbox" value="1"/>
|
||||
<span class="switch-label">
|
||||
Select All
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($permissiongroups as $group)
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
{{ ucwords($group->name) }}
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full gap-2.5">
|
||||
@foreach($group->getpermissionsByGroupId($group->id) as $permission)
|
||||
<label class="switch">
|
||||
@if(isset($role))
|
||||
<input type="checkbox" value="{{ $permission->id }}" name="permissions[]" {{ $role->hasPermissionTo($permission->name) ? 'checked' : null }} />
|
||||
@else
|
||||
<input type="checkbox" value="{{ $permission->id }}" name="permissions[]"/>
|
||||
@endif
|
||||
@php
|
||||
$permission_name = explode('.',$permission->name);
|
||||
@endphp
|
||||
|
||||
<span class="switch-label">
|
||||
{{ ucwords($permission_name[1]) }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="card pb-2.5">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
{{ isset($role->id) ? 'Edit' : 'Add' }} Role
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('users.roles.index') }}" class="btn btn-xs btn-info">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body grid gap-5">
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Name
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input class="input @error('name') border-danger @enderror" type="text" name="name" value="{{ $role->name ?? '' }}">
|
||||
@error('name')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Position
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<select class="select tomselect @error('position_id') border-danger @enderror" name="position_id">
|
||||
<option value="">Select Position</option>
|
||||
@foreach($positions as $position)
|
||||
<option value="{{ $position->id }}" {{ (isset($role) && $role->position_id == $position->id) ? 'selected' : '' }}>
|
||||
{{ $position->name }} | Tingkat Jabatan: {{ $position->level }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('position_id')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
Administrator/Superuser Access
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<label class="switch">
|
||||
<input name="check" id="select_all" type="checkbox" value="1"/>
|
||||
<span class="switch-label">
|
||||
Select All
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($permissiongroups as $group)
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">
|
||||
{{ ucwords($group->name) }}
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full gap-2.5">
|
||||
@foreach($group->getpermissionsByGroupId($group->id) as $permission)
|
||||
<label class="switch">
|
||||
@if(isset($role))
|
||||
<input type="checkbox" value="{{ $permission->id }}" name="permissions[]" {{ $role->hasPermissionTo($permission->name) ? 'checked' : null }} />
|
||||
@else
|
||||
<input type="checkbox" value="{{ $permission->id }}" name="permissions[]"/>
|
||||
@endif
|
||||
@php
|
||||
$permission_name = explode('.',$permission->name);
|
||||
@endphp
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
<span class="switch-label">
|
||||
{{ ucwords($permission_name[1]) }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@endforeach
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="grid">
|
||||
<div class="card card-grid min-w-full" data-datatable="false" data-datatable-page-size="5" data-datatable-state-save="true" id="roles-table" data-api-url="{{ route('users.roles.datatables') }}">
|
||||
<div class="card-header py-5 flex-wrap">
|
||||
<div class="min-w-full card card-grid" data-datatable="false" data-datatable-page-size="5"
|
||||
data-datatable-state-save="true" id="roles-table" data-api-url="{{ route('users.roles.datatables') }}">
|
||||
<div class="flex-wrap py-5 card-header">
|
||||
<h3 class="card-title">
|
||||
List of Roles
|
||||
</h3>
|
||||
@@ -19,29 +20,7 @@
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<select class="select select-sm w-28">
|
||||
<option value="1">
|
||||
Active
|
||||
</option>
|
||||
<option value="2">
|
||||
Disabled
|
||||
</option>
|
||||
<option value="2">
|
||||
Pending
|
||||
</option>
|
||||
</select>
|
||||
<select class="select select-sm w-28">
|
||||
<option value="desc">
|
||||
Latest
|
||||
</option>
|
||||
<option value="asc">
|
||||
Oldest
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline btn-primary">
|
||||
<i class="ki-filled ki-setting-4"> </i> <Filters></Filters>
|
||||
</button>
|
||||
<div class="flex flex-wrap gap-2.5 lg:gap-5">
|
||||
<div class="h-[24px] border border-r-gray-200"> </div>
|
||||
<a class="btn btn-sm btn-light" href="{{ route('users.roles.export') }}"> Export to Excel </a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.roles.create') }}"> Add Role </a>
|
||||
@@ -50,27 +29,38 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="scrollable-x-auto">
|
||||
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm" data-datatable-table="true">
|
||||
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
|
||||
data-datatable-table="true">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox"/>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Role </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox" />
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Role </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[200px]" data-datatable-column="position_name">
|
||||
<span class="sort"> <span class="sort-label"> Position </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[100px]" data-datatable-column="level">
|
||||
<span class="sort"> <span class="sort-label"> Tingkat Jabatan </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
||||
<div class="flex gap-2 items-center">
|
||||
Show
|
||||
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per page
|
||||
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
|
||||
page
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex gap-4 items-center">
|
||||
<span data-datatable-info="true"> </span>
|
||||
<div class="pagination" data-datatable-pagination="true">
|
||||
</div>
|
||||
@@ -88,7 +78,7 @@
|
||||
function deleteData(data) {
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: "You won't be able to revert this!" ,
|
||||
text: "You won't be able to revert this!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
@@ -98,14 +88,14 @@
|
||||
if (result.isConfirmed) {
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax(`roles/${data}`, {
|
||||
type: 'DELETE'
|
||||
}).then((response) => {
|
||||
swal.fire('Deleted!', 'User has been deleted.','success').then(() => {
|
||||
swal.fire('Deleted!', 'User has been deleted.', 'success').then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}).catch((error) => {
|
||||
@@ -138,6 +128,20 @@
|
||||
name: {
|
||||
title: 'Role',
|
||||
},
|
||||
position_name: {
|
||||
title: 'Position',
|
||||
render: (item, data) => {
|
||||
return data.position ? data.position.name : '-';
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
level: {
|
||||
title: 'Level',
|
||||
render: (item, data) => {
|
||||
return data.position ? data.position.level : '-';
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
actions: {
|
||||
title: 'Status',
|
||||
render: (item, data) => {
|
||||
@@ -156,10 +160,10 @@
|
||||
|
||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||
// Custom search functionality
|
||||
searchInput.addEventListener('input', function () {
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchValue = this.value.trim();
|
||||
dataTable.search(searchValue, true);
|
||||
dataTable.goPage(1);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
@@ -169,7 +169,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="switch switch-sm">
|
||||
<input {{ in_array($role->name,Auth()->user()->roles->pluck('name')->toArray()) ? 'checked' : '' }} name="roles" type="radio" value="{{ $role->name }}">
|
||||
@if(isset($user))
|
||||
<input {{ in_array($role->name,$user->roles->pluck("name")->toArray()) ? 'checked' : '' }} name="roles" type="radio" value="{{ $role->name }}">
|
||||
@else
|
||||
<input name="roles" type="radio" value="{{ $role->name }}">
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="grid">
|
||||
<div class="card card-grid min-w-full" data-datatable="false" data-datatable-page-size="5" data-datatable-state-save="true" id="users-table" data-api-url="{{ route('users.datatables') }}">
|
||||
<div class="card-header py-5 flex-wrap">
|
||||
<div class="min-w-full card card-grid" data-datatable="false" data-datatable-page-size="5"
|
||||
data-datatable-state-save="true" id="users-table" data-api-url="{{ route('users.datatables') }}">
|
||||
<div class="flex-wrap py-5 card-header">
|
||||
<h3 class="card-title">
|
||||
List of Users
|
||||
</h3>
|
||||
@@ -19,70 +20,56 @@
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<select class="select select-sm w-28">
|
||||
<option value="1">
|
||||
Active
|
||||
</option>
|
||||
<option value="2">
|
||||
Disabled
|
||||
</option>
|
||||
<option value="2">
|
||||
Pending
|
||||
</option>
|
||||
</select>
|
||||
<select class="select select-sm w-28">
|
||||
<option value="desc">
|
||||
Latest
|
||||
</option>
|
||||
<option value="asc">
|
||||
Oldest
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline btn-primary">
|
||||
<i class="ki-filled ki-setting-4"> </i> Filters
|
||||
</button>
|
||||
<div class="flex flex-wrap gap-2.5 lg:gap-5">
|
||||
<div class="h-[24px] border border-r-gray-200"> </div>
|
||||
<a class="btn btn-sm btn-light" href="{{ route('users.export') }}"> Export to Excel </a>
|
||||
<a class="btn btn-sm btn-light" id="export-btn" href="{{ route('users.export') }}"> Export to
|
||||
Excel </a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.create') }}"> Add User </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="scrollable-x-auto">
|
||||
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm" data-datatable-table="true">
|
||||
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
|
||||
data-datatable-table="true">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox"/>
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Name </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="email">
|
||||
<span class="sort"> <span class="sort-label"> Email </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="nik">
|
||||
<span class="sort"> <span class="sort-label"> NIK </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="branch">
|
||||
<span class="sort"> <span class="sort-label"> Branch </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="w-14">
|
||||
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox" />
|
||||
</th>
|
||||
<th class="min-w-[250px]" data-datatable-column="name">
|
||||
<span class="sort"> <span class="sort-label"> Name </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="email">
|
||||
<span class="sort"> <span class="sort-label"> Email </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="nik">
|
||||
<span class="sort"> <span class="sort-label"> NIK </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="branch">
|
||||
<span class="sort"> <span class="sort-label"> Branch </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[185px]" data-datatable-column="role">
|
||||
<span class="sort"> <span class="sort-label"> Role </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
||||
<div class="flex gap-2 items-center">
|
||||
Show
|
||||
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per page
|
||||
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
|
||||
page
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex gap-4 items-center">
|
||||
<span data-datatable-info="true"> </span>
|
||||
<div class="pagination" data-datatable-pagination="true">
|
||||
</div>
|
||||
@@ -100,7 +87,7 @@
|
||||
function deleteData(data) {
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: "You won't be able to revert this!" ,
|
||||
text: "You won't be able to revert this!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
@@ -110,14 +97,14 @@
|
||||
if (result.isConfirmed) {
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax(`users/${data}`, {
|
||||
type: 'DELETE'
|
||||
}).then((response) => {
|
||||
swal.fire('Deleted!', 'User has been deleted.','success').then(() => {
|
||||
swal.fire('Deleted!', 'User has been deleted.', 'success').then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}).catch((error) => {
|
||||
@@ -131,6 +118,20 @@
|
||||
<script type="module">
|
||||
const element = document.querySelector('#users-table');
|
||||
const searchInput = document.getElementById('search');
|
||||
const exportBtn = document.getElementById('export-btn');
|
||||
|
||||
// Update export URL with filters
|
||||
function updateExportUrl() {
|
||||
let url = new URL(exportBtn.href);
|
||||
|
||||
if (searchInput.value) {
|
||||
url.searchParams.set('search', searchInput.value);
|
||||
} else {
|
||||
url.searchParams.delete('search');
|
||||
}
|
||||
|
||||
exportBtn.href = url.toString();
|
||||
};
|
||||
|
||||
const apiUrl = element.getAttribute('data-api-url');
|
||||
const dataTableOptions = {
|
||||
@@ -159,7 +160,14 @@
|
||||
branch: {
|
||||
title: 'Branch',
|
||||
render: (item, data) => {
|
||||
return data.branch.name;
|
||||
return data.branch?.name || '-';
|
||||
},
|
||||
},
|
||||
role: {
|
||||
title: 'Role',
|
||||
render: (item, data) => {
|
||||
console.log(data);
|
||||
return data.roles.map(role => role.name).join(', ');
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
@@ -180,10 +188,11 @@
|
||||
|
||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||
// Custom search functionality
|
||||
searchInput.addEventListener('input', function () {
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchValue = this.value.trim();
|
||||
dataTable.search(searchValue, true);
|
||||
updateExportUrl();
|
||||
dataTable.goPage(1);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
@@ -59,6 +59,101 @@
|
||||
</div>
|
||||
<!-- End of Container -->
|
||||
</div>
|
||||
|
||||
<div class="container-fluid mt-8 w-full">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<!-- Edit Profile Form -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Edit Profile</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="{{ route('users.update-profile') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="mb-4">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="input @error('name') border-danger @enderror" id="name" name="name" value="{{ Auth::user()->name }}">
|
||||
|
||||
@error('name')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="input @error('email') border-danger @enderror" id="email" name="email" value="{{ Auth::user()->email }}">
|
||||
|
||||
@error('email')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="nik" class="form-label">NIK</label>
|
||||
<input type="text" class="input @error('nik') border-danger @enderror" id="nik" name="nik" value="{{ Auth::user()->nik }}">
|
||||
|
||||
@error('nik')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="sign" class="form-label">E-Sign</label>
|
||||
<input type="file" class="file-input @error('sign') border-danger @enderror" id="sign" name="sign" accept="image/*">
|
||||
@if(Auth::user()->sign)
|
||||
<div class="mt-2">
|
||||
<p>Current E-Sign:</p>
|
||||
<img src="{{ asset('storage/signatures/' . Auth::user()->id . '/' . Auth::user()->sign) }}"
|
||||
alt="E-Sign"
|
||||
class="mt-2 max-w-xs border border-gray-200 rounded">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@error('sign')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update Profile</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Change Password Form -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Change Password</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="{{ route('users.change-password') }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="mb-4">
|
||||
<label for="current_password" class="form-label">Current Password</label>
|
||||
<input type="password" class="input @error('current_password') border-danger @enderror" id="current_password" name="current_password">
|
||||
@error('current_password')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="password" class="form-label">New Password</label>
|
||||
<input type="password" class="input @error('password') border-danger @enderror" id="password" name="password">
|
||||
@error('password')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="password_confirmation" class="form-label">Confirm New Password</label>
|
||||
<input type="password" class="input @error('password_confirmation') border-danger @enderror" id="password_confirmation" name="password_confirmation">
|
||||
@error('password_confirmation')
|
||||
<div class="text-danger mt-2">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Change Password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
@@ -53,3 +53,18 @@
|
||||
$trail->parent('users.permissions');
|
||||
$trail->push('Edit Permission');
|
||||
});
|
||||
|
||||
Breadcrumbs::for('users.positions', function (BreadcrumbTrail $trail) {
|
||||
$trail->parent('users');
|
||||
$trail->push('Positions', route('users.positions.index'));
|
||||
});
|
||||
|
||||
Breadcrumbs::for('users.positions.create', function (BreadcrumbTrail $trail) {
|
||||
$trail->parent('users.positions');
|
||||
$trail->push('Add Position', route('users.positions.create'));
|
||||
});
|
||||
|
||||
Breadcrumbs::for('users.positions.edit', function (BreadcrumbTrail $trail) {
|
||||
$trail->parent('users.positions');
|
||||
$trail->push('Edit Position');
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Usermanagement\Http\Controllers\PermissionsController;
|
||||
use Modules\Usermanagement\Http\Controllers\PositionsController;
|
||||
use Modules\Usermanagement\Http\Controllers\RolesController;
|
||||
use Modules\Usermanagement\Http\Controllers\UsersController;
|
||||
|
||||
@@ -15,29 +16,39 @@
|
||||
| contains the "web" middleware group. Now create something great!
|
||||
|
|
||||
*/
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::name('users.')->prefix('users')->group(function () {
|
||||
Route::get('restore/{id}', [UsersController::class,'restore'])->name('restore');
|
||||
Route::get('datatables', [UsersController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [UsersController::class, 'export'])->name('export');
|
||||
Route::get('profile', [UsersController::class, 'profile'])->name('profile');
|
||||
});
|
||||
Route::resource('users', UsersController::class);
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::name('users.')->prefix('users')->group(function () {
|
||||
Route::get('restore/{id}', [UsersController::class, 'restore'])->name('restore');
|
||||
Route::get('datatables', [UsersController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [UsersController::class, 'export'])->name('export');
|
||||
Route::get('profile', [UsersController::class, 'profile'])->name('profile');
|
||||
|
||||
Route::name('users.')->group(function () {
|
||||
Route::name('roles.')->prefix('roles')->group(function () {
|
||||
Route::get('restore/{id}', [RolesController::class,'restore'])->name('restore');
|
||||
Route::get('datatables', [RolesController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [RolesController ::class, 'export'])->name('export');
|
||||
Route::put('/profile/update', [UsersController::class, 'updateProfile'])->name('update-profile');
|
||||
Route::put('/profile/change-password', [UsersController::class, 'changePassword'])->name(
|
||||
'change-password',
|
||||
);
|
||||
});
|
||||
Route::resource('roles', RolesController::class);
|
||||
Route::resource('users', UsersController::class);
|
||||
|
||||
Route::name('permissions.')->prefix('permissions')->group(function () {
|
||||
Route::get('restore/{id}', [PermissionsController::class,'restore'])->name('restore');
|
||||
Route::get('datatables', [PermissionsController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [PermissionsController ::class, 'export'])->name('export');
|
||||
Route::name('users.')->group(function () {
|
||||
Route::name('roles.')->prefix('roles')->group(function () {
|
||||
Route::get('restore/{id}', [RolesController::class, 'restore'])->name('restore');
|
||||
Route::get('datatables', [RolesController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [RolesController ::class, 'export'])->name('export');
|
||||
});
|
||||
Route::resource('roles', RolesController::class);
|
||||
|
||||
Route::name('permissions.')->prefix('permissions')->group(function () {
|
||||
Route::get('restore/{id}', [PermissionsController::class, 'restore'])->name('restore');
|
||||
Route::get('datatables', [PermissionsController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [PermissionsController ::class, 'export'])->name('export');
|
||||
});
|
||||
Route::resource('permissions', PermissionsController::class);
|
||||
|
||||
Route::name('positions.')->prefix('positions')->group(function () {
|
||||
Route::get('datatables', [PositionsController::class, 'dataForDatatables'])->name('datatables');
|
||||
Route::get('export', [PositionsController::class, 'export'])->name('export');
|
||||
});
|
||||
Route::resource('positions', PositionsController::class);
|
||||
});
|
||||
Route::resource('permissions', PermissionsController::class);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
474
tests/Feature/PermissionsControllerTest.php
Normal file
474
tests/Feature/PermissionsControllerTest.php
Normal file
@@ -0,0 +1,474 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class PermissionsControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
protected $user;
|
||||
protected $adminRole;
|
||||
protected $permissionGroup;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create admin role
|
||||
$this->adminRole = Role::create([
|
||||
'name' => 'Admin',
|
||||
'guard_name' => 'web'
|
||||
]);
|
||||
|
||||
// Create a permission group for usermanagement permissions
|
||||
$usermanagementGroup = PermissionGroup::create(['name' => 'Usermanagement']);
|
||||
|
||||
// Create permissions
|
||||
$permissions = [
|
||||
'usermanagement.create',
|
||||
'usermanagement.read',
|
||||
'usermanagement.update',
|
||||
'usermanagement.delete',
|
||||
'usermanagement.export',
|
||||
'usermanagement.store',
|
||||
'usermanagement.edit',
|
||||
'usermanagement.view',
|
||||
'usermanagement.restore'
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
Permission::create([
|
||||
'name' => $permission,
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $usermanagementGroup->id
|
||||
]);
|
||||
}
|
||||
|
||||
// Assign permissions to admin role
|
||||
$this->adminRole->givePermissionTo($permissions);
|
||||
|
||||
// Create user with admin role
|
||||
$this->user = User::create([
|
||||
'name' => 'Admin User',
|
||||
'email' => 'admin@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->user->assignRole($this->adminRole);
|
||||
|
||||
// Create a test permission group
|
||||
$this->permissionGroup = PermissionGroup::create(['name' => 'Test Group']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can view permissions index.
|
||||
*/
|
||||
public function test_user_with_permission_can_view_permissions_index(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->get(route('users.permissions.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertViewIs('usermanagement::permissions.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot view permissions index.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_view_permissions_index(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('users.permissions.index'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can create permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_create_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->get(route('users.permissions.create'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertViewIs('usermanagement::permissions.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot create permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_create_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user2@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('users.permissions.create'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can store permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_store_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$data = [
|
||||
'name' => 'TestPermission'
|
||||
];
|
||||
|
||||
$response = $this->post(route('users.permissions.store'), $data);
|
||||
|
||||
$response->assertRedirect(route('users.permissions.index'));
|
||||
$response->assertSessionHas('success');
|
||||
$this->assertDatabaseHas('permission_groups', ['name' => 'TestPermission']);
|
||||
|
||||
// Check if all the required permissions were created
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.create']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.read']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.update']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.delete']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.export']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.authorize']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'testpermission.report']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot store permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_store_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user3@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$data = [
|
||||
'name' => 'TestPermission2'
|
||||
];
|
||||
|
||||
$response = $this->post(route('users.permissions.store'), $data);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('permission_groups', ['name' => 'TestPermission2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can edit permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_edit_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->get(route('users.permissions.edit', $this->permissionGroup->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertViewIs('usermanagement::permissions.create');
|
||||
$response->assertViewHas('permission', $this->permissionGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot edit permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_edit_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user4@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('users.permissions.edit', $this->permissionGroup->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can update permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_update_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
// Create permissions for the test group
|
||||
$permissions = [
|
||||
'test group.create',
|
||||
'test group.read',
|
||||
'test group.update',
|
||||
'test group.delete',
|
||||
'test group.export',
|
||||
'test group.authorize',
|
||||
'test group.report'
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
Permission::create([
|
||||
'name' => $permission,
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'name' => 'Updated Group'
|
||||
];
|
||||
|
||||
$response = $this->put(route('users.permissions.update', $this->permissionGroup->id), $data);
|
||||
|
||||
$response->assertRedirect(route('users.permissions.index'));
|
||||
$response->assertSessionHas('success');
|
||||
$this->assertDatabaseHas('permission_groups', [
|
||||
'id' => $this->permissionGroup->id,
|
||||
'name' => 'Updated Group'
|
||||
]);
|
||||
|
||||
// Check if all the permissions were updated
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.create']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.read']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.update']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.delete']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.export']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.authorize']);
|
||||
$this->assertDatabaseHas('permissions', ['name' => 'updated group.report']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot update permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_update_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user5@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$data = [
|
||||
'name' => 'Should Not Update'
|
||||
];
|
||||
|
||||
$response = $this->put(route('users.permissions.update', $this->permissionGroup->id), $data);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('permission_groups', [
|
||||
'id' => $this->permissionGroup->id,
|
||||
'name' => 'Should Not Update'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can delete permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_delete_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->delete(route('users.permissions.destroy', $this->permissionGroup->id));
|
||||
|
||||
$response->assertJson([
|
||||
'message' => 'Permission deleted successfully.',
|
||||
'success' => true
|
||||
]);
|
||||
|
||||
$this->assertSoftDeleted('permission_groups', ['id' => $this->permissionGroup->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot delete permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_delete_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user6@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->delete(route('users.permissions.destroy', $this->permissionGroup->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseHas('permission_groups', ['id' => $this->permissionGroup->id, 'deleted_at' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can restore permission.
|
||||
*/
|
||||
public function test_user_with_permission_can_restore_permission(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
// First delete the permission group
|
||||
$this->permissionGroup->delete();
|
||||
$this->assertSoftDeleted('permission_groups', ['id' => $this->permissionGroup->id]);
|
||||
|
||||
$response = $this->get(route('users.permissions.restore', $this->permissionGroup->id));
|
||||
|
||||
$response->assertRedirect(route('users.permissions.index'));
|
||||
$response->assertSessionHas('success');
|
||||
$this->assertDatabaseHas('permission_groups', ['id' => $this->permissionGroup->id, 'deleted_at' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot restore permission.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_restore_permission(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user7@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
// First delete the permission group
|
||||
$this->permissionGroup->delete();
|
||||
$this->assertSoftDeleted('permission_groups', ['id' => $this->permissionGroup->id]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('users.permissions.restore', $this->permissionGroup->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertSoftDeleted('permission_groups', ['id' => $this->permissionGroup->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user with permission can access datatables data.
|
||||
*/
|
||||
public function test_user_with_permission_can_access_datatables_data(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->getJson(route('users.permissions.datatables') . '?page=1&size=10');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'draw',
|
||||
'recordsTotal',
|
||||
'recordsFiltered',
|
||||
'pageCount',
|
||||
'page',
|
||||
'totalCount',
|
||||
'data'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user without permission cannot access datatables data.
|
||||
*/
|
||||
public function test_user_without_permission_cannot_access_datatables_data(): void
|
||||
{
|
||||
// Create user without permissions
|
||||
$user = User::create([
|
||||
'name' => 'Regular User',
|
||||
'email' => 'user8@example.com',
|
||||
'password' => bcrypt('password')
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->getJson(route('users.permissions.datatables') . '?page=1&size=10');
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datatables search filters permissions correctly.
|
||||
*/
|
||||
public function test_datatables_search_filters_permissions_correctly(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
// Create additional permission groups for testing search
|
||||
PermissionGroup::create(['name' => 'SearchTest1']);
|
||||
PermissionGroup::create(['name' => 'SearchTest2']);
|
||||
PermissionGroup::create(['name' => 'DifferentName']);
|
||||
|
||||
$response = $this->getJson(route('users.permissions.datatables') . '?page=1&size=10&search=SearchTest');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonCount(2, 'data');
|
||||
$response->assertJsonPath('data.0.name', 'SearchTest1');
|
||||
$response->assertJsonPath('data.1.name', 'SearchTest2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datatables sorting works correctly.
|
||||
*/
|
||||
public function test_datatables_sorting_works_correctly(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
// Create additional permission groups for testing sorting
|
||||
PermissionGroup::create(['name' => 'A-Group']);
|
||||
PermissionGroup::create(['name' => 'Z-Group']);
|
||||
|
||||
// Test ascending order
|
||||
$response = $this->getJson(route('users.permissions.datatables') . '?page=1&size=10&sortField=name&sortOrder=asc');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonPath('data.0.name', 'A-Group');
|
||||
|
||||
// Test descending order
|
||||
$response = $this->getJson(route('users.permissions.datatables') . '?page=1&size=10&sortField=name&sortOrder=desc');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonPath('data.0.name', 'Z-Group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test export functionality.
|
||||
*/
|
||||
public function test_export_functionality(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->get(route('users.permissions.export'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
}
|
||||
}
|
||||
344
tests/Feature/PositionsControllerTest.php
Normal file
344
tests/Feature/PositionsControllerTest.php
Normal file
@@ -0,0 +1,344 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Modules\Usermanagement\Models\Position;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
|
||||
class PositionsControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $user;
|
||||
protected $adminRole;
|
||||
protected $position;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create permission group first
|
||||
$permissionGroup = PermissionGroup::create([
|
||||
'name' => 'usermanagement',
|
||||
'slug' => 'usermanagement'
|
||||
]);
|
||||
|
||||
// Create permissions with permission_group_id
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.create',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.read',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.update',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.delete',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.export',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create admin role with all permissions
|
||||
$this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$this->adminRole->givePermissionTo(Permission::all());
|
||||
|
||||
// Create a user with admin role
|
||||
$this->user = User::factory()->create();
|
||||
$this->user->assignRole($this->adminRole);
|
||||
|
||||
// Create a position for testing
|
||||
$this->position = Position::create([
|
||||
'code' => 'TEST',
|
||||
'name' => 'Test Position',
|
||||
'level' => 1
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_view_positions_index()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.positions.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_view_positions_index()
|
||||
{
|
||||
// Create a role without permissions
|
||||
$role = Role::create(['name' => 'viewer', 'guard_name' => 'web']);
|
||||
|
||||
// Create a user with the viewer role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.positions.index'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_create_position()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.positions.create'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_create_position()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.positions.create'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_store_position()
|
||||
{
|
||||
$positionData = [
|
||||
'code' => 'NEW',
|
||||
'name' => 'New Position',
|
||||
'level' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->post(route('users.positions.store'), $positionData);
|
||||
|
||||
$response->assertRedirect(route('users.positions.index'));
|
||||
$this->assertDatabaseHas('positions', $positionData);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_store_position()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$positionData = [
|
||||
'code' => 'NEW',
|
||||
'name' => 'New Position',
|
||||
'level' => 2
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post(route('users.positions.store'), $positionData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('positions', $positionData);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_edit_position()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.positions.edit', $this->position->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_edit_position()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.positions.edit', $this->position->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_update_position()
|
||||
{
|
||||
$updatedData = [
|
||||
'code' => 'UPD',
|
||||
'name' => 'Updated Position',
|
||||
'level' => 3
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->put(route('users.positions.update', $this->position->id), $updatedData);
|
||||
|
||||
$response->assertRedirect(route('users.positions.index'));
|
||||
$this->assertDatabaseHas('positions', $updatedData);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_update_position()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$updatedData = [
|
||||
'code' => 'UPD',
|
||||
'name' => 'Updated Position',
|
||||
'level' => 3
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->put(route('users.positions.update', $this->position->id), $updatedData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('positions', $updatedData);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_delete_position()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->delete(route('users.positions.destroy', $this->position->id));
|
||||
|
||||
$response->assertRedirect(route('users.positions.index'));
|
||||
$this->assertSoftDeleted($this->position);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_delete_position()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->delete(route('users.positions.destroy', $this->position->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseHas('positions', ['id' => $this->position->id, 'deleted_at' => null]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_access_datatables_data()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.positions.datatables'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'draw',
|
||||
'recordsTotal',
|
||||
'recordsFiltered',
|
||||
'pageCount',
|
||||
'page',
|
||||
'totalCount',
|
||||
'data'
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_access_datatables_data()
|
||||
{
|
||||
// Create a role without permissions
|
||||
$role = Role::create(['name' => 'viewer', 'guard_name' => 'web']);
|
||||
|
||||
// Create a user with the viewer role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.positions.datatables'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_export_positions()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.positions.export'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_export_positions()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.positions.export'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function cannot_delete_position_if_it_has_associated_roles()
|
||||
{
|
||||
// Create a role associated with the position
|
||||
$role = Role::create([
|
||||
'name' => 'Position-Linked Role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
// Attempt to delete the position
|
||||
$response = $this->actingAs($this->user)
|
||||
->delete(route('users.positions.destroy', $this->position->id));
|
||||
|
||||
// Assert that the request is redirected back with an error message
|
||||
$response->assertRedirect(route('users.positions.index'));
|
||||
$response->assertSessionHas('error');
|
||||
|
||||
// Assert that the position still exists in the database (not deleted)
|
||||
$this->assertDatabaseHas('positions', [
|
||||
'id' => $this->position->id,
|
||||
'deleted_at' => null
|
||||
]);
|
||||
}
|
||||
}
|
||||
467
tests/Feature/RolesControllerTest.php
Normal file
467
tests/Feature/RolesControllerTest.php
Normal file
@@ -0,0 +1,467 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Modules\Usermanagement\Models\Position;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
|
||||
class RolesControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $user;
|
||||
protected $adminRole;
|
||||
protected $position;
|
||||
protected $testRole;
|
||||
protected $permissionGroup;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create permission group first
|
||||
$this->permissionGroup = PermissionGroup::create([
|
||||
'name' => 'usermanagement',
|
||||
'slug' => 'usermanagement'
|
||||
]);
|
||||
|
||||
// Create permissions with permission_group_id
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.create',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.read',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.update',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.delete',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.export',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.restore',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $this->permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create admin role with all permissions
|
||||
$this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$this->adminRole->givePermissionTo(Permission::all());
|
||||
|
||||
// Create a user with admin role
|
||||
$this->user = User::factory()->create();
|
||||
$this->user->assignRole($this->adminRole);
|
||||
|
||||
// Create a position for testing
|
||||
$this->position = Position::create([
|
||||
'code' => 'TEST',
|
||||
'name' => 'Test Position',
|
||||
'level' => 1
|
||||
]);
|
||||
|
||||
// Create a test role for testing
|
||||
$this->testRole = Role::create([
|
||||
'name' => 'test-role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
$this->testRole->givePermissionTo('usermanagement.read');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_view_roles_index()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_view_roles_index()
|
||||
{
|
||||
// Create a role without permissions
|
||||
$role = Role::create(['name' => 'viewer', 'guard_name' => 'web']);
|
||||
|
||||
// Create a user with the viewer role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.roles.index'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_create_role()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.create'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_create_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.roles.create'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_store_role()
|
||||
{
|
||||
$permissions = Permission::where('name', 'usermanagement.read')->pluck('id')->toArray();
|
||||
|
||||
$roleData = [
|
||||
'name' => 'New Role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id,
|
||||
'permissions' => $permissions
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->post(route('users.roles.store'), $roleData);
|
||||
|
||||
$response->assertRedirect(route('users.roles.index'));
|
||||
$this->assertDatabaseHas('roles', [
|
||||
'name' => 'New Role',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
// Check if permission was assigned
|
||||
$newRole = Role::where('name', 'New Role')->first();
|
||||
$this->assertTrue($newRole->hasPermissionTo('usermanagement.read'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_store_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$permissions = Permission::where('name', 'usermanagement.read')->pluck('id')->toArray();
|
||||
|
||||
$roleData = [
|
||||
'name' => 'New Role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id,
|
||||
'permissions' => $permissions
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post(route('users.roles.store'), $roleData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('roles', ['name' => 'New Role']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_edit_role()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.edit', $this->testRole->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_edit_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.roles.edit', $this->testRole->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_update_role()
|
||||
{
|
||||
$permissions = Permission::whereIn('name', ['usermanagement.read', 'usermanagement.update'])->pluck('id')->toArray();
|
||||
|
||||
$updatedData = [
|
||||
'name' => 'Updated Role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id,
|
||||
'permissions' => $permissions
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->put(route('users.roles.update', $this->testRole->id), $updatedData);
|
||||
|
||||
$response->assertRedirect(route('users.roles.index'));
|
||||
$this->assertDatabaseHas('roles', [
|
||||
'id' => $this->testRole->id,
|
||||
'name' => 'Updated Role',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
// Check if permissions were updated
|
||||
$updatedRole = Role::find($this->testRole->id);
|
||||
$this->assertTrue($updatedRole->hasPermissionTo('usermanagement.read'));
|
||||
$this->assertTrue($updatedRole->hasPermissionTo('usermanagement.update'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_update_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$permissions = Permission::whereIn('name', ['usermanagement.read', 'usermanagement.update'])->pluck('id')->toArray();
|
||||
|
||||
$updatedData = [
|
||||
'name' => 'Updated Role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id,
|
||||
'permissions' => $permissions
|
||||
];
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->put(route('users.roles.update', $this->testRole->id), $updatedData);
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseMissing('roles', [
|
||||
'id' => $this->testRole->id,
|
||||
'name' => 'Updated Role'
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_delete_role()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->delete(route('users.roles.destroy', $this->testRole->id));
|
||||
|
||||
// The destroy method returns JSON response
|
||||
$response->assertJson([
|
||||
'message' => 'Role deleted successfully.',
|
||||
'success' => true
|
||||
]);
|
||||
|
||||
$this->assertSoftDeleted($this->testRole);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_delete_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->delete(route('users.roles.destroy', $this->testRole->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertDatabaseHas('roles', [
|
||||
'id' => $this->testRole->id,
|
||||
'deleted_at' => null
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_restore_role()
|
||||
{
|
||||
// First soft delete the role
|
||||
$this->testRole->delete();
|
||||
$this->assertSoftDeleted($this->testRole);
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.restore', $this->testRole->id));
|
||||
|
||||
$response->assertRedirect(route('users.roles.index'));
|
||||
$this->assertDatabaseHas('roles', [
|
||||
'id' => $this->testRole->id,
|
||||
'deleted_at' => null
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_restore_role()
|
||||
{
|
||||
// Create a role with only read permission
|
||||
$role = Role::create(['name' => 'reader', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with the reader role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
// First soft delete the role
|
||||
$this->testRole->delete();
|
||||
$this->assertSoftDeleted($this->testRole);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.roles.restore', $this->testRole->id));
|
||||
|
||||
$response->assertStatus(403);
|
||||
$this->assertSoftDeleted($this->testRole);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_access_datatables_data()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.datatables'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'draw',
|
||||
'recordsTotal',
|
||||
'recordsFiltered',
|
||||
'pageCount',
|
||||
'page',
|
||||
'totalCount',
|
||||
'data'
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_without_permission_cannot_access_datatables_data()
|
||||
{
|
||||
// Create a role without permissions
|
||||
$role = Role::create(['name' => 'viewer', 'guard_name' => 'web']);
|
||||
|
||||
// Create a user with the viewer role
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole($role);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('users.roles.datatables'));
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function user_with_permission_can_export_roles()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.export'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function datatables_search_filters_roles_correctly()
|
||||
{
|
||||
// Create additional roles for testing search
|
||||
Role::create([
|
||||
'name' => 'searchable-role',
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.datatables', ['search' => 'searchable']));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$responseData = json_decode($response->getContent(), true);
|
||||
|
||||
// Check that the search returned the correct role
|
||||
$this->assertGreaterThan(0, $responseData['recordsFiltered']);
|
||||
$foundSearchableRole = false;
|
||||
foreach ($responseData['data'] as $role) {
|
||||
if ($role['name'] === 'searchable-role') {
|
||||
$foundSearchableRole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($foundSearchableRole);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function datatables_sorting_works_correctly()
|
||||
{
|
||||
// Create additional roles for testing sorting
|
||||
Role::create([
|
||||
'name' => 'A-role', // Should come first in ascending order
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
Role::create([
|
||||
'name' => 'Z-role', // Should come last in ascending order
|
||||
'guard_name' => 'web',
|
||||
'position_id' => $this->position->id
|
||||
]);
|
||||
|
||||
// Test ascending order
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.datatables', [
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'asc'
|
||||
]));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$responseData = json_decode($response->getContent(), true);
|
||||
|
||||
// Check that the first role is 'A-role'
|
||||
$this->assertEquals('A-role', $responseData['data'][0]['name']);
|
||||
|
||||
// Test descending order
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.roles.datatables', [
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'desc'
|
||||
]));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$responseData = json_decode($response->getContent(), true);
|
||||
|
||||
// Check that the first role is 'Z-role'
|
||||
$this->assertEquals('Z-role', $responseData['data'][0]['name']);
|
||||
}
|
||||
}
|
||||
466
tests/Feature/UsersControllerTest.php
Normal file
466
tests/Feature/UsersControllerTest.php
Normal file
@@ -0,0 +1,466 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Usermanagement\Tests\Feature;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
use Modules\Usermanagement\Models\User;
|
||||
use Modules\Usermanagement\Models\Role;
|
||||
use Modules\Usermanagement\Models\Permission;
|
||||
use Modules\Usermanagement\Models\PermissionGroup;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
|
||||
class UsersControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $user;
|
||||
protected $adminRole;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create permission group
|
||||
$permissionGroup = PermissionGroup::create([
|
||||
'name' => 'usermanagement',
|
||||
'slug' => 'usermanagement'
|
||||
]);
|
||||
|
||||
// Create usermanagement.read permission
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.read',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create role with usermanagement.read permission
|
||||
$this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$this->adminRole->givePermissionTo('usermanagement.read');
|
||||
|
||||
// Create a user with admin role
|
||||
// Create a user for testing
|
||||
$this->user = User::factory()->create([
|
||||
'name' => 'Original Name',
|
||||
'email' => 'original@example.com',
|
||||
'nik' => '123456',
|
||||
'sign' => 'old-signature.jpg'
|
||||
]);
|
||||
|
||||
// Mock the storage
|
||||
Storage::fake('public');
|
||||
$this->user->assignRole($this->adminRole);
|
||||
|
||||
// Create test role for assignment to new user
|
||||
Role::create(['name' => 'operator', 'guard_name' => 'web']);
|
||||
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_display_users_index_page_when_user_has_users_view_permission()
|
||||
{
|
||||
$response = $this->actingAs($this->user)
|
||||
->get(route('users.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertViewIs('usermanagement::users.index');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_return_json_response_with_correct_pagination_data_for_datatables()
|
||||
{
|
||||
// Create some test users
|
||||
$testUsers = User::factory()->count(15)->create();
|
||||
|
||||
// Set up the request parameters
|
||||
$requestData = [
|
||||
'draw' => 1,
|
||||
'page' => 1, // Changed from 2 to 1 to match the controller logic
|
||||
'size' => 5,
|
||||
'search' => '',
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'asc'
|
||||
];
|
||||
|
||||
// Make the request
|
||||
$response = $this->actingAs($this->user)
|
||||
->getJson(route('users.datatables') . '?' . http_build_query($requestData));
|
||||
|
||||
// Assert response status and structure
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'draw',
|
||||
'recordsTotal',
|
||||
'recordsFiltered',
|
||||
'pageCount',
|
||||
'page',
|
||||
'totalCount',
|
||||
'data'
|
||||
]);
|
||||
|
||||
// Get total count of users for verification (16 = 15 created + 1 from setup)
|
||||
$totalUsers = User::count();
|
||||
|
||||
// Verify the pagination data
|
||||
$responseData = $response->json();
|
||||
$this->assertEquals(1, $responseData['draw']);
|
||||
$this->assertEquals($totalUsers, $responseData['recordsTotal']);
|
||||
$this->assertEquals($totalUsers, $responseData['recordsFiltered']);
|
||||
$this->assertEquals(ceil($totalUsers / $requestData['size']), $responseData['pageCount']);
|
||||
$this->assertEquals($requestData['page'], $responseData['page']);
|
||||
|
||||
// Verify that we have the correct number of users in the response
|
||||
$this->assertCount(5, $responseData['data']);
|
||||
|
||||
// Verify that the data is ordered correctly - get first page of sorted data
|
||||
$this->assertEquals(
|
||||
User::orderBy('name', 'asc')->take(5)->pluck('id')->toArray(),
|
||||
collect($responseData['data'])->pluck('id')->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_filter_users_by_search_term_when_search_parameter_is_provided()
|
||||
{
|
||||
// Create test users with specific names for testing search
|
||||
$matchingUser1 = User::factory()->create(['name' => 'Test User One']);
|
||||
$matchingUser2 = User::factory()->create(['email' => 'test@example.com']);
|
||||
$nonMatchingUser = User::factory()->create(['name' => 'Different User', 'email' => 'different@example.com']);
|
||||
|
||||
// Set up the request parameters with search term
|
||||
$requestData = [
|
||||
'draw' => 1,
|
||||
'page' => 1,
|
||||
'size' => 10,
|
||||
'search' => 'test',
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'asc'
|
||||
];
|
||||
|
||||
// Make the request
|
||||
$response = $this->actingAs($this->user)
|
||||
->getJson(route('users.datatables') . '?' . http_build_query($requestData));
|
||||
|
||||
// Assert response status and structure
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'draw',
|
||||
'recordsTotal',
|
||||
'recordsFiltered',
|
||||
'pageCount',
|
||||
'page',
|
||||
'totalCount',
|
||||
'data'
|
||||
]);
|
||||
|
||||
// Get the response data
|
||||
$responseData = $response->json();
|
||||
|
||||
// Verify that only matching users are returned
|
||||
$this->assertEquals(2, $responseData['recordsFiltered']);
|
||||
|
||||
// Extract user IDs from the response
|
||||
$returnedUserIds = collect($responseData['data'])->pluck('id')->toArray();
|
||||
|
||||
// Verify the correct users are returned
|
||||
$this->assertContains($matchingUser1->id, $returnedUserIds);
|
||||
$this->assertContains($matchingUser2->id, $returnedUserIds);
|
||||
$this->assertNotContains($nonMatchingUser->id, $returnedUserIds);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_correctly_sort_users_when_sortField_and_sortOrder_parameters_are_specified()
|
||||
{
|
||||
// Create test users with varying names to test different sort orders
|
||||
$userA = User::factory()->create(['name' => 'Adam Smith']);
|
||||
$userB = User::factory()->create(['name' => 'Brian Jones']);
|
||||
$userC = User::factory()->create(['name' => 'Charlie Brown']);
|
||||
|
||||
// Test ascending order
|
||||
$requestDataAsc = [
|
||||
'draw' => 1,
|
||||
'page' => 1,
|
||||
'size' => 10,
|
||||
'search' => '',
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'asc'
|
||||
];
|
||||
|
||||
$responseAsc = $this->actingAs($this->user)
|
||||
->getJson(route('users.datatables') . '?' . http_build_query($requestDataAsc));
|
||||
|
||||
$responseAsc->assertStatus(200);
|
||||
$responseDataAsc = $responseAsc->json();
|
||||
|
||||
// Check if sorted ascending by name
|
||||
$userIdsAsc = collect($responseDataAsc['data'])->pluck('id')->toArray();
|
||||
$expectedOrderAsc = User::orderBy('name', 'asc')->pluck('id')->toArray();
|
||||
$this->assertEquals($expectedOrderAsc, $userIdsAsc);
|
||||
|
||||
// Test descending order
|
||||
$requestDataDesc = [
|
||||
'draw' => 1,
|
||||
'page' => 1,
|
||||
'size' => 10,
|
||||
'search' => '',
|
||||
'sortField' => 'name',
|
||||
'sortOrder' => 'desc'
|
||||
];
|
||||
|
||||
$responseDesc = $this->actingAs($this->user)
|
||||
->getJson(route('users.datatables') . '?' . http_build_query($requestDataDesc));
|
||||
|
||||
$responseDesc->assertStatus(200);
|
||||
$responseDataDesc = $responseDesc->json();
|
||||
|
||||
// Check if sorted descending by name
|
||||
$userIdsDesc = collect($responseDataDesc['data'])->pluck('id')->toArray();
|
||||
$expectedOrderDesc = User::orderBy('name', 'desc')->pluck('id')->toArray();
|
||||
$this->assertEquals($expectedOrderDesc, $userIdsDesc);
|
||||
|
||||
// Test sorting by a different field (email)
|
||||
$requestDataEmail = [
|
||||
'draw' => 1,
|
||||
'page' => 1,
|
||||
'size' => 10,
|
||||
'search' => '',
|
||||
'sortField' => 'email',
|
||||
'sortOrder' => 'asc'
|
||||
];
|
||||
|
||||
$responseEmail = $this->actingAs($this->user)
|
||||
->getJson(route('users.datatables') . '?' . http_build_query($requestDataEmail));
|
||||
|
||||
$responseEmail->assertStatus(200);
|
||||
$responseDataEmail = $responseEmail->json();
|
||||
|
||||
// Check if sorted by email
|
||||
$userIdsEmail = collect($responseDataEmail['data'])->pluck('id')->toArray();
|
||||
$expectedOrderEmail = User::orderBy('email', 'asc')->pluck('id')->toArray();
|
||||
$this->assertEquals($expectedOrderEmail, $userIdsEmail);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_successfully_create_a_new_user_and_assign_roles_when_valid_data_is_submitted()
|
||||
{
|
||||
// Prepare valid user data
|
||||
$userData = [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => 'password123',
|
||||
'password_confirmation' => 'password123',
|
||||
'nik' => '789234',
|
||||
'roles' => ['operator']
|
||||
];
|
||||
|
||||
// Submit the request to create a new user
|
||||
$response = $this->actingAs($this->user)
|
||||
->post(route('users.store'), $userData);
|
||||
|
||||
// Assert redirect to users index page with success message
|
||||
$response->assertRedirect(route('users.index'));
|
||||
$response->assertSessionHas('success', 'User created successfully.');
|
||||
|
||||
// Assert the user was created in the database
|
||||
$this->assertDatabaseHas('users', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'nik' => '789234'
|
||||
]);
|
||||
|
||||
// Assert the user was assigned the correct role
|
||||
$newUser = User::where('email', 'test@example.com')->first();
|
||||
$this->assertTrue($newUser->hasRole('operator'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_successfully_update_existing_user_information_and_role_assignments()
|
||||
{
|
||||
// Create a test user with admin role
|
||||
$userToUpdate = User::factory()->create([
|
||||
'name' => 'Original Name',
|
||||
'email' => 'originalee@example.com',
|
||||
'nik' => '987654'
|
||||
]);
|
||||
$userToUpdate->assignRole($this->adminRole);
|
||||
|
||||
// Create an additional role for the update test
|
||||
$newRole = Role::create(['name' => 'editor', 'guard_name' => 'web']);
|
||||
|
||||
// Prepare update data
|
||||
$updateData = [
|
||||
'name' => 'Updated Name',
|
||||
'email' => 'updated@example.com',
|
||||
'nik' => '654321',
|
||||
'roles' => ['operator'] // Change role from admin to operator
|
||||
];
|
||||
|
||||
// Make the request to update the user
|
||||
$response = $this->actingAs($this->user)
|
||||
->put(route('users.update', $userToUpdate->id), $updateData);
|
||||
|
||||
// Assert redirect to users index page with success message
|
||||
$response->assertRedirect(route('users.index'));
|
||||
$response->assertSessionHas('success', 'User updated successfully.');
|
||||
|
||||
// Assert the user was updated in the database
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $userToUpdate->id,
|
||||
'name' => 'Updated Name',
|
||||
'email' => 'updated@example.com',
|
||||
'nik' => '654321'
|
||||
]);
|
||||
|
||||
// Refresh the user model from database
|
||||
$userToUpdate->refresh();
|
||||
|
||||
// Assert the user has the new role and doesn't have the old role
|
||||
$this->assertTrue($userToUpdate->hasRole('operator'));
|
||||
$this->assertFalse($userToUpdate->hasRole('admin'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_delete_a_user_when_the_authenticated_user_has_users_delete_permission()
|
||||
{
|
||||
// Create the permission for delete users
|
||||
$permissionGroup = PermissionGroup::create([
|
||||
'name' => 'usermanagement',
|
||||
'slug' => 'usermanagement'
|
||||
]);
|
||||
|
||||
// Create delete permission
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.delete',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create role with delete permission
|
||||
$role = Role::create(['name' => 'manager', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.delete');
|
||||
|
||||
// Create an admin user with the role that has delete permission
|
||||
$adminUser = User::factory()->create();
|
||||
$adminUser->assignRole($role);
|
||||
|
||||
// Create a user to be deleted
|
||||
$userToDelete = User::factory()->create();
|
||||
|
||||
// Make the request to delete the user
|
||||
$response = $this->actingAs($adminUser)
|
||||
->delete(route('users.destroy', $userToDelete->id));
|
||||
|
||||
// Assert the response is correct
|
||||
$decodedResponse = json_decode($response->getContent(), true);
|
||||
$this->assertEquals('User deleted successfully.', $decodedResponse['message']);
|
||||
$this->assertTrue($decodedResponse['success']);
|
||||
|
||||
// Assert the user was soft deleted
|
||||
$this->assertSoftDeleted('users', ['id' => $userToDelete->id]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_restore_a_soft_deleted_user_when_the_authenticated_user_has_users_restore_permission()
|
||||
{
|
||||
// Create permission group
|
||||
$permissionGroup = PermissionGroup::create([
|
||||
'name' => 'usermanagement',
|
||||
'slug' => 'usermanagement'
|
||||
]);
|
||||
|
||||
// Create restore permission
|
||||
Permission::create([
|
||||
'name' => 'usermanagement.restore',
|
||||
'guard_name' => 'web',
|
||||
'permission_group_id' => $permissionGroup->id
|
||||
]);
|
||||
|
||||
// Create role with restore permission
|
||||
$role = Role::create(['name' => 'restorer', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('usermanagement.restore');
|
||||
|
||||
// Create an admin user with the role that has restore permission
|
||||
$adminUser = User::factory()->create();
|
||||
$adminUser->assignRole($role);
|
||||
|
||||
// Create a user to be restored
|
||||
$userToRestore = User::factory()->create();
|
||||
$userToRestore->delete(); // Soft delete the user
|
||||
|
||||
// Verify the user is soft-deleted
|
||||
$this->assertSoftDeleted('users', ['id' => $userToRestore->id]);
|
||||
|
||||
// Make the request to restore the user
|
||||
$response = $this->actingAs($adminUser)
|
||||
->get(route('users.restore', $userToRestore->id));
|
||||
|
||||
// Assert the response redirects to users.index with success message
|
||||
$response->assertRedirect(route('users.index'));
|
||||
$response->assertSessionHas('success', 'User restored successfully.');
|
||||
|
||||
// Assert the user was restored
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $userToRestore->id,
|
||||
'deleted_at' => null
|
||||
]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function should_update_users_profile_including_signature_image_when_valid_data_is_submitted()
|
||||
{
|
||||
// Create a fake signature file
|
||||
$file = UploadedFile::fake()->image('new-signature.jpg');
|
||||
|
||||
// Create a fake old signature file in storage
|
||||
Storage::disk('public')->put(
|
||||
'signatures/' . $this->user->id . '/old-signature.jpg',
|
||||
'fake content'
|
||||
);
|
||||
|
||||
// Prepare valid profile data with new signature
|
||||
$profileData = [
|
||||
'name' => 'Updated Name',
|
||||
'email' => 'updated@example.com',
|
||||
'nik' => '654321',
|
||||
'sign' => $file
|
||||
];
|
||||
|
||||
// Make the request to update the profile
|
||||
$response = $this->actingAs($this->user)
|
||||
->put(route('users.update-profile'), $profileData);
|
||||
|
||||
// Assert redirect to profile page with success message
|
||||
$response->assertRedirect(route('users.profile'));
|
||||
$response->assertSessionHas('success', 'Profile updated successfully.');
|
||||
|
||||
// Assert the user was updated in the database
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $this->user->id,
|
||||
'name' => 'Updated Name',
|
||||
'email' => 'updated@example.com',
|
||||
'nik' => '654321',
|
||||
]);
|
||||
|
||||
// Refresh the user model from database
|
||||
$this->user->refresh();
|
||||
|
||||
// Assert that the user has a sign value (any non-empty string)
|
||||
$this->assertNotEmpty($this->user->sign);
|
||||
|
||||
// Debug information
|
||||
$files = Storage::disk('public')->allFiles('signatures/' . $this->user->id);
|
||||
|
||||
// Assert the file has been stored in the expected location
|
||||
// Use a more flexible check that doesn't rely on the exact filename
|
||||
$signaturePath = 'signatures/' . $this->user->id;
|
||||
$this->assertTrue(
|
||||
Storage::disk('public')->exists($signaturePath . '/' . $this->user->sign),
|
||||
"Signature file not found at expected location: {$signaturePath}/{$this->user->sign}"
|
||||
);
|
||||
|
||||
// Verify old signature was deleted
|
||||
Storage::disk('public')->assertMissing('signatures/' . $this->user->id . '/old-signature.jpg');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user