Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net> # Conflicts: # public/css/build/app.css # public/css/build/overrides.css # public/css/dist/all.css # public/mix-manifest.json
This commit is contained in:
@@ -23,6 +23,7 @@ use App\Notifications\CurrentInventory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -480,8 +481,25 @@ class UsersController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
||||
}
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
// check for permissions related fields and pull them out if the current user cannot edit them
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
if ($request->filled('username')) {
|
||||
$user->username = $request->input('username');
|
||||
}
|
||||
|
||||
if ($request->filled('email')) {
|
||||
$user->email = $request->input('email');
|
||||
}
|
||||
|
||||
if ($request->filled('activated')) {
|
||||
$user->activated = $request->input('activated');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We need to use has() instead of filled()
|
||||
|
||||
@@ -13,14 +13,8 @@ use App\Models\Company;
|
||||
use App\Models\Group;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Redirect;
|
||||
use Str;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use App\Notifications\CurrentInventory;
|
||||
|
||||
@@ -129,7 +123,7 @@ class UsersController extends Controller
|
||||
}
|
||||
$user->permissions = json_encode($permissions_array);
|
||||
|
||||
// we have to invoke the
|
||||
// we have to invoke the form request here to handle image uploads
|
||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
@@ -235,20 +229,14 @@ class UsersController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Only save groups if the user is a superuser
|
||||
if (auth()->user()->isSuperUser()) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
}
|
||||
|
||||
// Update the user fields
|
||||
$user->username = trim($request->input('username'));
|
||||
$user->email = trim($request->input('email'));
|
||||
|
||||
$user->first_name = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
|
||||
$user->locale = $request->input('locale');
|
||||
$user->employee_num = $request->input('employee_num');
|
||||
$user->activated = $request->input('activated', 0);
|
||||
$user->jobtitle = $request->input('jobtitle', null);
|
||||
$user->phone = $request->input('phone');
|
||||
$user->location_id = $request->input('location_id', null);
|
||||
@@ -260,8 +248,6 @@ class UsersController extends Controller
|
||||
$user->city = $request->input('city', null);
|
||||
$user->state = $request->input('state', null);
|
||||
$user->country = $request->input('country', null);
|
||||
// if a user is editing themselves we should always keep activated true
|
||||
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
$user->vip = $request->input('vip', 0);
|
||||
@@ -270,30 +256,49 @@ class UsersController extends Controller
|
||||
$user->end_date = $request->input('end_date', null);
|
||||
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
|
||||
|
||||
// Set this here so that we can overwrite it later if the user is an admin or superadmin
|
||||
$user->activated = $request->input('activated', auth()->user()->is($user) ? 1 : $user->activated);
|
||||
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)
|
||||
->update(['location_id' => $request->input('location_id', null)]);
|
||||
|
||||
// Do we want to update the user password?
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
// check for permissions related fields and only set them if the user has permission to edit them
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
|
||||
$user->username = trim($request->input('username'));
|
||||
$user->email = trim($request->input('email'));
|
||||
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
|
||||
|
||||
// Do we want to update the user password?
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
$permissions_array = $request->input('permission');
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
if (! auth()->user()->isSuperUser()) {
|
||||
unset($permissions_array['superuser']);
|
||||
$permissions_array['superuser'] = $orig_superuser;
|
||||
}
|
||||
|
||||
$user->permissions = json_encode($permissions_array);
|
||||
|
||||
// Only save groups if the user is a superuser
|
||||
if (auth()->user()->isSuperUser()) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)
|
||||
->update(['location_id' => $user->location_id]);
|
||||
|
||||
$permissions_array = $request->input('permission');
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
if (! auth()->user()->isSuperUser()) {
|
||||
unset($permissions_array['superuser']);
|
||||
$permissions_array['superuser'] = $orig_superuser;
|
||||
}
|
||||
|
||||
$user->permissions = json_encode($permissions_array);
|
||||
|
||||
// Handle uploaded avatar
|
||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WelcomeNotification;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
|
||||
@@ -81,6 +82,7 @@ class UserImporter extends ItemImporter
|
||||
$this->item['username'] = $user_formatted_array['username'];
|
||||
}
|
||||
|
||||
|
||||
// Check if a numeric ID was passed. If it does, use that above all else.
|
||||
if ((array_key_exists('id', $this->item) && ($this->item['id'] != "") && (is_numeric($this->item['id'])))) {
|
||||
$user = User::find($this->item['id']);
|
||||
@@ -90,12 +92,25 @@ class UserImporter extends ItemImporter
|
||||
|
||||
if ($user) {
|
||||
|
||||
// If the user does not want to update existing values, only add new ones, bail out
|
||||
if (! $this->updating) {
|
||||
Log::debug('A matching User '.$this->item['name'].' already exists. ');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating User');
|
||||
|
||||
// Todo - check that this works
|
||||
if (!Gate::allows('canEditAuthFields', $user)) {
|
||||
unset($user->username);
|
||||
unset($user->email);
|
||||
unset($user->password);
|
||||
unset($user->activated);
|
||||
}
|
||||
|
||||
$user->update($this->sanitizeItemForUpdating($user));
|
||||
|
||||
// Why do we have to do this twice? Update should
|
||||
$user->save();
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
@@ -116,8 +131,12 @@ class UserImporter extends ItemImporter
|
||||
$this->log('No matching user, creating one');
|
||||
$user = new User();
|
||||
$user->created_by = auth()->id();
|
||||
|
||||
$user->fill($this->sanitizeItemForStoring($user));
|
||||
|
||||
// TODO - check for gate here I guess
|
||||
|
||||
|
||||
if ($user->save()) {
|
||||
$this->log('User '.$this->item['name'].' was created');
|
||||
|
||||
@@ -143,6 +162,7 @@ class UserImporter extends ItemImporter
|
||||
$this->logError($user, 'User');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch an existing department, or create new if it doesn't exist
|
||||
*
|
||||
|
||||
@@ -203,11 +203,19 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
{
|
||||
$user_groups = $this->groups;
|
||||
if (($this->permissions == '') && (count($user_groups) == 0)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_permissions = json_decode($this->permissions, true);
|
||||
$user_permissions = $this->permissions;
|
||||
|
||||
if (is_object($this->permissions)) {
|
||||
$user_permissions = json_decode(json_encode($this->permissions), true);
|
||||
}
|
||||
|
||||
if (is_string($this->permissions)) {
|
||||
$user_permissions = json_decode($this->permissions, true);
|
||||
}
|
||||
|
||||
|
||||
$is_user_section_permissions_set = ($user_permissions != '') && array_key_exists($section, $user_permissions);
|
||||
//If the user is explicitly granted, return true
|
||||
@@ -261,6 +269,18 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return $this->checkPermissionSection('superuser');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user is an admin
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v8.1.18]
|
||||
* @return bool
|
||||
*/
|
||||
public function isAdmin()
|
||||
{
|
||||
return $this->checkPermissionSection('admin');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the user can edit their own profile
|
||||
|
||||
@@ -101,13 +101,21 @@ class AuthServiceProvider extends ServiceProvider
|
||||
* This is where we set the superadmin permission to allow superadmins to be able to do everything within the system.
|
||||
*
|
||||
*/
|
||||
Gate::before(function ($user) {
|
||||
Gate::before(function ($user, $ability) {
|
||||
|
||||
// Disallow even superadmins to edit non-editable things when in demo mode.
|
||||
// (We have to do this to prevent jerks from trying to break the demo by editing things they shouldn't.)
|
||||
if (($ability == 'editableOnDemo') && (config('app.lock_passwords'))) {
|
||||
return false;
|
||||
}
|
||||
if ($user->isSuperUser()) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* GENERAL GATES
|
||||
*
|
||||
@@ -115,6 +123,45 @@ class AuthServiceProvider extends ServiceProvider
|
||||
* use in our controllers to determine if a user has access to a certain area.
|
||||
*/
|
||||
|
||||
Gate::define('canEditAuthFields', function ($user, $item) {
|
||||
|
||||
if ($item instanceof User) {
|
||||
|
||||
// if they can only edit users, deny them if the user is admin or superadmin
|
||||
if (($user->hasAccess('users.edit')) && (!$user->isAdmin()) && (!$user->isAdmin())) {
|
||||
|
||||
if ($item->isAdmin() || $item->isSuperUser()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// if they are an admin, deny them only if the user is a superadmin
|
||||
if ($user->hasAccess('admin')) {
|
||||
if ($item->isSuperUser()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Define the demo mode gate so we have an easy way to use @can and Gate::allows()
|
||||
*/
|
||||
Gate::define('editableOnDemo', function () {
|
||||
if (config('app.lock_passwords')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Gate::define('admin', function ($user) {
|
||||
if ($user->hasAccess('admin')) {
|
||||
return true;
|
||||
@@ -249,5 +296,6 @@ class AuthServiceProvider extends ServiceProvider
|
||||
return $user->canEditProfile();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,6 +1165,11 @@ input[type="radio"]:checked::before {
|
||||
display: table-row !important;
|
||||
}
|
||||
|
||||
.form-control-static {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
|
||||
td.text-right.text-padding-number-cell {
|
||||
padding-right: 30px !important;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -17,7 +17,7 @@ return array(
|
||||
'last_login' => 'Last Login',
|
||||
'last_name' => 'Last Name',
|
||||
'location' => 'Location',
|
||||
'lock_passwords' => 'Login details cannot be changed on this installation.',
|
||||
'lock_passwords' => 'Login details cannot be changed on the demo.',
|
||||
'manager' => 'Manager',
|
||||
'managed_locations' => 'Managed Locations',
|
||||
'managed_users' => 'Managed Users',
|
||||
|
||||
@@ -4,6 +4,7 @@ return [
|
||||
'2FA_reset' => '2FA reset',
|
||||
'accessories' => 'Accessories',
|
||||
'activated' => 'Activated',
|
||||
'login_status' => 'Login Status',
|
||||
'accepted_date' => 'Date Accepted',
|
||||
'accessory' => 'Accessory',
|
||||
'accessory_report' => 'Accessory Report',
|
||||
@@ -316,6 +317,7 @@ return [
|
||||
'upload_filetypes_help' => 'Allowed filetypes are: :allowed_filetypes. Max upload size allowed is :size.',
|
||||
'uploaded' => 'Uploaded',
|
||||
'user' => 'User',
|
||||
'password' => 'Password',
|
||||
'accepted' => 'accepted',
|
||||
'declined' => 'declined',
|
||||
'declined_note' => 'Declined Notes',
|
||||
@@ -476,7 +478,7 @@ return [
|
||||
'update_existing_values' => 'Update Existing Values?',
|
||||
'auto_incrementing_asset_tags_disabled_so_tags_required' => 'Generating auto-incrementing asset tags is disabled so all rows need to have the "Asset Tag" column populated.',
|
||||
'auto_incrementing_asset_tags_enabled_so_now_assets_will_be_created' => 'Note: Generating auto-incrementing asset tags is enabled so assets will be created for rows that do not have "Asset Tag" populated. Rows that do have "Asset Tag" populated will be updated with the provided information.',
|
||||
'send_welcome_email_to_users' => ' Send Welcome Email for new Users?',
|
||||
'send_welcome_email_to_users' => ' Send Welcome Email for new Users? Note that only users with a valid email address and who are marked as activated in your import file will received a welcome.',
|
||||
'send_email' => 'Send Email',
|
||||
'call' => 'Call number',
|
||||
'back_before_importing' => 'Backup before importing?',
|
||||
|
||||
@@ -78,7 +78,9 @@
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#info" data-toggle="tab">{{ trans('general.information') }} </a></li>
|
||||
<li><a href="#permissions" data-toggle="tab">{{ trans('general.permissions') }} </a></li>
|
||||
@can('admin')
|
||||
<li><a href="#permissions" data-toggle="tab">{{ trans('general.permissions') }} </a></li>
|
||||
@endcan
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
@@ -93,138 +95,168 @@
|
||||
|
||||
<!-- Username -->
|
||||
<div class="form-group {{ $errors->has('username') ? 'has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="username">{{ trans('admin/users/table.username') }}</label>
|
||||
|
||||
<label class="col-md-3 control-label" for="username">
|
||||
{{ trans('admin/users/table.username') }}
|
||||
</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
@if ($user->ldap_import!='1' || str_contains(Route::currentRouteName(), 'clone'))
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
value="{{ old('username', $user->username) }}"
|
||||
autocomplete="off"
|
||||
maxlength="191"
|
||||
readonly
|
||||
{{ (Helper::checkIfRequired($user, 'username')) ? ' required' : '' }}
|
||||
onfocus="this.removeAttribute('readonly');"
|
||||
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
|
||||
>
|
||||
<input type="hidden" name="username" value="{{ old('username', $user->username) }}">
|
||||
<!-- if the user is not managed by LDAP, or this is a clone operation, allow editing of the username -->
|
||||
@if ($user->ldap_import!='1' || str_contains(Route::currentRouteName(), 'clone'))
|
||||
<input class="form-control" type="text" name="username" id="username" value="{{ old('username', $user->username) }}" autocomplete="off" maxlength="191" {{ (Helper::checkIfRequired($user, 'username')) ? ' required' : '' }} onfocus="this.removeAttribute('readonly');" readonly {{ (!Gate::allows('canEditAuthFields', $user)) || ((!Gate::allows('editableOnDemo')) && ($user->id)) ? ' disabled' : '' }}>
|
||||
@else
|
||||
|
||||
@else
|
||||
<!-- insert the old username so we don't break validation -->
|
||||
{{ trans('general.managed_ldap') }}
|
||||
<input type="hidden" name="username" value="{{ old('username', $user->username) }}">
|
||||
@endif
|
||||
</div>
|
||||
<!-- insert the old username so we don't break validation -->
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.managed_ldap') }}
|
||||
</p>
|
||||
<input type="hidden" name="username" value="{{ old('username', $user->username) }}">
|
||||
@endif
|
||||
|
||||
@cannot('canEditAuthFields', $user)
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.action_permission_generic', ['action' => trans('general.edit'), 'item_type' => trans('general.username')]) }}
|
||||
</p>
|
||||
@endcannot
|
||||
</div> <!--/col-md-6-->
|
||||
|
||||
|
||||
@if (config('app.lock_passwords') && ($user->id))
|
||||
<!-- disallow changing existing usernames on the demo -->
|
||||
<div class="col-md-8 col-md-offset-3">
|
||||
<p class="text-warning"><x-icon type="lock" /> {{ trans('general.feature_disabled') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if (!Gate::allows('editableOnDemo') && ($user->id))
|
||||
<!-- disallow changing existing usernames on the demo -->
|
||||
<div class="col-md-8 col-md-offset-3">
|
||||
<p class="text-warning">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/table.lock_passwords') }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($errors->first('username'))
|
||||
<div class="col-md-8 col-md-offset-3">
|
||||
{!! $errors->first('username', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
@endif
|
||||
@if ($errors->first('username'))
|
||||
<div class="col-md-8 col-md-offset-3">
|
||||
{!! $errors->first('username', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="form-group {{ $errors->has('password') ? 'has-error' : '' }}">
|
||||
|
||||
<label class="col-md-3 control-label" for="password">
|
||||
{{ trans('admin/users/table.password') }}
|
||||
</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
@if ($user->ldap_import!='1' || str_contains(Route::currentRouteName(), 'clone') )
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
value=""
|
||||
maxlength="500"
|
||||
autocomplete="off"
|
||||
readonly
|
||||
{{ ((Helper::checkIfRequired($user, 'password')) && (!$user->id)) ? ' required' : '' }}
|
||||
onfocus="this.removeAttribute('readonly');"
|
||||
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}>
|
||||
@else
|
||||
{{ trans('general.managed_ldap') }}
|
||||
@endif
|
||||
<span id="generated-password"></span>
|
||||
{!! $errors->first('password', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
@if ($user->ldap_import!='1' || str_contains(Route::currentRouteName(), 'clone') )
|
||||
<input type="password" name="password" class="form-control" id="password" value="" maxlength="500" autocomplete="off" onfocus="this.removeAttribute('readonly');" readonly {{ ((Helper::checkIfRequired($user, 'password')) && (!$user->id)) ? ' required' : '' }}{{ (!Gate::allows('canEditAuthFields', $user)) || ((!Gate::allows('editableOnDemo') && ($user->id))) ? ' disabled' : '' }}>
|
||||
<span id="generated-password"></span>
|
||||
{!! $errors->first('password', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
@else
|
||||
<p class="form-control-static">
|
||||
{{ trans('general.managed_ldap') }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@cannot('canEditAuthFields', $user)
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.action_permission_generic', ['action' => trans('general.edit'), 'item_type' => trans('general.password')]) }}
|
||||
</p>
|
||||
@endcan
|
||||
|
||||
@if (!Gate::allows('editableOnDemo') && ($user->id))
|
||||
<p class="text-warning">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/table.lock_passwords') }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
@if ($user->ldap_import!='1')
|
||||
|
||||
@if (Gate::allows('editableOnDemo') && (Gate::allows('canEditAuthFields', $user)) && ($user->ldap_import!='1'))
|
||||
<a href="#" class="left" id="genPassword">{{ trans('general.generate') }}</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (($user->ldap_import!='1') || str_contains(Route::currentRouteName(), 'clone'))
|
||||
<!-- Password Confirm -->
|
||||
<div class="form-group {{ $errors->has('password_confirmation') ? 'has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="password_confirmation">
|
||||
{{ trans('admin/users/table.password_confirm') }}
|
||||
</label>
|
||||
<div class="col-md-6">
|
||||
<input type="password" name="password_confirmation" id="password_confirm" class="form-control" value="" maxlength="500" autocomplete="off" aria-label="password_confirmation" {{ (!$user->id) ? ' required' : '' }} onfocus="this.removeAttribute('readonly');" readonly {{ (!Gate::allows('canEditAuthFields', $user)) || ((!Gate::allows('editableOnDemo')) && ($user->id)) ? ' disabled' : '' }}>
|
||||
|
||||
@if ($user->ldap_import!='1' || str_contains(Route::currentRouteName(), 'clone'))
|
||||
<!-- Password Confirm -->
|
||||
<div class="form-group {{ $errors->has('password_confirmation') ? 'has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="password_confirmation">
|
||||
{{ trans('admin/users/table.password_confirm') }}
|
||||
</label>
|
||||
<div class="col-md-6">
|
||||
<input
|
||||
type="password"
|
||||
name="password_confirmation"
|
||||
id="password_confirm"
|
||||
class="form-control"
|
||||
value=""
|
||||
maxlength="500"
|
||||
autocomplete="off"
|
||||
aria-label="password_confirmation"
|
||||
readonly
|
||||
{{ (!$user->id) ? ' required' : '' }}
|
||||
onfocus="this.removeAttribute('readonly');"
|
||||
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
|
||||
>
|
||||
@if (config('app.lock_passwords') && ($user->id))
|
||||
<p class="help-block">{{ trans('admin/users/table.lock_passwords') }}</p>
|
||||
@endif
|
||||
{!! $errors->first('password_confirmation', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
@cannot('canEditAuthFields', $user)
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.action_permission_generic', ['action' => trans('general.edit'), 'item_type' => trans('general.password')]) }}
|
||||
</p>
|
||||
@endcan
|
||||
|
||||
@if (!Gate::allows('editableOnDemo') && ($user->id))
|
||||
<p class="text-warning">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/table.lock_passwords') }}
|
||||
</p>
|
||||
@endif
|
||||
{!! $errors->first('password_confirmation', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Activation Status (Can the user login?) -->
|
||||
<div class="form-group {{ $errors->has('activated') ? 'has-error' : '' }}">
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
|
||||
<!-- checkbox($name, $value = 1, $checked = null, $options = array() -->
|
||||
@if (config('app.lock_passwords'))
|
||||
<!-- disallow changes to the user's login status -->
|
||||
@if ((!Gate::allows('canEditAuthFields', $user)) || ($user->id == auth()->user()->id) || ($user->id))
|
||||
<!-- demo mode - disallow changes -->
|
||||
<label class="form-control form-control--disabled">
|
||||
<input type="checkbox" value="1" name="activated" class="disabled" {{ (old('activated', $user->activated)) == '1' ? ' checked="checked"' : '' }} disabled="disabled" aria-label="activated">
|
||||
{{ trans('admin/users/general.activated_help_text') }}
|
||||
|
||||
</label>
|
||||
<p class="text-warning"><x-icon type="lock" /> {{ trans('general.feature_disabled') }}</p>
|
||||
|
||||
@elseif ($user->id === Auth::user()->id)
|
||||
<!-- disallow the user from editing their own login status -->
|
||||
<label class="form-control form-control--disabled">
|
||||
<input type="checkbox" name="activated" value="1" checked disabled aria-label="activated">
|
||||
<input type="checkbox" value="1" name="activated" class="disabled" {{ (old('activated', $user->activated)) == '1' ? ' checked="checked"' : '' }} disabled aria-label="activated">
|
||||
{{ trans('admin/users/general.activated_help_text') }}
|
||||
</label>
|
||||
<p class="text-warning">{{ trans('admin/users/general.activated_disabled_help_text') }}</p>
|
||||
|
||||
@cannot('canEditAuthFields', $user)
|
||||
<!-- authed user is an admin or regular user and is trying to edit someone higher -->
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.action_permission_generic', ['action' => trans('general.edit'), 'item_type' => trans('general.login_status')]) }}
|
||||
</p>
|
||||
@endcannot
|
||||
|
||||
@if ((auth()->user()->cannot('editableOnDemo')) && ($user->id))
|
||||
<!-- app is locked -->
|
||||
<p class="text-warning">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/table.lock_passwords') }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if ($user->id == auth()->user()->id)
|
||||
<!-- disallow editing activation on your own account -->
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/general.activated_disabled_help_text') }}
|
||||
</p>
|
||||
@endcannot
|
||||
|
||||
@else
|
||||
<!-- everything is normal - as you were -->
|
||||
<label class="form-control">
|
||||
<input type="checkbox" value="1" name="activated"{{ ((old('activated') == '1') || ($user->activated) == '1') ? ' checked="checked"' : '' }} aria-label="activated" id="activated">
|
||||
{{ trans('admin/users/general.activated_help_text') }}
|
||||
</label>
|
||||
|
||||
@endif
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -232,22 +264,28 @@
|
||||
<div class="form-group {{ $errors->has('email') ? 'has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="email">{{ trans('admin/users/table.email') }} </label>
|
||||
<div class="col-md-6">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="email"
|
||||
id="email"
|
||||
maxlength="191"
|
||||
value="{{ old('email', $user->email) }}"
|
||||
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
|
||||
autocomplete="off"
|
||||
readonly
|
||||
{{ (Helper::checkIfRequired($user, 'email')) ? ' required' : '' }}
|
||||
onfocus="this.removeAttribute('readonly');">
|
||||
@if (config('app.lock_passwords') && ($user->id))
|
||||
<p class="help-block">{{ trans('admin/users/table.lock_passwords') }}</p>
|
||||
@endif
|
||||
{!! $errors->first('email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
<input class="form-control" type="email" name="email" id="email" maxlength="191" value="{{ old('email', $user->email) }}" autocomplete="off"
|
||||
readonly onfocus="this.removeAttribute('readonly');" {{ (Helper::checkIfRequired($user, 'email')) ? ' required' : '' }}{{ (!Gate::allows('canEditAuthFields', $user)) || ((!Gate::allows('editableOnDemo') && ($user->id))) ? ' disabled' : '' }}>
|
||||
|
||||
@cannot('canEditAuthFields', $user)
|
||||
<!-- authed user is an admin or regular user and is trying to edit someone higher -->
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('general.action_permission_generic', ['action' => trans('general.edit'), 'item_type' => trans('general.email')]) }}
|
||||
</p>
|
||||
@endcannot
|
||||
|
||||
|
||||
@if (!Gate::allows('editableOnDemo') && ($user->id))
|
||||
<p class="text-warning">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/table.lock_passwords') }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
{!! $errors->first('email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -274,8 +312,19 @@
|
||||
<!-- everything here should be what is considered optional -->
|
||||
<br>
|
||||
<!-- Company -->
|
||||
@if (\App\Models\Company::canManageUsersCompanies())
|
||||
@if ((Gate::allows('canEditAuthFields', $user)) && (\App\Models\Company::canManageUsersCompanies()))
|
||||
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.select_company'), 'fieldname' => 'company_id'])
|
||||
@else
|
||||
@if ($user->company)
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label" for="locale">{{ trans('general.company') }}</label>
|
||||
<div class="col-md-6">
|
||||
<p class="form-control-static">
|
||||
{{ $user->company ? $user->company->name : '' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
|
||||
@@ -457,7 +506,7 @@
|
||||
<div class="form-group">
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
|
||||
@if (config('app.lock_passwords'))
|
||||
@if (!Gate::allows('editableOnDemo'))
|
||||
|
||||
<label class="form-control form-control--disabled" for="two_factor_optin">
|
||||
<input type="checkbox" value="1" name="two_factor_optin" {{ (old('two_factor_optin', $user->two_factor_optin)) == '1' ? ' checked="checked"' : '' }} aria-label="two_factor_optin" disabled>
|
||||
@@ -470,7 +519,9 @@
|
||||
<input type="checkbox" value="1" name="two_factor_optin" {{ (old('two_factor_optin', $user->two_factor_optin)) == '1' ? ' checked="checked"' : '' }} aria-label="two_factor_optin">
|
||||
{{ trans('admin/settings/general.two_factor') }}
|
||||
</label>
|
||||
<p class="help-block">{{ trans('admin/users/general.two_factor_admin_optin_help') }}</p>
|
||||
<p class="help-block">
|
||||
{{ trans('admin/users/general.two_factor_admin_optin_help') }}
|
||||
</p>
|
||||
|
||||
@endif
|
||||
|
||||
@@ -488,7 +539,9 @@
|
||||
<span id="two_factor_resetstatus"></span>
|
||||
</div>
|
||||
<div class="col-md-8 col-md-offset-3 two_factor_resetrow">
|
||||
<p class="help-block">{{ trans('admin/settings/general.two_factor_reset_help') }}</p>
|
||||
<p class="help-block">
|
||||
{{ trans('admin/settings/general.two_factor_reset_help') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -497,11 +550,13 @@
|
||||
|
||||
<!-- Groups -->
|
||||
<div class="form-group{{ $errors->has('groups') ? ' has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="groups[]"> {{ trans('general.groups') }}</label>
|
||||
<label class="col-md-3 control-label" for="groups[]">
|
||||
{{ trans('general.groups') }}
|
||||
</label>
|
||||
<div class="col-md-6">
|
||||
|
||||
@if ($groups->count())
|
||||
@if ((Config::get('app.lock_passwords') || (!Auth::user()->isSuperUser())))
|
||||
@if ((!Gate::allows('editableOnDemo') || (!Auth::user()->isSuperUser())))
|
||||
|
||||
@if (count($userGroups->keys()) > 0)
|
||||
<ul>
|
||||
@@ -511,27 +566,30 @@
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<span class="help-block">{{ trans('admin/users/general.group_memberships_helpblock') }}</span>
|
||||
@else
|
||||
<div class="controls">
|
||||
<select
|
||||
name="groups[]"
|
||||
aria-label="groups[]"
|
||||
id="groups[]"
|
||||
multiple="multiple"
|
||||
class="form-control">
|
||||
<p class="help-block">
|
||||
<x-icon type="locked" />
|
||||
{{ trans('admin/users/general.group_memberships_helpblock') }}
|
||||
</p>
|
||||
@else
|
||||
<div class="controls">
|
||||
<select
|
||||
name="groups[]"
|
||||
aria-label="groups[]"
|
||||
id="groups[]"
|
||||
multiple="multiple"
|
||||
class="form-control">
|
||||
|
||||
@foreach ($groups as $id => $group)
|
||||
<option value="{{ $id }}"
|
||||
{{ ($userGroups->keys()->contains($id) ? ' selected="selected"' : '') }}>
|
||||
{{ $group }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@foreach ($groups as $id => $group)
|
||||
<option value="{{ $id }}"
|
||||
{{ ($userGroups->keys()->contains($id) ? ' selected="selected"' : '') }}>
|
||||
{{ $group }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
<span class="help-block">
|
||||
{{ trans('admin/users/table.groupnotes') }}
|
||||
</span>
|
||||
<p class="help-block">
|
||||
{{ trans('admin/users/table.groupnotes') }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
@@ -552,6 +610,7 @@
|
||||
</div>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
||||
@can('admin')
|
||||
<div class="tab-pane" id="permissions">
|
||||
<div class="col-md-12">
|
||||
@if (!Auth::user()->isSuperUser())
|
||||
@@ -575,6 +634,7 @@
|
||||
@include('partials.forms.edit.permissions-base')
|
||||
</table>
|
||||
</div><!-- /.tab-pane -->
|
||||
@endcan
|
||||
</div><!-- /.tab-content -->
|
||||
<x-redirect_submit_options
|
||||
index_route="users.index"
|
||||
|
||||
@@ -164,15 +164,6 @@
|
||||
<div class="tab-pane active" id="details">
|
||||
<div class="row">
|
||||
|
||||
@if ($user->deleted_at!='')
|
||||
<div class="col-md-12">
|
||||
<div class="callout callout-warning">
|
||||
<i class="icon fas fa-exclamation-triangle"></i>
|
||||
{{ trans('admin/users/message.user_deleted_warning') }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="info-stack-container">
|
||||
<!-- Start button column -->
|
||||
<div class="col-md-3 col-xs-12 col-sm-push-9 info-stack">
|
||||
@@ -241,7 +232,7 @@
|
||||
@endcan
|
||||
|
||||
@can('update', $user)
|
||||
@if (($user->activated == '1') && ($user->ldap_import == '0'))
|
||||
@if ((($user->deleted_at=='')) && ($user->activated == '1') && ($user->ldap_import == '0'))
|
||||
<div class="col-md-12" style="padding-top: 5px;">
|
||||
@if (($user->email != '') && ($user->activated=='1'))
|
||||
<form action="{{ route('users.password',['userId'=> $user->id]) }}" method="POST">
|
||||
@@ -271,7 +262,7 @@
|
||||
@endcan
|
||||
|
||||
|
||||
@can('delete', $user)
|
||||
@can('update', $user)
|
||||
@if ($user->deleted_at=='')
|
||||
<div class="col-md-12" style="padding-top: 30px;">
|
||||
@if ($user->isDeletable())
|
||||
@@ -987,38 +978,20 @@
|
||||
<div class="table-responsive">
|
||||
|
||||
|
||||
<table
|
||||
data-cookie-id-table="usersHistoryTable"
|
||||
data-id-table="usersHistoryTable"
|
||||
data-side-pagination="server"
|
||||
data-sort-order="desc"
|
||||
id="usersHistoryTable"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.activity.index', ['target_id' => $user->id, 'target_type' => 'user']) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-{{ str_slug($user->present()->fullName ) }}-history-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">Icon</th>
|
||||
<th data-field="created_at" data-formatter="dateDisplayFormatter" data-sortable="true">{{ trans('general.date') }}</th>
|
||||
<th data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
|
||||
<th data-field="action_type">{{ trans('general.action') }}</th>
|
||||
<th data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
|
||||
<th data-field="note">{{ trans('general.notes') }}</th>
|
||||
@if ($snipeSettings->require_accept_signature=='1')
|
||||
<th data-field="signature_file" data-visible="false" data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
|
||||
@endif
|
||||
<th data-field="item.serial" data-visible="false">{{ trans('admin/hardware/table.serial') }}</th>
|
||||
<th data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.created_by') }}</th>
|
||||
<th data-field="remote_ip" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_ip') }}</th>
|
||||
<th data-field="user_agent" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_user_agent') }}</th>
|
||||
<th data-field="action_source" data-visible="false" data-sortable="true">{{ trans('general.action_source') }}</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<table
|
||||
data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
|
||||
class="table table-striped snipe-table"
|
||||
data-cookie-id-table="UserHistoryTable"
|
||||
data-id-table="UserHistoryTable"
|
||||
id="UserHistoryTable"
|
||||
data-side-pagination="server"
|
||||
data-sort-order="desc"
|
||||
data-export-options='{
|
||||
"fileName": "export-{{ str_slug($user->name) }}-history-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
}'
|
||||
data-url="{{ route('api.activity.index', ['target_id' => $user->id, 'item_type' => User::class]) }}">
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
||||
@@ -162,7 +162,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testApiUsersCanBeActivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => 0]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
@@ -175,7 +175,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testApiUsersCanBeActivatedWithBooleanTrue()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => false]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
@@ -188,7 +188,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testApiUsersCanBeDeactivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
@@ -201,7 +201,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testApiUsersCanBeDeactivatedWithBooleanFalse()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
@@ -212,6 +212,33 @@ class UpdateUserTest extends TestCase
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testEditingUsersCannotEditEscalationFieldsForAdmins()
|
||||
{
|
||||
$hashed_original = Hash::make('!!094850394680980380kfejlskjfl');
|
||||
$hashed_new = Hash::make('!ABCDEFGIJKL123!!!');
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->admin()->create(['username' => 'brandnewuser', 'email'=> 'brandnewemail@example.org', 'password' => $hashed_original, 'activated' => 1]);
|
||||
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'username' => 'brandnewuser',
|
||||
'email' => 'brandnewemail@example.org',
|
||||
'activated' => 1,
|
||||
'password' => $hashed_original,
|
||||
]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patch(route('api.users.update', $user), [
|
||||
'username' => 'testnewusername',
|
||||
'email' => 'testnewemail@example.org',
|
||||
'activated' => 0,
|
||||
'password' => $hashed_new,
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
|
||||
}
|
||||
public function testUsersScopedToCompanyDuringUpdateWhenMultipleFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
@@ -7,17 +7,26 @@ use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Error;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UpdateUserTest extends TestCase
|
||||
{
|
||||
|
||||
public function testRequiresPermission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->get(route('users.edit', User::factory()->create()->id))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testPageRenders()
|
||||
{
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
$this->actingAs(User::factory()->editUsers()->create())
|
||||
->get(route('users.edit', User::factory()->create()->id))
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function testCannotViewEditPageForSoftDeletedUser()
|
||||
public function testCanViewEditPageForSoftDeletedUser()
|
||||
{
|
||||
$user = User::factory()->trashed()->create();
|
||||
|
||||
@@ -28,7 +37,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testUsersCanBeActivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => 0]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
@@ -43,7 +52,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testUsersCanBeActivatedWithBooleanTrue()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => false]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
@@ -58,7 +67,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testUsersCanBeDeactivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
@@ -73,7 +82,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testUsersCanBeDeactivatedWithBooleanFalse()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$admin = User::factory()->editUsers()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
@@ -88,7 +97,7 @@ class UpdateUserTest extends TestCase
|
||||
|
||||
public function testUsersUpdatingThemselvesDoNotDeactivateTheirAccount()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create(['activated' => true]);
|
||||
$admin = User::factory()->editUsers()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $admin), [
|
||||
@@ -99,6 +108,87 @@ class UpdateUserTest extends TestCase
|
||||
$this->assertEquals(1, $admin->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testEditingUsersCannotEditEscalationFieldsForAdmins()
|
||||
{
|
||||
$admin = User::factory()->editUsers()->create(['activated' => true]);
|
||||
$hashed_original = Hash::make('!!094850394680980380kfejlskjfl');
|
||||
$hashed_new = Hash::make('!ABCDEFGIJKL123!!!');
|
||||
$user = User::factory()->admin()->create(['username' => 'brandnewuser', 'email'=> 'brandnewemail@example.org', 'password' => $hashed_original, 'activated' => true]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'username' => 'brandnewuser',
|
||||
'email' => 'brandnewemail@example.org',
|
||||
'activated' => 1,
|
||||
'password' => $hashed_original,
|
||||
]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'username' => 'testnewusername',
|
||||
'email' => 'testnewemail@example.org',
|
||||
'activated' => 0,
|
||||
'password' => 'super-secret',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
'activated' => $user->activated,
|
||||
'password' => $hashed_original,
|
||||
]);
|
||||
|
||||
$this->assertEquals('brandnewuser', $user->refresh()->username);
|
||||
$this->assertEquals('brandnewemail@example.org', $user->refresh()->email);
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
$this->assertNotEquals(Hash::check('super-secret', $user->password), $user->refresh()->password);
|
||||
$this->assertNotEquals('testnewusername', $user->refresh()->username);
|
||||
$this->assertNotEquals('testnewemail@example.org', $user->refresh()->email);
|
||||
$this->assertNotEquals(0, $user->refresh()->activated);
|
||||
$this->assertNotEquals(Hash::check('super-secret', $user->password), $user->refresh()->password);
|
||||
}
|
||||
|
||||
public function testAdminUsersCannotEditFieldsForSuperAdmins()
|
||||
{
|
||||
$admin = User::factory()->admin()->create(['activated' => true]);
|
||||
$hashed_original = Hash::make('my-awesome-password');
|
||||
$user = User::factory()->superuser()->create(['username' => 'brandnewuser', 'email'=> 'brandnewemail@example.org', 'password' => $hashed_original, 'activated' => true]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'username' => 'brandnewuser',
|
||||
'email' => 'brandnewemail@example.org',
|
||||
'activated' => 1,
|
||||
'password' => $hashed_original,
|
||||
]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'username' => 'testnewusername',
|
||||
'email' => 'testnewemail@example.org',
|
||||
'activated' => 0,
|
||||
'password' => 'super-secret-new-password',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
'activated' => $user->activated,
|
||||
'password' => $hashed_original,
|
||||
]);
|
||||
|
||||
$this->assertEquals('brandnewuser', $user->refresh()->username);
|
||||
$this->assertEquals('brandnewemail@example.org', $user->refresh()->email);
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
$this->assertTrue(Hash::check('my-awesome-password', $user->password), $user->refresh()->password);
|
||||
$this->assertNotEquals('testnewusername', $user->refresh()->username);
|
||||
$this->assertNotEquals('testnewemail@example.org', $user->refresh()->email);
|
||||
$this->assertNotTrue(Hash::check('super-secret-new-password', $user->password), $user->refresh()->password);
|
||||
}
|
||||
|
||||
|
||||
public function testMultiCompanyUserCannotBeMovedIfHasAssetInDifferentCompany()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
@@ -188,7 +278,7 @@ class UpdateUserTest extends TestCase
|
||||
$user->delete();
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->create())
|
||||
->put(route('users.update', $id), [
|
||||
->put(route('users.update', $user), [
|
||||
'first_name' => 'test',
|
||||
'username' => 'test',
|
||||
'company_id' => $companyB->id,
|
||||
|
||||
Reference in New Issue
Block a user