2018-07-24 19:35:26 -07:00
< ? php
namespace App\Http\Controllers\Users ;
2023-03-17 16:24:58 -07:00
use App\Events\UserMerged ;
2018-07-24 19:35:26 -07:00
use App\Helpers\Helper ;
use App\Http\Controllers\Controller ;
use App\Models\Accessory ;
2022-07-20 17:57:19 -07:00
use App\Models\License ;
2018-07-24 19:35:26 -07:00
use App\Models\Actionlog ;
use App\Models\Asset ;
use App\Models\Group ;
use App\Models\LicenseSeat ;
2022-07-20 17:57:19 -07:00
use App\Models\ConsumableAssignment ;
use App\Models\Consumable ;
2018-07-24 19:35:26 -07:00
use App\Models\User ;
2023-03-16 18:19:16 -07:00
use Carbon\Carbon ;
2018-07-24 19:35:26 -07:00
use Illuminate\Http\Request ;
use Illuminate\Support\Facades\Auth ;
use Illuminate\Support\Facades\DB ;
2018-07-30 20:30:47 -07:00
use Illuminate\Support\Facades\Password ;
2024-05-29 04:38:15 -07:00
use Illuminate\Support\Facades\Log ;
2018-07-24 19:35:26 -07:00
class BulkUsersController extends Controller
{
/**
2023-03-17 16:24:38 -07:00
* Returns a view that confirms the user ' s a bulk action will be applied to .
2018-07-24 19:35:26 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
* @ since [ v1 . 7 ]
* @ param Request $request
* @ return \Illuminate\Contracts\View\View
* @ throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit ( Request $request )
{
$this -> authorize ( 'update' , User :: class );
2018-07-30 20:37:19 -07:00
// Make sure there were users selected
2018-07-24 22:51:31 -07:00
if (( $request -> filled ( 'ids' )) && ( count ( $request -> input ( 'ids' )) > 0 )) {
2023-03-17 16:24:38 -07:00
2018-07-30 20:37:19 -07:00
// Get the list of affected users
2021-10-21 11:28:58 -07:00
$user_raw_array = request ( 'ids' );
$users = User :: whereIn ( 'id' , $user_raw_array )
2024-07-03 15:18:37 -07:00
-> with ( 'assets' , 'manager' , 'userlog' , 'licenses' , 'consumables' , 'accessories' , 'managedLocations' , 'uploads' , 'acceptances' ) -> get ();
2018-07-30 20:30:47 -07:00
2023-03-17 16:24:38 -07:00
// bulk edit, display the bulk edit form
2018-07-24 19:35:26 -07:00
if ( $request -> input ( 'bulk_actions' ) == 'edit' ) {
return view ( 'users/bulk-edit' , compact ( 'users' ))
-> with ( 'groups' , Group :: pluck ( 'name' , 'id' ));
2023-03-17 16:24:38 -07:00
// bulk delete, display the bulk delete confirmation form
2018-07-30 20:30:47 -07:00
} elseif ( $request -> input ( 'bulk_actions' ) == 'delete' ) {
2021-06-10 13:15:52 -07:00
return view ( 'users/confirm-bulk-delete' ) -> with ( 'users' , $users ) -> with ( 'statuslabel_list' , Helper :: statusLabelList ());
2023-03-17 16:24:38 -07:00
// merge, confirm they have at least 2 users selected and display the merge screen
2023-03-16 18:19:16 -07:00
} elseif ( $request -> input ( 'bulk_actions' ) == 'merge' ) {
2023-03-17 16:24:38 -07:00
if (( $request -> filled ( 'ids' )) && ( count ( $request -> input ( 'ids' )) > 1 )) {
2023-03-17 16:24:58 -07:00
return view ( 'users/confirm-merge' ) -> with ( 'users' , $users );
2023-03-17 16:24:38 -07:00
// Not enough users selected, send them back
} else {
return redirect () -> back () -> with ( 'error' , trans ( 'general.not_enough_users_selected' , [ 'count' => 2 ]));
}
// bulk password reset, just do the thing
2018-07-30 20:30:47 -07:00
} elseif ( $request -> input ( 'bulk_actions' ) == 'bulkpasswordreset' ) {
2020-05-23 11:58:44 -07:00
foreach ( $users as $user ) {
2021-06-10 13:15:52 -07:00
if (( $user -> activated == '1' ) && ( $user -> email != '' )) {
2020-05-23 11:58:44 -07:00
$credentials = [ 'email' => $user -> email ];
2022-05-16 10:38:12 -07:00
Password :: sendResetLink ( $credentials /* , function ( Message $message ) {
$message -> subject ( $this -> getEmailSubject ()); // TODO - I'm not sure if we still need this, but this second parameter is no longer accepted in later Laravel versions.
} */ ); // TODO - so hopefully this doesn't give us generic password reset messages? But it at least _works_
2018-07-30 20:30:47 -07:00
}
}
2021-06-10 13:15:52 -07:00
return redirect () -> back () -> with ( 'success' , trans ( 'admin/users/message.password_resets_sent' ));
2018-07-30 20:30:47 -07:00
2018-07-24 19:35:26 -07:00
}
}
2023-03-17 02:42:50 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'general.no_users_selected' ));
2018-07-24 19:35:26 -07:00
}
/**
* Save bulk - edited users
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
* @ since [ v1 . 0 ]
* @ param Request $request
* @ return \Illuminate\Http\RedirectResponse
* @ throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update ( Request $request )
{
$this -> authorize ( 'update' , User :: class );
2021-06-10 13:15:52 -07:00
if (( ! $request -> filled ( 'ids' )) || $request -> input ( 'ids' ) <= 0 ) {
2023-03-17 02:42:50 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'general.no_users_selected' ));
2018-07-24 19:35:26 -07:00
}
$user_raw_array = $request -> input ( 'ids' );
// Remove the user from any updates.
$user_raw_array = array_diff ( $user_raw_array , [ Auth :: id ()]);
$manager_conflict = false ;
2024-07-04 12:49:22 -07:00
$users = User :: whereIn ( 'id' , $user_raw_array ) -> where ( 'id' , '!=' , auth () -> id ()) -> get ();
2018-07-24 19:35:26 -07:00
$return_array = [
2021-06-10 13:15:52 -07:00
'success' => trans ( 'admin/users/message.success.update_bulk' ),
2018-07-24 19:35:26 -07:00
];
$this -> conditionallyAddItem ( 'location_id' )
-> conditionallyAddItem ( 'department_id' )
-> conditionallyAddItem ( 'company_id' )
-> conditionallyAddItem ( 'locale' )
2022-03-04 06:47:23 -08:00
-> conditionallyAddItem ( 'remote' )
2022-05-18 15:37:10 -07:00
-> conditionallyAddItem ( 'ldap_import' )
2023-04-16 15:26:33 -07:00
-> conditionallyAddItem ( 'activated' )
-> conditionallyAddItem ( 'autoassign_licenses' );
2022-05-18 15:35:57 -07:00
2022-05-18 15:37:10 -07:00
2018-07-24 19:35:26 -07:00
// If the manager_id is one of the users being updated, generate a warning.
if ( array_search ( $request -> input ( 'manager_id' ), $user_raw_array )) {
$manager_conflict = true ;
$return_array = [
2021-06-10 13:15:52 -07:00
'warning' => trans ( 'admin/users/message.bulk_manager_warn' ),
2018-07-24 19:35:26 -07:00
];
}
2023-03-21 23:03:57 -07:00
2023-10-31 05:52:53 -07:00
/**
* Check to see if the user wants to actually blank out the values vs skip them
*/
2023-03-21 23:03:57 -07:00
if ( $request -> input ( 'null_location_id' ) == '1' ) {
$this -> update_array [ 'location_id' ] = null ;
}
2023-10-31 05:52:53 -07:00
if ( $request -> input ( 'null_department_id' ) == '1' ) {
$this -> update_array [ 'department_id' ] = null ;
}
if ( $request -> input ( 'null_manager_id' ) == '1' ) {
$this -> update_array [ 'manager_id' ] = null ;
}
if ( $request -> input ( 'null_company_id' ) == '1' ) {
$this -> update_array [ 'company_id' ] = null ;
}
2021-06-10 13:15:52 -07:00
if ( ! $manager_conflict ) {
2018-07-24 19:35:26 -07:00
$this -> conditionallyAddItem ( 'manager_id' );
}
// Save the updated info
User :: whereIn ( 'id' , $user_raw_array )
-> where ( 'id' , '!=' , Auth :: id ()) -> update ( $this -> update_array );
2022-05-18 15:35:57 -07:00
if ( array_key_exists ( 'location_id' , $this -> update_array )){
2022-04-06 17:23:49 -07:00
Asset :: where ( 'assigned_type' , User :: class )
-> whereIn ( 'assigned_to' , $user_raw_array )
-> update ([ 'location_id' => $this -> update_array [ 'location_id' ]]);
}
2018-07-24 19:35:26 -07:00
// Only sync groups if groups were selected
2018-07-24 22:51:31 -07:00
if ( $request -> filled ( 'groups' )) {
2018-07-24 19:35:26 -07:00
foreach ( $users as $user ) {
$user -> groups () -> sync ( $request -> input ( 'groups' ));
}
}
return redirect () -> route ( 'users.index' )
-> with ( $return_array );
}
/**
* Array to store update data per item
2021-06-10 13:15:52 -07:00
* @ var array
2018-07-24 19:35:26 -07:00
*/
private $update_array = [];
/**
* Adds parameter to update array for an item if it exists in request
2021-06-10 13:15:52 -07:00
* @ param string $field field name
2018-07-24 19:35:26 -07:00
* @ return BulkUsersController Model for Chaining
*/
protected function conditionallyAddItem ( $field )
{
2021-06-10 13:15:52 -07:00
if ( request () -> filled ( $field )) {
2018-07-24 19:35:26 -07:00
$this -> update_array [ $field ] = request () -> input ( $field );
}
2021-06-10 13:15:52 -07:00
2018-07-24 19:35:26 -07:00
return $this ;
}
/**
* Soft - delete bulk users
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
* @ since [ v1 . 0 ]
* @ param Request $request
* @ return \Illuminate\Http\RedirectResponse
* @ throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy ( Request $request )
{
$this -> authorize ( 'update' , User :: class );
2021-06-10 13:15:52 -07:00
if (( ! $request -> filled ( 'ids' )) || ( count ( $request -> input ( 'ids' )) == 0 )) {
2023-03-17 02:42:50 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'general.no_users_selected' ));
2018-07-24 19:35:26 -07:00
}
if ( config ( 'app.lock_passwords' )) {
2023-03-17 02:42:50 -07:00
return redirect () -> route ( 'users.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
2018-07-24 19:35:26 -07:00
}
2022-07-20 17:57:19 -07:00
2018-07-24 19:35:26 -07:00
$user_raw_array = request ( 'ids' );
if (( $key = array_search ( Auth :: id (), $user_raw_array )) !== false ) {
unset ( $user_raw_array [ $key ]);
}
$users = User :: whereIn ( 'id' , $user_raw_array ) -> get ();
2021-06-10 13:16:56 -07:00
$assets = Asset :: whereIn ( 'assigned_to' , $user_raw_array ) -> where ( 'assigned_type' , \App\Models\User :: class ) -> get ();
2018-07-24 19:35:26 -07:00
$accessories = DB :: table ( 'accessories_users' ) -> whereIn ( 'assigned_to' , $user_raw_array ) -> get ();
$licenses = DB :: table ( 'license_seats' ) -> whereIn ( 'assigned_to' , $user_raw_array ) -> get ();
2022-07-20 17:57:19 -07:00
$consumables = DB :: table ( 'consumables_users' ) -> whereIn ( 'assigned_to' , $user_raw_array ) -> get ();
if ((( $assets -> count () > 0 ) && (( ! $request -> filled ( 'status_id' )) || ( $request -> input ( 'status_id' ) == '' )))) {
return redirect () -> route ( 'users.index' ) -> with ( 'error' , 'No status selected' );
}
2018-07-24 19:35:26 -07:00
$this -> logItemCheckinAndDelete ( $assets , Asset :: class );
$this -> logItemCheckinAndDelete ( $accessories , Accessory :: class );
2022-07-20 17:57:19 -07:00
$this -> logItemCheckinAndDelete ( $licenses , License :: class );
$this -> logItemCheckinAndDelete ( $consumables , Consumable :: class );
2018-07-24 19:35:26 -07:00
Asset :: whereIn ( 'id' , $assets -> pluck ( 'id' )) -> update ([
'status_id' => e ( request ( 'status_id' )),
'assigned_to' => null ,
'assigned_type' => null ,
2022-10-26 00:54:37 -07:00
'expected_checkin' => null ,
2018-07-24 19:35:26 -07:00
]);
LicenseSeat :: whereIn ( 'id' , $licenses -> pluck ( 'id' )) -> update ([ 'assigned_to' => null ]);
2022-07-20 17:57:19 -07:00
ConsumableAssignment :: whereIn ( 'id' , $consumables -> pluck ( 'id' )) -> delete ();
2018-07-24 19:35:26 -07:00
foreach ( $users as $user ) {
2022-07-20 17:57:19 -07:00
$user -> consumables () -> sync ([]);
2018-07-24 19:35:26 -07:00
$user -> accessories () -> sync ([]);
2022-07-20 17:57:19 -07:00
if ( $request -> input ( 'delete_user' ) == '1' ) {
$user -> delete ();
}
2018-07-24 19:35:26 -07:00
}
2022-07-20 17:57:19 -07:00
$msg = trans ( 'general.bulk_checkin_success' );
if ( $request -> input ( 'delete_user' ) == '1' ) {
$msg = trans ( 'general.bulk_checkin_delete_success' );
}
return redirect () -> route ( 'users.index' ) -> with ( 'success' , $msg );
2018-07-24 19:35:26 -07:00
}
/**
* Generate an action log entry for each of a group of items .
* @ param $items
* @ param $itemType string name of items being passed .
*/
2021-06-10 13:15:52 -07:00
protected function logItemCheckinAndDelete ( $items , $itemType )
{
foreach ( $items as $item ) {
2022-08-25 17:16:48 -07:00
$item_id = $item -> id ;
2018-07-24 19:35:26 -07:00
$logAction = new Actionlog ();
2022-08-25 17:16:48 -07:00
2022-10-26 00:54:37 -07:00
if ( $itemType == License :: class ){
2022-08-25 17:16:48 -07:00
$item_id = $item -> license_id ;
}
2022-10-26 00:54:37 -07:00
2022-08-25 17:16:48 -07:00
$logAction -> item_id = $item_id ;
2018-07-24 19:35:26 -07:00
// We can't rely on get_class here because the licenses/accessories fetched above are not eloquent models, but simply arrays.
$logAction -> item_type = $itemType ;
$logAction -> target_id = $item -> assigned_to ;
$logAction -> target_type = User :: class ;
$logAction -> user_id = Auth :: id ();
2022-07-20 17:57:19 -07:00
$logAction -> note = 'Bulk checkin items' ;
2018-07-24 19:35:26 -07:00
$logAction -> logaction ( 'checkin from' );
}
}
2023-03-16 18:19:16 -07:00
/**
* Save bulk - edited users
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
* @ since [ v1 . 0 ]
* @ param Request $request
* @ return \Illuminate\Http\RedirectResponse
* @ throws \Illuminate\Auth\Access\AuthorizationException
*/
public function merge ( Request $request )
{
$this -> authorize ( 'update' , User :: class );
2023-03-17 02:42:50 -07:00
if ( config ( 'app.lock_passwords' )) {
return redirect () -> route ( 'users.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
}
2023-03-16 18:19:16 -07:00
$user_ids_to_merge = $request -> input ( 'ids_to_merge' );
$user_ids_to_merge = array_diff ( $user_ids_to_merge , array ( $request -> input ( 'merge_into_id' )));
2023-03-17 16:24:58 -07:00
if (( ! $request -> filled ( 'merge_into_id' )) || ( count ( $user_ids_to_merge ) < 1 )) {
2023-03-16 18:19:16 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'general.no_users_selected' ));
}
// Get the users
$merge_into_user = User :: find ( $request -> input ( 'merge_into_id' ));
2024-07-03 11:41:34 -07:00
$users_to_merge = User :: whereIn ( 'id' , $user_ids_to_merge ) -> with ( 'assets' , 'manager' , 'userlog' , 'licenses' , 'consumables' , 'accessories' , 'managedLocations' , 'uploads' , 'acceptances' ) -> get ();
2024-07-04 12:49:22 -07:00
$admin = User :: find ( auth () -> id ());
2023-03-16 18:19:16 -07:00
// Walk users
2023-03-17 16:24:58 -07:00
foreach ( $users_to_merge as $user_to_merge ) {
2023-03-16 18:19:16 -07:00
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> assets as $asset ) {
2024-05-29 04:38:15 -07:00
Log :: debug ( 'Updating asset: ' . $asset -> asset_tag . ' to ' . $merge_into_user -> id );
2023-03-16 18:19:16 -07:00
$asset -> assigned_to = $request -> input ( 'merge_into_id' );
$asset -> save ();
}
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> licenses as $license ) {
2024-05-29 04:38:15 -07:00
Log :: debug ( 'Updating license pivot: ' . $license -> id . ' to ' . $merge_into_user -> id );
2023-03-17 16:24:58 -07:00
$user_to_merge -> licenses () -> updateExistingPivot ( $license -> id , [ 'assigned_to' => $merge_into_user -> id ]);
2023-03-16 18:19:16 -07:00
}
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> consumables as $consumable ) {
2024-05-29 04:38:15 -07:00
Log :: debug ( 'Updating consumable pivot: ' . $consumable -> id . ' to ' . $merge_into_user -> id );
2023-03-17 16:24:58 -07:00
$user_to_merge -> consumables () -> updateExistingPivot ( $consumable -> id , [ 'assigned_to' => $merge_into_user -> id ]);
2023-03-16 18:19:16 -07:00
}
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> accessories as $accessory ) {
$user_to_merge -> accessories () -> updateExistingPivot ( $accessory -> id , [ 'assigned_to' => $merge_into_user -> id ]);
2023-03-16 18:19:16 -07:00
}
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> userlog as $log ) {
2024-07-03 06:29:49 -07:00
$log -> target_id = $merge_into_user -> id ;
2023-03-16 18:19:16 -07:00
$log -> save ();
}
2024-07-03 06:29:49 -07:00
foreach ( $user_to_merge -> uploads as $upload ) {
$upload -> item_id = $merge_into_user -> id ;
$upload -> save ();
}
foreach ( $user_to_merge -> acceptances as $acceptance ) {
$acceptance -> item_id = $merge_into_user -> id ;
$acceptance -> save ();
}
2023-03-17 16:24:58 -07:00
User :: where ( 'manager_id' , '=' , $user_to_merge -> id ) -> update ([ 'manager_id' => $merge_into_user -> id ]);
2023-03-16 18:19:16 -07:00
2023-03-17 16:24:58 -07:00
foreach ( $user_to_merge -> managedLocations as $managedLocation ) {
2023-03-16 18:19:16 -07:00
$managedLocation -> manager_id = $merge_into_user -> id ;
$managedLocation -> save ();
}
2023-03-17 16:24:58 -07:00
$user_to_merge -> delete ();
event ( new UserMerged ( $user_to_merge , $merge_into_user , $admin ));
2023-03-16 18:19:16 -07:00
}
2023-03-17 16:24:58 -07:00
return redirect () -> route ( 'users.index' ) -> with ( 'success' , trans ( 'general.merge_success' , [ 'count' => $users_to_merge -> count (), 'into_username' => $merge_into_user -> username ]));
2023-03-16 18:19:16 -07:00
}
2018-07-24 19:35:26 -07:00
}