diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 9200f80b1..856b3b6a6 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -427,13 +427,10 @@ class UsersController extends Controller * @param \Illuminate\Http\Request $request * @param int $id */ - public function update(SaveUserRequest $request, $id) : JsonResponse + public function update(SaveUserRequest $request, User $user): JsonResponse { $this->authorize('update', User::class); - if ($user = User::find($id)) { - - $this->authorize('update', $user); /** @@ -443,12 +440,10 @@ class UsersController extends Controller * */ - - if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) { + if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) { return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.')); } - $user->fill($request->all()); if ($user->id == $request->input('manager_id')) { @@ -473,16 +468,13 @@ class UsersController extends Controller $user->permissions = $permissions_array; } - // 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)]); - app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar'); if ($user->save()) { - // Check if the request has groups passed and has a value, AND that the user us a superuser if (($request->has('groups')) && (auth()->user()->isSuperUser())) { @@ -496,18 +488,10 @@ class UsersController extends Controller // Sync the groups since the user is a superuser and the groups pass validation $user->groups()->sync($request->input('groups')); - - } - return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors())); - } - - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id')))); - } /** diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 1965962ad..1d7fc91eb 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -186,7 +186,7 @@ class UsersController extends Controller { $this->authorize('update', User::class); - $user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id); + $user = User::with(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed()->find($id); if ($user) { @@ -214,83 +214,79 @@ class UsersController extends Controller * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function update(SaveUserRequest $request, $id = null) + public function update(SaveUserRequest $request, User $user) { $this->authorize('update', User::class); // This is a janky hack to prevent people from changing admin demo user data on the public demo. // The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder. // Thanks, jerks. You are why we can't have nice things. - snipe - - if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) { + if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) { return redirect()->route('users.index')->with('error', trans('general.permission_denied_superuser_demo')); } - // We need to reverse the UI specific logic for our // permissions here before we update the user. $permissions = $request->input('permissions', []); app('request')->request->set('permissions', $permissions); - $user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id); + $user->load(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed(); - // User is valid - continue... - if ($user) { - $this->authorize('update', $user); + $this->authorize('update', $user); - // Figure out of this user was an admin before this edit - $orig_permissions_array = $user->decodePermissions(); - $orig_superuser = '0'; - if (is_array($orig_permissions_array)) { - if (array_key_exists('superuser', $orig_permissions_array)) { - $orig_superuser = $orig_permissions_array['superuser']; - } + // Figure out of this user was an admin before this edit + $orig_permissions_array = $user->decodePermissions(); + $orig_superuser = '0'; + if (is_array($orig_permissions_array)) { + if (array_key_exists('superuser', $orig_permissions_array)) { + $orig_superuser = $orig_permissions_array['superuser']; } + } - // Only save groups if the user is a superuser - if (auth()->user()->isSuperUser()) { - $user->groups()->sync($request->input('groups')); - } + // 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); - $user->company_id = Company::getIdForUser($request->input('company_id', null)); - $user->manager_id = $request->input('manager_id', null); - $user->notes = $request->input('notes'); - $user->department_id = $request->input('department_id', null); - $user->address = $request->input('address', null); - $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); - $user->website = $request->input('website', null); - $user->start_date = $request->input('start_date', null); - $user->end_date = $request->input('end_date', null); - $user->autoassign_licenses = $request->input('autoassign_licenses', 0); + // 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); + $user->company_id = Company::getIdForUser($request->input('company_id', null)); + $user->manager_id = $request->input('manager_id', null); + $user->notes = $request->input('notes'); + $user->department_id = $request->input('department_id', null); + $user->address = $request->input('address', null); + $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); + $user->website = $request->input('website', null); + $user->start_date = $request->input('start_date', null); + $user->end_date = $request->input('end_date', null); + $user->autoassign_licenses = $request->input('autoassign_licenses', 0); - // 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)]); + // 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')); - } + // Do we want to update the user password? + if ($request->filled('password')) { + $user->password = bcrypt($request->input('password')); + } // Update the location of any assets checked out to this user @@ -318,13 +314,7 @@ class UsersController extends Controller return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users')) ->with('success', trans('admin/users/message.success.update')); } - return redirect()->back()->withInput()->withErrors($user->getErrors()); - - - } - - return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id'))); } /** diff --git a/app/Http/Requests/SaveUserRequest.php b/app/Http/Requests/SaveUserRequest.php index b38193c15..f778d016d 100644 --- a/app/Http/Requests/SaveUserRequest.php +++ b/app/Http/Requests/SaveUserRequest.php @@ -34,6 +34,14 @@ class SaveUserRequest extends FormRequest $rules = [ 'department_id' => 'nullable|exists:departments,id', 'manager_id' => 'nullable|exists:users,id', + 'company_id' => [ + // determines if the user is being moved between companies and checks to see if they have any items assigned + function ($attribute, $value, $fail) { + if (($this->has('company_id')) && ($this->user?->allAssignedCount() > 0) && (Setting::getSettings()->full_multiple_companies_support)) { + $fail(trans('admin/users/message.error.multi_company_items_assigned')); + } + } + ] ]; switch ($this->method()) { diff --git a/app/Http/Requests/UpdateAssetRequest.php b/app/Http/Requests/UpdateAssetRequest.php index a749e5816..1b379358f 100644 --- a/app/Http/Requests/UpdateAssetRequest.php +++ b/app/Http/Requests/UpdateAssetRequest.php @@ -4,6 +4,7 @@ namespace App\Http\Requests; use App\Http\Requests\Traits\MayContainCustomFields; use App\Models\Asset; +use App\Models\Setting; use Illuminate\Support\Facades\Gate; use Illuminate\Validation\Rule; @@ -41,6 +42,12 @@ class UpdateAssetRequest extends ImageUploadRequest ], ); + // if the purchase cost is passed in as a string **and** the digit_separator is ',' (as is common in the EU) + // then we tweak the purchase_cost rule to make it a string + if (Setting::getSettings()->digit_separator === '1.234,56' && is_string($this->input('purchase_cost'))) { + $rules['purchase_cost'] = ['nullable', 'string']; + } + return $rules; } } diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index af12c3d29..f26946d22 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -21,6 +21,11 @@ class SnipeModel extends Model */ public function setPurchaseCostAttribute($value) { + if (is_float($value)) { + //value is *already* a floating-point number. Just assign it directly + $this->attributes['purchase_cost'] = $value; + return; + } $value = Helper::ParseCurrency($value); if ($value == 0) { diff --git a/package-lock.json b/package-lock.json index f4d51c45a..a5296ae5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "ekko-lightbox": "^5.1.1", "imagemin": "^8.0.1", "jquery-slimscroll": "^1.3.8", - "jquery-ui": "^1.13.3", + "jquery-ui": "^1.14.0", "jquery-validation": "^1.21.0", "jquery.iframe-transport": "^1.0.0", "jspdf-autotable": "^3.8.2", @@ -37,7 +37,7 @@ "signature_pad": "^4.2.0", "tableexport.jquery.plugin": "1.30.0", "tether": "^1.4.0", - "webpack": "^5.92.0" + "webpack": "^5.94.0" }, "devDependencies": { "all-contributors-cli": "^6.26.1", @@ -2105,25 +2105,10 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/express": { "version": "4.17.21", @@ -5310,9 +5295,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -7067,10 +7052,11 @@ "license": "BSD-2-Clause" }, "node_modules/jquery-ui": { - "version": "1.13.3", - "license": "MIT", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.0.tgz", + "integrity": "sha512-mPfYKBoRCf0MzaT2cyW5i3IuZ7PfTITaasO5OFLAQxrHuI+ZxruPa+4/K1OMNT8oElLWGtIxc9aRbyw20BKr8g==", "dependencies": { - "jquery": ">=1.8.0 <4.0.0" + "jquery": ">=1.12.0 <5.0.0" } }, "node_modules/jquery-validation": { @@ -10879,11 +10865,10 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -10892,7 +10877,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/package.json b/package.json index a36144a17..3d8e3eda2 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "ekko-lightbox": "^5.1.1", "imagemin": "^8.0.1", "jquery-slimscroll": "^1.3.8", - "jquery-ui": "^1.13.3", + "jquery-ui": "^1.14.0", "jquery-validation": "^1.21.0", "jquery.iframe-transport": "^1.0.0", "jspdf-autotable": "^3.8.2", @@ -57,6 +57,6 @@ "signature_pad": "^4.2.0", "tableexport.jquery.plugin": "1.30.0", "tether": "^1.4.0", - "webpack": "^5.92.0" + "webpack": "^5.94.0" } } diff --git a/public/js/build/app.js b/public/js/build/app.js index 329860412..736ab69c8 100644 --- a/public/js/build/app.js +++ b/public/js/build/app.js @@ -1,2 +1,2 @@ /*! For license information please see app.js.LICENSE.txt */ -(()=>{var t,e={571:(t,e,n)=>{window._=n(543),n(139),jQuery.fn.uitooltip=jQuery.fn.tooltip,n(43)},671:(t,e,n)=>{n(571),lineOptions={legend:{position:"bottom"},scales:{yAxes:[{ticks:{fontColor:"rgba(0,0,0,0.5)",fontStyle:"bold",beginAtZero:!0,maxTicksLimit:5,padding:20},gridLines:{drawTicks:!1,display:!1}}],xAxes:[{gridLines:{zeroLineColor:"transparent"},ticks:{padding:20,fontColor:"rgba(0,0,0,0.5)",fontStyle:"bold"}}]}},pieOptions={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:1,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,responsive:!0,maintainAspectRatio:!1,legendTemplate:"
0&&xt(a,!u&&wt(t,"script")),s},cleanData:function(t){for(var e,n,r,i=C.event.special,o=0;void 0!==(n=t[o]);o++)if(K(n)){if(e=n[G.expando]){if(e.events)for(r in e.events)i[r]?C.event.remove(n,r):C.removeEvent(n,r,e.handle);n[G.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),C.fn.extend({detach:function(t){return Wt(this,t,!0)},remove:function(t){return Wt(this,t)},text:function(t){return U(this,(function(t){return void 0===t?C.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=t)}))}),null,t,arguments.length)},append:function(){return Ft(this,arguments,(function(t){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Lt(this,t).appendChild(t)}))},prepend:function(){return Ft(this,arguments,(function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=Lt(this,t);e.insertBefore(t,e.firstChild)}}))},before:function(){return Ft(this,arguments,(function(t){this.parentNode&&this.parentNode.insertBefore(t,this)}))},after:function(){return Ft(this,arguments,(function(t){this.parentNode&&this.parentNode.insertBefore(t,this.nextSibling)}))},empty:function(){for(var t,e=0;null!=(t=this[e]);e++)1===t.nodeType&&(C.cleanData(wt(t,!1)),t.textContent="");return this},clone:function(t,e){return t=null!=t&&t,e=null==e?t:e,this.map((function(){return C.clone(this,t,e)}))},html:function(t){return U(this,(function(t){var e=this[0]||{},n=0,r=this.length;if(void 0===t&&1===e.nodeType)return e.innerHTML;if("string"==typeof t&&!Dt.test(t)&&!bt[(mt.exec(t)||["",""])[1].toLowerCase()]){t=C.htmlPrefilter(t);try{for(;n