Compare commits

...

427 Commits

Author SHA1 Message Date
snipe
4a0410d969 Uncomment git stash
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:55:39 +00:00
snipe
668b9f8fb9 Nicer upgrade.php UI
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:51:32 +00:00
Brady Wetherington
09a5e5b1bd Whoops! Need minimum 8.2, not 8.1 (probably mis-merge?) 2025-02-25 14:40:45 +00:00
snipe
7b4f4b6b7f Merge pull request #16337 from joakimbergros/develop
Fixed #16173: `useraccountcontrol` was not included in the ldap query attributes
2025-02-25 13:49:38 +00:00
Joakim Bergros
5c66334017 Added a check to see if the user has specified that is an ActiveDirectory server in the configuration before adding the useraccountcontrol attribute to the ldap query. 2025-02-25 14:22:22 +01:00
Joakim Bergros
ae82051b73 Fixed #16173: useraccountcontrol was not included in the ldap query attributes.
`$results` did not include the `useraccountcontrol` and thus rendered the fallback logic void when `active_flag` was blank.

 Added a condition to check if `active_flag` is blank and only then add `useraccountcontrol` to the ldap query since it is then a requirement in accordance with "we respect the userAccountControl attribute" text in the `admin/ldap` route.

[`elseif' will become true when `active_flag` is blank](b141945add/app/Console/Commands/LdapSync.php (L364))
2025-02-25 13:55:53 +01:00
snipe
c3a2e81afd Updated version
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:18:22 +00:00
snipe
18c7cbbbbb Merge pull request #16336 from snipe/change_order_in_upgrade_script
Fixed #16334 - Changed composer order in upgrade script
2025-02-25 12:09:15 +00:00
snipe
3718f08c72 Changed composer order in upgrade script
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:05:00 +00:00
snipe
b7821a69b6 Added link to the google apps script repo
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 11:07:04 +00:00
snipe
8049f21068 Updated laravel version in readme
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 11:02:00 +00:00
snipe
8140110bf9 Chnage dev docker env to en-US from en
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 10:57:38 +00:00
snipe
a4587f6322 Merge pull request #16335 from snipe/added_label_test
Added label test
2025-02-25 10:40:46 +00:00
snipe
163e19f1e9 Added label test
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 10:37:06 +00:00
snipe
8a40c3ecb4 Merge pull request #16325 from spencerrlongg/bug/sc-28520
Remove remaining hardware references in favor of new RMB
2025-02-25 10:09:35 +00:00
spencerrlongg
d949a9689f fix all 2025-02-24 22:35:47 -06:00
snipe
27a7c6fd10 Merge pull request #16324 from marcusmoore/chore/migrate-checkbox-helpers-p2
Replace calls to Form::checkbox pt2
2025-02-25 02:33:02 +00:00
Marcus Moore
4d55a67628 Merge branch 'develop' into chore/migrate-checkbox-helpers-p2 2025-02-24 16:37:59 -08:00
snipe
9d453226bd Merge pull request #16321 from spencerrlongg/bug/sc-28515
Changed Parameter Name for RMB
2025-02-25 00:17:37 +00:00
snipe
cd26694767 Merge pull request #16322 from marcusmoore/fixes/fix-test-edit-route
Fixed edit routes in tests
2025-02-25 00:17:10 +00:00
Marcus Moore
a26cc2ced1 Use .edit routes instead of .update 2025-02-24 15:55:05 -08:00
spencerrlongg
1fd81d17a3 route model binding change 2025-02-24 17:53:41 -06:00
snipe
134045f1ec Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2025-02-24 23:46:55 +00:00
snipe
b6b6a3eec7 Remove req for 0 min
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 23:46:50 +00:00
snipe
b62714d702 Merge pull request #16062 from snipe/remove_mcrypt
Removed references to mcrypt
2025-02-24 23:22:32 +00:00
Brady Wetherington
271bcc66bf Remove lib-mcrypt as a dependency 2025-02-24 23:19:08 +00:00
snipe
ced560daa9 Add @jostrander as a contributor 2025-02-24 23:16:27 +00:00
snipe
b395c9130a Merge remote-tracking branch 'origin/master' into develop 2025-02-24 23:06:46 +00:00
snipe
ed46a757fa Merge pull request #16320 from jostrander/fix/location-edit
Fixed: fix 500 on edit locations page by referencing current location
2025-02-24 23:03:01 +00:00
Jesse Ostrander
6a8a41b389 fix: reference to item location on location edit method 2025-02-24 17:34:18 -05:00
snipe
4800f4c853 Merge branch 'develop' into remove_mcrypt 2025-02-24 22:12:56 +00:00
snipe
c79ff49c85 Add @addex12 as a contributor 2025-02-24 20:30:04 +00:00
snipe
ee85a392e7 Merge pull request #16316 from snipe/v8_final_merge
V8 final merge
2025-02-24 19:18:12 +00:00
Brady Wetherington
6c2d367124 Tweak version number and hashes 2025-02-24 18:38:53 +00:00
Brady Wetherington
982cfeca32 Merge branch 'develop' 2025-02-24 18:37:41 +00:00
snipe
5fa4f85c20 Merge pull request #16106 from marcusmoore/bug/sc-27960
Fixed asset show page erroring when asset not associated with model
2025-02-24 17:16:12 +00:00
snipe
43b8c0bf7b Merge pull request #16313 from snipe/localizations/2024-02-24
Updated strings, added Oromo
2025-02-24 14:51:45 +00:00
snipe
54b664d679 Updated strings, added Oromo
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 14:50:23 +00:00
snipe
bf2355a297 Fixed showfile path
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 14:34:10 +00:00
snipe
2bf4ec0ae8 A few more small tweaks
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 14:24:15 +00:00
Brady Wetherington
9555825a67 Update minimum PHP version 2025-02-24 14:03:57 +00:00
snipe
0bea07e2f9 Merge pull request #16312 from snipe/small_cleanups
Small cleanups before release
2025-02-24 13:53:28 +00:00
snipe
22f7a9ddd4 Fixed stray tag
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:46:33 +00:00
snipe
77b417bcea Passed user to showfile
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:43:39 +00:00
snipe
76e3c00d2d Removed footer on tables that didn’t need it
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:41:49 +00:00
snipe
77add8abbc Added strings
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:39:07 +00:00
snipe
b53957268a Added warning if deleted
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:38:55 +00:00
snipe
ba49fc554d Moved warning to be consistent with other FCOs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:38:47 +00:00
snipe
e60462b751 Added/updated tests
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:38:28 +00:00
snipe
a5009aa7df Added withTrashed() to handle soft deletes with RMB
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:38:06 +00:00
snipe
e589adbe80 Updated model route
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 13:31:09 +00:00
snipe
0501c5f53c Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 11:15:03 +00:00
snipe
6a9247ba8a Cast token policies to int
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 11:14:49 +00:00
snipe
fcf84bf63f Fixed test namespace
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 11:09:54 +00:00
snipe
cebb9d034c Merge pull request #16305 from snipe/bug/sc-28425
Fixed #16262 - Check for quantity before allowing component deletion
2025-02-23 14:17:36 +00:00
snipe
dd2b570db5 Added tighter constraints on deleting components
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 14:11:39 +00:00
snipe
2bee4532ec Added qty error string
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 13:21:58 +00:00
snipe
96248e0023 Removed soft delete from test
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 13:21:49 +00:00
snipe
157801242d Added API test, renamed test to match filter
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 13:21:36 +00:00
snipe
7b151cf692 Added test
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 13:17:20 +00:00
snipe
50c88df4cc Merge pull request #16304 from snipe/security/snyk-updates-less-papaparse
Updated less and papaparse
2025-02-23 12:51:38 +00:00
snipe
d87a6868cc Updated less and papaparse
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 12:50:09 +00:00
snipe
201f487853 Merge pull request #16303 from snipe/chore/sc-28493
Added tooltip for currency in table
2025-02-23 12:21:04 +00:00
snipe
069860d65f Added tooltip for currency in table
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 12:19:18 +00:00
snipe
afa7391080 Merge pull request #16299 from snipe/added_checkin_checkout_indicator_for_custom_fields
Added checkin/checkout indicators on custom field table
2025-02-22 19:34:04 +00:00
snipe
07cf203018 Add checkin/checkout indicators on custom field table
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 19:32:34 +00:00
snipe
5f561452d2 Merge pull request #16298 from uberbrady/tooltips_custom_fields
Add tooltips to custom fields display, especially for icons
2025-02-22 19:17:28 +00:00
Brady Wetherington
cbe04e8514 Add tooltips to custom fields display, especially for icons 2025-02-22 19:13:09 +00:00
snipe
9b44dfd9b6 Merge pull request #16297 from snipe/add_field_to_checkin_checkout
Fixed #6188 - Added custom fields to checkin/checkout screens
2025-02-22 19:09:51 +00:00
snipe
9abf3029ef Compact the method just a little
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 19:02:41 +00:00
snipe
19fb45f488 Refactor into method
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:57:18 +00:00
snipe
e983ee4d0f Tweaked icon position
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:47:12 +00:00
snipe
40acd48eff Tweaked some style
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:19:09 +00:00
snipe
f5eedb8d23 Added RMB and include $item so the asset fields are populated
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:13:12 +00:00
snipe
172df0d220 Save new custom field values
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:12:46 +00:00
snipe
c611cb5612 Updated loggable to check for custom fields that were passed for meta
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:12:30 +00:00
snipe
da77ddd447 Added fields to custom field edit form
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:11:56 +00:00
snipe
c727633e6b Added language strings
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:11:42 +00:00
snipe
10834cf638 Added migration
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:11:35 +00:00
snipe
42eda089e2 Added include for custom fields partial
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:11:27 +00:00
snipe
2434c82a75 Added if/else for custom fields model partial
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:11:04 +00:00
snipe
1b9d046f5f Fixed test for RMB
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:08:25 +00:00
snipe
a0a0727b5c Corrected route breadcrumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 18:08:13 +00:00
snipe
917b9f0293 Merge pull request #16296 from snipe/added_select_unselect_tooltip_to_presenters
Added select/unselect tooltip to presenters, added translation
2025-02-22 14:32:04 +00:00
snipe
bb70250007 Added select/unselect tooltip to presenters, added translation
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 14:30:49 +00:00
snipe
346aeeda71 Merge pull request #16287 from uberbrady/better_hover_titles
Fixes: [sc-28423] Better tooltips on lists, Bootstrap style
2025-02-22 14:24:02 +00:00
snipe
84a29378cd Merge pull request #16295 from snipe/#16282_adds_accessories_tab_to_assets
Fixed #16282 - adds accessories tab to assets
2025-02-22 14:21:32 +00:00
snipe
0cd0abe8bb Fixed #16282 - adds accessories tab to assets
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 14:20:21 +00:00
snipe
7db11dc12b Merge pull request #16277 from Godmartinz/bulk_delete_asset_bug
Fixes deletion of assigned assets through bulk delete
2025-02-22 12:59:37 +00:00
snipe
e0221301ff Increased text limit on notes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 12:56:25 +00:00
snipe
b0fa059a28 Merge pull request #16285 from marcusmoore/bug/sc-28148
Re-added ability to add notes to assets
2025-02-22 12:55:18 +00:00
snipe
3fb00a9fa9 Merge pull request #16293 from uberbrady/fix_default_docker_image
Updated default Dockerfile to handle newer PHP versions
2025-02-22 12:52:37 +00:00
snipe
3ef8b047ba Merge pull request #16294 from snipe/bug/sc-28474
Don’t delete avatar file on soft-delete
2025-02-22 12:52:18 +00:00
snipe
7a77de6ffe Don’t delete avatar file on soft-delete
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 12:49:04 +00:00
Brady Wetherington
5e85891b10 Updated default Dockerfile to handle newer PHP versions 2025-02-22 12:43:30 +00:00
snipe
934da0f630 Merge pull request #16291 from uberbrady/fix_tests_and_migrations_v8
Fix tests and fix migrations to always explicitly include nullable()
2025-02-22 12:21:56 +00:00
snipe
cca46ea9e0 Merge pull request #16292 from snipe/add_email_list_assigned_to_bulk
Added ability to send user inventory via bulk UI
2025-02-22 12:20:01 +00:00
snipe
bde034593b Updateed string
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 12:17:04 +00:00
Brady Wetherington
7e1295bac7 Fix tests and fix migrations to always explicitly include nullable() 2025-02-22 12:15:12 +00:00
snipe
d1cc0fcfac Added ability to send user inventory via bulk UI
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 12:07:54 +00:00
snipe
056fbefb16 Merge pull request #16290 from snipe/update_php_versions_for_tests
Removed php 8.1, added 8.4
2025-02-22 11:11:53 +00:00
snipe
83a848980f Removed php 8.1, added 8.4
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 11:11:01 +00:00
snipe
7b930357e4 Cast years to int
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 10:51:27 +00:00
snipe
bdab052f40 Fixed test name
Signed-off-by: snipe <snipe@snipe.net>
2025-02-22 10:51:16 +00:00
Brady Wetherington
2d1e9b237f Better tooltips on list views, in Bootstrap style 2025-02-21 13:23:19 +00:00
Brady Wetherington
1cff49116e Bump version numbers and upgrade requirements 2025-02-21 11:49:25 +00:00
Brady Wetherington
38c5f23a52 Merge branch 'v8' into develop 2025-02-21 11:15:44 +00:00
Marcus Moore
c6bee0c47a Fix test 2025-02-20 13:24:01 -08:00
Marcus Moore
ae7d7f7d22 Merge branch 'develop' into bug/sc-28148
# Conflicts:
#	routes/web.php
2025-02-20 13:23:55 -08:00
Marcus Moore
96ab828cec Fix indent 2025-02-20 13:05:42 -08:00
Marcus Moore
43f679a554 Revert some changes from #15525 2025-02-20 12:59:16 -08:00
Marcus Moore
f1bf9fcf5c Implement test 2025-02-20 12:51:08 -08:00
Marcus Moore
992b4c7d86 Remove old comment 2025-02-20 12:50:03 -08:00
Marcus Moore
39bb2c2adb Implement tests 2025-02-20 12:49:58 -08:00
Marcus Moore
41129829e6 Add frontend required validation 2025-02-20 12:43:51 -08:00
Marcus Moore
44503fc423 Use translation 2025-02-20 12:41:56 -08:00
Marcus Moore
0190ccea27 Finish implementing test 2025-02-20 12:40:05 -08:00
snipe
5b63eb5a15 Merge pull request #16272 from snipe/experiments/breadcrumbs
Experimental WIP - added breadcrumbs, route model binding for resource routes
2025-02-20 19:21:58 +00:00
snipe
54cc427ef5 Updated tests for new RMB behavior
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 18:28:46 +00:00
snipe
e0beed0fa3 Reapplied accessory gate
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 18:28:01 +00:00
snipe
d4b24e5e57 Exception handler exceptions - exception inception!
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 18:27:45 +00:00
snipe
671b64bc6b Fixed RMB for kits and fields
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 15:01:17 +00:00
snipe
75db0d9e66 Fixed parameter for audit
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 15:00:57 +00:00
snipe
b891992351 Nice language for audit/checkin screens accounting for null
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 15:00:35 +00:00
snipe
ddb72bf4d0 Added breadcrumbs to licenses routes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 15:00:08 +00:00
snipe
6f071722a2 Fixed kit crimbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:59:50 +00:00
snipe
be9bd93588 More crombs, removed scan route that we don’t use
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:59:10 +00:00
snipe
44a7bdbfb5 Moved SAML gui settings routes to web.php
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:58:17 +00:00
snipe
0341335d14 Additional crombs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:57:48 +00:00
snipe
76f038d142 RMB for custom fields
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:57:18 +00:00
snipe
3150ad50c9 RMB for audits
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 14:57:07 +00:00
snipe
80394ef788 Revert delete because route model binding + resources routes + soft deletes = sux0r
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 12:29:37 +00:00
snipe
8a70f09dd3 Temp “fix” RMB for soft-deleted users
Signed-off-by: snipe <snipe@snipe.net>
2025-02-20 12:19:31 +00:00
Godfrey M
a275391557 adds test for deleting assigned asset 2025-02-19 15:59:57 -08:00
Godfrey M
eaacf29d57 fix tests 2025-02-19 15:11:16 -08:00
snipe
441fdaa54a Merge pull request #16278 from marcusmoore/bug/sc-27234
Added better error handling around rendering barcodes
2025-02-19 20:54:24 +00:00
Marcus Moore
759c8c8f5c Catch TypeError in addition to Exceptions when rendering barcodes 2025-02-19 12:36:50 -08:00
snipe
6242296930 Remove the “View” part of the breadcrumb
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 19:30:13 +00:00
snipe
d330ef9919 Added crumbs and RMB for custom fields
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 18:23:16 +00:00
snipe
0708af7d07 Made the help ring slightly less goofy looking
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 18:22:50 +00:00
Godfrey M
a534b488b2 prevents deletion of assigned assets in bulk deletion 2025-02-19 10:09:02 -08:00
snipe
3171c1b1c9 Added breadcrumbs for bulkaudit, requested, and import history
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 17:40:47 +00:00
snipe
2f2b879d98 Language refinement
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 17:40:12 +00:00
snipe
039f483ec8 Check for notes and cost before displaying them
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 16:57:24 +00:00
snipe
7f665e0005 De-uglifying the maintenances detail page
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 16:34:48 +00:00
snipe
292819afa5 Added maintenances crumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:29:06 +00:00
snipe
7a94b09017 Use MLB for kit group
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:07:14 +00:00
snipe
6b46d12d67 Added breadcrumbs on kits (sort of)
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:05:29 +00:00
snipe
e264907157 Added breadcrumbs on more web routes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:05:12 +00:00
snipe
32b89e937c Fixed routes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:04:56 +00:00
snipe
0e1dc8745c Wider custom report
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:04:45 +00:00
snipe
129d44cc70 Made icon possible for dashboard/home
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:04:34 +00:00
snipe
11b746d801 UI tweak
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:04:19 +00:00
snipe
545445d584 Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:04:07 +00:00
snipe
4d72fd8667 Added additional resource crumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:03:53 +00:00
snipe
fca62a14f9 Fixed asset presenter to link to the company directly
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:03:29 +00:00
snipe
c8f2d9806a Use route model binding on kits
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:03:15 +00:00
snipe
1ee5f28fca Added angle-right and house icon
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 14:02:59 +00:00
snipe
24a17b09a5 Fixed a few more tests and strings
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 09:03:41 +00:00
snipe
a617c0545e WIP license checkin
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:39:25 +00:00
snipe
eb7e24eeb0 Asset checkout with route model binding
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:39:16 +00:00
snipe
22c58678c4 License checkout controller with route model binding
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:38:55 +00:00
snipe
4beaf6b3ec Added item
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:38:40 +00:00
snipe
4c1856b91f Fixed wonky quote in HTML
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:37:58 +00:00
snipe
9d299340da Checkout license modifications (this doesn’t work yet
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:37:39 +00:00
snipe
457228d033 Route model binding on more asset methods
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:37:06 +00:00
snipe
63f4e3cc89 More breadcrumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 08:36:52 +00:00
snipe
cd7135ea77 More test fixes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 06:19:50 +00:00
snipe
347eb2bdee Fixed route parameters and tests to match
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 05:03:56 +00:00
snipe
ecc0e76e7b Fixed route parameters for helper
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 05:03:39 +00:00
snipe
35a89de6dd Fixed handler for reports
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 05:03:26 +00:00
snipe
82d8e1b0a9 Added item back into edit
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 04:18:57 +00:00
snipe
5a7ffa5664 Sure, whatever I guess.
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 04:18:40 +00:00
snipe
55abd242f2 Don’t know why I need to compact this?
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 04:07:09 +00:00
snipe
217d65f64c More changes to the error message formatting
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 03:47:51 +00:00
snipe
fa20eb4965 Add exception for hardware vs assets :(
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 03:41:01 +00:00
snipe
560311b883 Added ->with(‘item’) back in
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 03:37:34 +00:00
snipe
3954ff20b4 More tweaks to the controllers, more breadcrumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 03:29:31 +00:00
snipe
989082d719 Handle the not found errors with route model binding
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 03:26:44 +00:00
snipe
644527c5a6 More resources to breadcrumb provider
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 02:49:21 +00:00
snipe
f7d213052a Route model binding for resource groups
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 02:49:05 +00:00
snipe
972bd1ef83 Tinkering with routes for breadcrumbs
Signed-off-by: snipe <snipe@snipe.net>
2025-02-19 00:37:09 +00:00
Marcus Moore
cf0ce1c5ea Start to implement tests 2025-02-18 16:24:52 -08:00
Marcus Moore
3d69721af0 Scaffold tests 2025-02-18 16:16:00 -08:00
Marcus Moore
1995e1399e Start recording ip, user agent, and source 2025-02-18 16:04:53 -08:00
Marcus Moore
79d1147f20 Add validation 2025-02-18 15:46:52 -08:00
Marcus Moore
53c084c6c0 WIP: begin to store notes 2025-02-18 15:43:58 -08:00
Marcus Moore
c165e6f400 Formatting 2025-02-18 15:20:22 -08:00
Marcus Moore
25215fd3c9 WIP: begin migrating notes to ui controller 2025-02-18 15:20:06 -08:00
Brady Wetherington
a8231bc338 Merge branch 'develop' into v8 2025-02-18 22:40:27 +00:00
snipe
4d25e8f7f0 Merge pull request #16271 from snipe/localization/2024-02-18
Updated language strings
2025-02-18 22:26:02 +00:00
snipe
8368576dc9 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 22:18:39 +00:00
snipe
071b4d1e67 Merge pull request #16245 from marcusmoore/chore/migrate-form-open-pt5
Replace Form::open and Form::close pt5
2025-02-18 21:23:15 +00:00
snipe
1fe170e6a1 Merge pull request #16040 from Godmartinz/template_validate_error
Adds a null check to label templates, adds return types for validation methods
2025-02-18 21:00:10 +00:00
snipe
612a708c8d Merge pull request #16246 from marcusmoore/chore/migrate-form-open-pt6
Replace Form::open and Form::close pt6
2025-02-18 20:43:38 +00:00
snipe
580a4c476e Merge pull request #16244 from marcusmoore/chore/migrate-form-open-pt4
Replace Form::open and Form::close pt4
2025-02-18 20:42:44 +00:00
snipe
c9de9ebbab Merge pull request #16243 from marcusmoore/chore/migrate-form-open-pt3
Replace Form::open and Form::close pt3
2025-02-18 20:41:56 +00:00
snipe
3d0770973a Merge pull request #16242 from marcusmoore/chore/migrate-form-open-pt2
Replace Form::open and Form::close pt2
2025-02-18 20:41:16 +00:00
snipe
e814cd5a9e Merge pull request #16235 from marcusmoore/chore/migrate-form-open-pt1
Replace Form::open and Form::close pt1
2025-02-18 20:23:47 +00:00
Marcus Moore
e5f426ec64 Remove unneeded multipart/form-data 2025-02-18 12:19:32 -08:00
snipe
a1b0a30351 Merge pull request #16225 from marcusmoore/chore/remove-cols-from-textarea
Removed cols property from textarea component
2025-02-18 19:56:40 +00:00
snipe
c0f0f43dd7 Merge pull request #16188 from Godmartinz/translations-for-labels-n-ldap
Adds translations to LDAP  and Label settings pages
2025-02-18 19:56:14 +00:00
snipe
57c07a3687 Merge pull request #16270 from snipe/feature/sc-28365_ldap_text_update
Updated LDAP sync text
2025-02-18 19:28:18 +00:00
snipe
6de08f46fd Few more tweaks
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 19:26:36 +00:00
snipe
3554270366 Updated LDAP sync text
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 19:25:40 +00:00
snipe
029450bcbf Merge pull request #16269 from snipe/bug/sc-28437_fix
Scope API results by location ID
2025-02-18 19:05:29 +00:00
snipe
329fbf6a7c Scope results by location ID
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 19:01:16 +00:00
snipe
b7d0fccabc Merge pull request #16268 from snipe/fixed_16259_archived_assets_in_company_scope
Fixed #16259 - mismatch in asset count if archived assets are hidden
2025-02-18 16:35:01 +00:00
snipe
48ab94c15b Fixed query duplication for AssetsForShow scope
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 16:18:12 +00:00
snipe
ac907add83 Merge pull request #16082 from marcusmoore/chore/sc-28173
Replace calls to Form::text
2025-02-18 14:58:40 +00:00
snipe
3d47a8ba50 Fixed name format tests (#16236)
Signed-off-by: snipe <snipe@snipe.net>
2025-02-18 14:52:52 +00:00
snipe
452185be45 Merge pull request #16199 from akemidx/feature/sc-28271
Adding <Last Name.First Initial> as an option for usernames
2025-02-18 14:42:54 +00:00
Brady Wetherington
14feed61d8 Merge branch 'develop' into v8 2025-02-17 16:18:02 +00:00
snipe
02a8e17704 Merge pull request #16260 from snipe/fix_for_qr_on_old_label_engine
Fix for QR code on old label engine
2025-02-17 10:45:51 +00:00
snipe
7553ec3e27 Fixed equals
Signed-off-by: snipe <snipe@snipe.net>
2025-02-17 10:44:58 +00:00
snipe
c8f82cbc2b Merge pull request #16250 from uberbrady/improve_tls_client_side_file_caching
Instead of saving TLS cache-files on save, cache them when used
2025-02-13 15:46:22 +00:00
Brady Wetherington
b7bd56daf7 Instead of saving TLS cache-files on save, cache them when used 2025-02-13 15:09:28 +00:00
snipe
393118f083 Merge pull request #16249 from snipe/flatten_api_return
Return flat JSON instead of transformed data
2025-02-13 14:28:41 +00:00
snipe
d3210c6d40 Return flat JSON instead of transformed data
Signed-off-by: snipe <snipe@snipe.net>
2025-02-13 14:16:32 +00:00
Marcus Moore
60d7232569 Remove unneeded Form::close from users index 2025-02-12 13:50:38 -08:00
Marcus Moore
2f1212fa1a Remove unneeded Form::close on view status label page 2025-02-12 13:49:37 -08:00
Marcus Moore
cc4d8f2a5b Migrate Form::close on security settings page 2025-02-12 13:47:15 -08:00
Marcus Moore
c0a3284fad Migrate Form::open and Form::close on saml settings 2025-02-12 13:46:42 -08:00
Marcus Moore
caff608e3c Migrate Form::open and Form::close on purge deleted records page 2025-02-12 13:41:44 -08:00
Marcus Moore
c48fa7c2cb Migrate Form::open and Form::close on localization page 2025-02-12 13:39:04 -08:00
Marcus Moore
14b25949b8 Migrate Form::close on ldap settings page 2025-02-12 13:36:48 -08:00
Marcus Moore
2df995c2c7 Remove unneeded Form::open on label settings page 2025-02-12 13:29:02 -08:00
Marcus Moore
ad182a96fa Migrate Form::open and Form::close on label settings 2025-02-12 13:28:40 -08:00
Marcus Moore
a728f38bd1 Migrate Form::open and Form::close on google settings page 2025-02-12 13:21:07 -08:00
Marcus Moore
894754e8dc Migrate Form::close on general settings page 2025-02-12 13:18:55 -08:00
Marcus Moore
d141675478 Migrate Form::open and Form::close on branding settings pagee 2025-02-12 13:17:59 -08:00
Marcus Moore
8bdd80e236 Migrate Form::open and Form::close on backups page 2025-02-12 13:12:45 -08:00
Marcus Moore
c422737525 Migrate Form::open and Form::close on asset tag settings page 2025-02-12 13:11:06 -08:00
Marcus Moore
fc55786ca2 Migrate Form::close on notification settings page 2025-02-12 12:50:37 -08:00
Marcus Moore
2949fdecdd Migrate Form::open and Form::close on unaccepted assets report page 2025-02-12 12:49:19 -08:00
Marcus Moore
d32163f881 Migrate Form::open and Form::close on custom report page 2025-02-12 12:43:51 -08:00
Marcus Moore
215fe501ac Migrate Form::open and Form::close on activity report page 2025-02-12 12:14:00 -08:00
Marcus Moore
ef3112e526 Add missing @csrf 2025-02-12 12:11:36 -08:00
Marcus Moore
8aa0135afa Migrate Form::open and Form::close in bulk users partial 2025-02-12 12:10:16 -08:00
snipe
ff1157a95e Merge pull request #16232 from Godmartinz/adds-expiring-notifications
Expiration notifcation switched to use Mailable
2025-02-12 20:07:24 +00:00
Godfrey M
e66b690c93 removed unnecessary base_path changes 2025-02-12 12:01:43 -08:00
Godfrey M
242fd00e8a remove commented dd 2025-02-12 11:55:28 -08:00
Godfrey M
c77a1faa69 moar unnecssary changes removed 2025-02-12 11:54:34 -08:00
Marcus Moore
540b609591 Migrate Form::open and Form::close in models bulk actions partial 2025-02-12 11:53:23 -08:00
Marcus Moore
ac5a409cdf Migrate Form::open and Form::close in locations bulk actions partial 2025-02-12 11:51:17 -08:00
Godfrey M
4cbc751dad removed unnecessary changes 2025-02-12 11:49:36 -08:00
Marcus Moore
1dc579ce71 Migrate Form::open and Form::close in asset bulk actions partial 2025-02-12 11:49:13 -08:00
Marcus Moore
37282fffff Remove unneeded Form::close on model show page 2025-02-12 11:45:09 -08:00
Marcus Moore
b3e98cb7eb Remove unneeded Form::close on model index page 2025-02-12 11:44:14 -08:00
Godfrey M
bd03d70937 adds test for expiring licenses 2025-02-12 11:43:22 -08:00
Marcus Moore
716161e626 Migrate Form::open and Form::close in upload file modal 2025-02-12 11:42:09 -08:00
Marcus Moore
93a67847ba Migrate Form::open and Form::close on asset view 2025-02-12 11:38:19 -08:00
Godfrey M
6873244e7e adds test for expiring asset notifications 2025-02-12 11:28:36 -08:00
Marcus Moore
c569a84f87 Migrate Form::open and Form::close on requested assets page 2025-02-12 10:52:32 -08:00
akemidx
1e07927e78 test created and passing 2025-02-11 19:35:55 -05:00
Marcus Moore
c4b8b85602 Migrate Form::open and Form::close on bulk audit page 2025-02-11 15:42:20 -08:00
Marcus Moore
464e4d11e9 Migrate Form::open and Form::close on quick scan checkin page 2025-02-11 14:24:38 -08:00
Marcus Moore
85e4a19f03 Migrate Form::open on asset audit page 2025-02-11 14:22:17 -08:00
Marcus Moore
6263d01c73 Migrate Form::close in previously changed views 2025-02-11 14:10:52 -08:00
Marcus Moore
967e646989 Migrate Form::open in depreciations view 2025-02-11 14:10:52 -08:00
Marcus Moore
e9d3b9dcde Migrate Form::open and Form::close in manage custom fields view 2025-02-11 14:10:52 -08:00
Marcus Moore
3065ba851e Migrate Form::open in custom fieldset view 2025-02-11 14:10:52 -08:00
Marcus Moore
80522a2505 Migrate Form::open in custom field view 2025-02-11 14:10:52 -08:00
Marcus Moore
532e6c1c1d Migrate Form::open in profile view 2025-02-11 14:10:52 -08:00
Marcus Moore
5cf314a314 Migrate Form::open in change password view 2025-02-11 14:10:52 -08:00
snipe
c08cfb9b73 Merge pull request #16226 from snipe/add_notes_to_locations_companies_etc
Fixed #16184 - added notes to locations, companies, categories, manufacturers and groups
2025-02-11 19:25:10 +00:00
snipe
61591633f8 Fixed layout sorta
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 19:23:04 +00:00
Godfrey M
9b5b58687d removed unused 2025-02-11 11:02:25 -08:00
Godfrey M
fb7bec4be4 adds expiring asset and license mail 2025-02-11 10:55:56 -08:00
snipe
9dba03646b Pointless rename
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 18:32:51 +00:00
snipe
ddd2ce07f3 Fixed branch from weird merge down
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 01:14:35 +00:00
snipe
3de5f5882c Added/updated tests
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 01:07:41 +00:00
Marcus Moore
73e010434e Remove cols property 2025-02-10 16:43:39 -08:00
snipe
a9d6a5f618 Updated note partial to use generic notes text
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:39:46 +00:00
snipe
ef9cc4fceb Added notes to blades
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:39:26 +00:00
snipe
e104decf77 Added placeholder translation array
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:35:03 +00:00
snipe
96e38da875 Created migration
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:34:50 +00:00
snipe
ff95049f7c Added notes to factories
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:34:30 +00:00
snipe
63cb4e70bc Added notes to presenters
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:34:10 +00:00
snipe
e6ae9cae6b Added notes to searchable and fillable attributes
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:33:51 +00:00
snipe
1f1e1401cf Added location notes to importer
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:32:58 +00:00
snipe
af1159658d Added notes to transformers
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:32:37 +00:00
snipe
4e2b22135a Added notes to UI controllers
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:32:07 +00:00
snipe
4ee5a4c5c3 Added notes to API controllers
Signed-off-by: snipe <snipe@snipe.net>
2025-02-11 00:31:50 +00:00
snipe
aa14cfe18d Merge pull request #16075 from marcusmoore/chore/migrate-textarea-helper
Convert Form::textarea to blade component
2025-02-11 00:14:23 +00:00
Marcus Moore
0797c4ac97 Merge branch 'develop' into chore/sc-28173
# Conflicts:
#	resources/views/settings/saml.blade.php
#	resources/views/settings/security.blade.php
#	resources/views/setup/user.blade.php
2025-02-10 15:57:41 -08:00
snipe
b4ea75f34f Merge branch 'master' into chore/migrate-textarea-helper 2025-02-10 23:47:13 +00:00
snipe
e37a990820 Merge remote-tracking branch 'origin/develop' 2025-02-10 22:42:58 +00:00
snipe
b54d68ebf1 Merge pull request #16212 from Godmartinz/ternary-checks-on-location-in-notifications
adds ternaries on check in/out hardware notifications
2025-02-10 22:28:36 +00:00
snipe
4ae2126ded Merge pull request #16213 from marcusmoore/chore/migrate-checkbox-helpers-p1
Replace calls to Form::checkbox pt1
2025-02-10 22:27:19 +00:00
snipe
c420670ebb Small fixes to accessories files handling
Signed-off-by: snipe <snipe@snipe.net>
2025-02-10 22:26:00 +00:00
Brady Wetherington
dae1f43359 Merge branch 'develop' into v8 2025-02-10 15:14:55 +00:00
Marcus Moore
77635c3737 Migrate Form::checkboxes on license edit view 2025-02-06 17:05:35 -08:00
Marcus Moore
b937b7e767 Migrate Form::checkboxes on asset history import page 2025-02-06 17:01:09 -08:00
Marcus Moore
38df5e8b07 Replace more Form::checkboxes 2025-02-06 15:52:23 -08:00
akemidx
d1cd670af5 oop forgot the user form bit 2025-02-06 18:05:22 -05:00
Marcus Moore
04e4b6c181 Replace Form::checkbox 2025-02-06 14:16:18 -08:00
Marcus Moore
9559c5a025 Replace Form::checkbox and inline label 2025-02-06 14:08:13 -08:00
Marcus Moore
42fa2e12db Replace Form::checkbox 2025-02-06 13:55:33 -08:00
Godfrey M
f41583fd59 adds ternary checks on locations before pulling names in notifications 2025-02-06 11:34:14 -08:00
snipe
b48704b3af Merge pull request #16209 from uberbrady/eliminate_preg_split_deprecation_warnings
Fixed #16208 - don't call preg_split() with a null
2025-02-06 13:30:53 +00:00
Brady Wetherington
de3ebfecfe Ensure we don't call preg_split() with a null as the second parameter 2025-02-06 13:24:39 +00:00
snipe
29311b1b5b Merge remote-tracking branch 'origin/develop' 2025-02-06 10:34:58 +00:00
snipe
b131227b71 Merge pull request #16207 from snipe/security/upgrade_papaparse
Upgraded papaparse to 5.5.1
2025-02-06 10:34:29 +00:00
snipe
ec45833cd8 Upgraded papaparse to 5.5.1
Signed-off-by: snipe <snipe@snipe.net>
2025-02-06 10:22:17 +00:00
snipe
4c2905b1f0 Merge pull request #16176 from marcusmoore/chore/migrate-form-radio
Replaced some calls to the Form::radio helper
2025-02-06 10:19:51 +00:00
snipe
6e51be6c57 Merge pull request #16178 from marcusmoore/chore/migrate-form-radio-helpers-pt1
Replaced calls to Form::radio helper on group create and edit pages
2025-02-06 10:19:35 +00:00
snipe
b195168c83 Merge pull request #16167 from Godmartinz/asset_controller_qr_check_fix
Adds qr code type check in getQRCode method
2025-02-06 10:18:34 +00:00
snipe
a722eca6aa Merge pull request #16179 from marcusmoore/chore/migrate-form-radio-helpers-bulk-hardware
Replaced calls to Form::radio helper on bulk hardware edit page
2025-02-06 10:18:16 +00:00
snipe
1f6428ee1c Merge pull request #16180 from marcusmoore/chore/migrate-form-radio-helpers-bulk-models
Replaced calls to Form::radio helper on bulk asset model edit page
2025-02-06 10:18:05 +00:00
snipe
ab10fb466c Merge pull request #16193 from marcusmoore/chore/migrate-label-helpers-pt3
Replace calls to Form::label pt3
2025-02-06 10:17:26 +00:00
snipe
dcabf90409 Merge pull request #16192 from marcusmoore/chore/migrate-label-helpers-pt2
Replace calls to Form::label pt2
2025-02-06 10:17:11 +00:00
snipe
27752f595c Merge pull request #16194 from marcusmoore/chore/migrate-label-helpers-pt4
Replace calls to Form::label pt4
2025-02-06 10:16:33 +00:00
snipe
c17598d4b4 Merge pull request #16195 from marcusmoore/chore/migrate-label-helpers-pt5
Replace calls to Form::label pt5
2025-02-06 10:16:17 +00:00
snipe
d74d9900da Merge pull request #16190 from marcusmoore/chore/migrate-label-helpers-pt1
Replace calls to Form::label pt1
2025-02-06 10:15:43 +00:00
snipe
5505c9ab67 Merge pull request #16196 from marcusmoore/chore/migrate-label-helpers-pt6
Replace calls to Form::label pt6
2025-02-06 10:14:55 +00:00
snipe
8d2ffea7df Merge pull request #16197 from marcusmoore/chore/migrate-label-helpers-pt7
Replace calls to Form::label in QuickStart
2025-02-06 10:06:41 +00:00
snipe
1233c939f8 Merge branch 'develop' into chore/migrate-label-helpers-pt7 2025-02-06 10:03:42 +00:00
snipe
46dd83c34e Merge pull request #16168 from Godmartinz/print_all_assigned_location_null_check
Added ternary check that asset has `asset status` before checking archived
2025-02-06 10:01:10 +00:00
snipe
639aa85353 Merge pull request #16198 from marcusmoore/chore/migrate-email-helpers
Replace call to Form::email
2025-02-06 09:57:53 +00:00
akemidx
008b6f1db2 lastname.first initial 2025-02-05 20:11:33 -05:00
Marcus Moore
f46ad4811e Migrate form email helper on user setup page 2025-02-05 16:44:09 -08:00
Marcus Moore
b39b24e6b9 Migrate form labels on user setup 2025-02-05 15:01:51 -08:00
Marcus Moore
7f0133a4d6 Migrate form labels on create supplier page 2025-02-05 14:42:07 -08:00
Marcus Moore
85bc8bc8f0 Migrate form label on create status label page 2025-02-05 14:40:20 -08:00
Marcus Moore
32e1d4b2ef Migrate form labels on security settings page 2025-02-05 14:39:16 -08:00
Marcus Moore
f8d5af836f Migrate form labels on saml settings page 2025-02-05 14:35:53 -08:00
Marcus Moore
19ceb3f5b7 Migrate form label on purge page 2025-02-05 14:29:49 -08:00
Marcus Moore
f346c55cf1 Migrate form labels on localization settings page 2025-02-05 14:29:49 -08:00
Marcus Moore
e797705dad Migrate form labels on google settings page 2025-02-05 14:29:49 -08:00
Marcus Moore
a331e14ef2 Migrate form labels on general settings page 2025-02-05 14:19:34 -08:00
Marcus Moore
d6b4c27302 Migrate form label on branding settings page 2025-02-05 14:14:50 -08:00
Marcus Moore
f8d7291923 Migrate form labels on asset tag settings page 2025-02-05 14:11:36 -08:00
Marcus Moore
b59674ab77 Migrate form labels on settings alert page 2025-02-05 13:48:50 -08:00
Marcus Moore
0620b8b163 Migrate form label in checkout select partial 2025-02-05 13:44:00 -08:00
Marcus Moore
f639d82693 Migrate form label in user select partial 2025-02-05 13:40:27 -08:00
Marcus Moore
13d2d41f0c Migrate form label in supplier select partial 2025-02-05 13:39:03 -08:00
Marcus Moore
015cd44136 Migrate form label in status select partial 2025-02-05 13:34:07 -08:00
Marcus Moore
4834f60a44 Migrate form label in phone input partial 2025-02-05 13:32:06 -08:00
Marcus Moore
3327e1d8f2 Migrate form label in asset model select partial 2025-02-05 13:30:14 -08:00
Marcus Moore
40e002911c Migrate form label in manufacturer select partial 2025-02-05 13:29:06 -08:00
Marcus Moore
03bcc3b73f Migrate form label in location select partial 2025-02-05 13:27:29 -08:00
Marcus Moore
f963df0658 Migrate form label in location profile select partial 2025-02-05 13:26:08 -08:00
Marcus Moore
0aa77d281f Replace calls to Form::label in license-select partial 2025-02-05 13:24:02 -08:00
Marcus Moore
0988255693 Replace calls to Form::label in (unused?) kit select 2025-02-05 13:23:10 -08:00
Marcus Moore
fb9e7cf5e1 Migrate form label in fax input partial 2025-02-05 13:19:22 -08:00
Marcus Moore
ecc1bd69b9 Migrate form label in department select partial 2025-02-05 13:19:16 -08:00
Marcus Moore
830f095a6e Migrate form label in datepicker partial 2025-02-05 13:16:28 -08:00
Marcus Moore
288f7e4e93 Migrate form label on consumable select 2025-02-05 13:12:52 -08:00
Marcus Moore
a205ae12a4 Migrate form label on (unsed?) company select partial 2025-02-05 13:11:49 -08:00
Marcus Moore
1866426f11 Migrate form label in category select partial 2025-02-05 13:02:36 -08:00
Marcus Moore
e4ab6c0c24 Migrate form label on asset select partial 2025-02-05 12:59:00 -08:00
Marcus Moore
189c148761 Migrate labels on address partial 2025-02-05 12:47:06 -08:00
Marcus Moore
8b7c1a195c Migrate label on accessory select partial 2025-02-05 12:41:35 -08:00
Marcus Moore
d77547aecf Migrate labels on slack component 2025-02-05 12:40:00 -08:00
Marcus Moore
478a5c0e1a Migrate labels on bulk audit pag 2025-02-05 12:12:43 -08:00
Marcus Moore
5c6757ecf6 Migrate labels on quick checkin page 2025-02-05 12:07:17 -08:00
Godfrey M
f2981cf12b adds translations to label settings 2025-02-05 10:55:05 -08:00
Godfrey M
c3310a0772 adds translations to LDAP settings page 2025-02-05 10:38:16 -08:00
Marcus Moore
fe485acd4a Swap Form::radio in bulk model edit view 2025-02-04 16:18:49 -08:00
Marcus Moore
fbe19738cb Swap Form::radio in bulk hardware edit view 2025-02-04 15:49:46 -08:00
Marcus Moore
d29a62a335 Simplify @checked 2025-02-04 13:50:08 -08:00
snipe
6cc2013102 Merge remote-tracking branch 'origin/develop' 2025-02-04 21:39:27 +00:00
snipe
39ce7b75ca Merge pull request #16175 from Godmartinz/channel-not-found-warning-added 2025-02-04 21:38:15 +00:00
Marcus Moore
f3959323ff Add required attribute to name field 2025-02-04 13:33:16 -08:00
Marcus Moore
0d62ab2ad4 Fix call to @checked 2025-02-04 13:31:28 -08:00
Godfrey M
cbf9239d86 adds channel not found warning 2025-02-04 11:21:56 -08:00
Marcus Moore
295875c45e Fix and replace remaining radios on bulk user edit page 2025-02-04 11:02:40 -08:00
snipe
5e363f7dd4 Merge pull request #16166 from Godmartinz/rollbar_none-qr-code 2025-02-04 16:16:00 +00:00
Godfrey M
6bb0927f26 remove unrelated change 2025-02-03 12:30:21 -08:00
Godfrey M
24bb679305 adds check that asset has asset status before checking archived 2025-02-03 12:24:22 -08:00
Godfrey M
ddc22b4d6b adds a check to see that qr code type is not none 2025-02-03 10:38:49 -08:00
Godfrey M
9a75131a98 removed old label artifact 2025-02-03 10:18:13 -08:00
Marcus Moore
26b4063435 Convert section items 2025-01-30 16:07:46 -08:00
Marcus Moore
8dd432c3a2 Convert section headings 2025-01-30 15:56:08 -08:00
Marcus Moore
0e390f1a9b Temporarily order properties 2025-01-30 15:54:27 -08:00
Marcus Moore
6fb83d66a2 Revert "Re-order parameters"
This reverts commit bf96688aef.
2025-01-30 15:46:22 -08:00
Marcus Moore
bf96688aef Re-order parameters 2025-01-30 15:37:05 -08:00
Marcus Moore
eb4aeb47c1 Replace Form::radio in top section of group permissions page 2025-01-30 15:36:38 -08:00
snipe
d906f3cf62 Merge pull request #16148 from spencerrlongg/bug/sc-27619 2025-01-29 21:05:08 +00:00
spencerrlongg
0defed9abe add nullsafe 2025-01-29 11:27:02 -06:00
Marcus Moore
ac925af3d0 Replace a few radio inputs on bulk user edit page 2025-01-27 13:50:22 -08:00
Marcus Moore
4f08b2360c Migrate radios on custom report page 2025-01-27 13:36:59 -08:00
snipe
fd60ce1198 Merge pull request #16140 from marcusmoore/chore/sc-28233 2025-01-27 19:28:41 +00:00
Marcus Moore
00cdb13803 Convert remaining Form:hidden in labels view 2025-01-27 11:23:01 -08:00
Marcus Moore
ef6d747b37 Convert some Form:hidden in labels view 2025-01-27 11:15:09 -08:00
Marcus Moore
e26abb8684 Replace Form::hidden with @csrf 2025-01-27 11:07:19 -08:00
Marcus Moore
82801242d3 Merge branch 'develop' into chore/sc-28173
# Conflicts:
#	resources/views/settings/alerts.blade.php
2025-01-22 14:54:53 -08:00
snipe
5ac6caf257 Merge remote-tracking branch 'origin/develop' 2025-01-22 21:49:55 +00:00
snipe
bebc1f4d0d Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-01-22 17:31:17 +00:00
Marcus Moore
31097bdc37 Formatting 2025-01-21 10:25:53 -08:00
Marcus Moore
e733d2a5d0 Backfill test 2025-01-21 10:24:15 -08:00
Marcus Moore
6a35fa7ba3 Account for missing asset model 2025-01-21 10:14:27 -08:00
Marcus Moore
370666b5bd Fix indenting 2025-01-21 10:12:56 -08:00
snipe
fb857ccf56 Merge remote-tracking branch 'origin/develop' 2025-01-20 21:07:04 +00:00
snipe
d4ef0f8aa8 Merge remote-tracking branch 'origin/develop' 2025-01-20 20:26:33 +00:00
snipe
48ff7cdbe8 Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-01-20 17:00:02 +00:00
snipe
ca446ad7df Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-01-20 16:59:55 +00:00
Brady Wetherington
dd34f07989 Fix custom translator for new Laravel 11 syntax 2025-01-20 15:24:06 +00:00
snipe
5dafa3c5c9 Merge remote-tracking branch 'origin/develop' 2025-01-20 15:00:01 +00:00
Brady Wetherington
6b242f47e4 Initial work at putting together a v8 branch 2025-01-20 14:54:28 +00:00
Brady Wetherington
17c9c93456 Made composer changes for v8 2025-01-20 14:04:57 +00:00
snipe
954ffbfcaf Merge remote-tracking branch 'origin/develop' 2025-01-17 19:11:18 +00:00
snipe
7f5ea30904 Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-01-17 17:09:00 +00:00
snipe
53b6ccbac0 Merge remote-tracking branch 'origin/develop' 2025-01-17 17:07:44 +00:00
snipe
eaa0e9d1fa Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2025-01-17 16:38:46 +00:00
Godfrey M
0eb34cb979 adds period to translation 2025-01-16 13:24:32 -08:00
Godfrey M
79a4c83879 add spaces 2025-01-16 13:23:16 -08:00
Marcus Moore
cb56f89954 Merge branch 'develop' into chore/sc-28173
# Conflicts:
#	resources/views/settings/alerts.blade.php
2025-01-15 16:54:10 -08:00
Marcus Moore
68988524d6 Replace Form::text in certain views 2025-01-15 16:31:16 -08:00
Marcus Moore
c278900581 Replace Form::text in certain views 2025-01-15 15:58:33 -08:00
Marcus Moore
8e790fdc47 Replace Form::text in certain views 2025-01-15 13:37:00 -08:00
Marcus Moore
0ef20c524f Replace Form::text in certain views 2025-01-15 13:01:32 -08:00
Marcus Moore
5ccaf2c23e Replace Form::text in certain views 2025-01-15 12:23:43 -08:00
Marcus Moore
bec9511df1 Add more spacing for input values to be displayed 2025-01-15 12:10:05 -08:00
Marcus Moore
017948c3bb Replace Form::text in certain views 2025-01-15 12:07:33 -08:00
Marcus Moore
1cb72e3e9c Replace Form::text in certain views 2025-01-15 11:53:22 -08:00
Marcus Moore
e45f563b50 Convert Form::textareas to blade component 2025-01-14 13:16:31 -08:00
Godfrey M
69d255f584 adds validation rules for label names 2025-01-14 12:07:59 -08:00
Godfrey Martinez
dd08642a7c Merge pull request #25 from Godmartinz/template_validate_error_p2
remove try catch, add validation rules for label template
2025-01-14 09:52:09 -08:00
Godfrey M
3ac0877418 remove try/catch, add rules for template 2025-01-14 09:50:43 -08:00
Marcus Moore
9573428201 Introduce textarea component 2025-01-13 16:34:12 -08:00
snipe
99526cfc2c Remove mcrypt and legacy recrypter
Signed-off-by: snipe <snipe@snipe.net>
2025-01-13 19:54:00 +00:00
Godfrey M
0118504cd3 adds redirect to render and save if template is null 2025-01-08 15:32:23 -08:00
Godfrey M
f4e69679ca add a try catch around template validation 2025-01-08 12:13:31 -08:00
Godfrey M
ce7a8ad808 add a space 2025-01-08 09:48:45 -08:00
Godfrey M
c17c011488 checks if template is null, adds return types for validation methods 2025-01-08 09:47:20 -08:00
1102 changed files with 13471 additions and 5997 deletions

View File

@@ -3271,6 +3271,24 @@
"contributions": [
"code"
]
},
{
"login": "addex12",
"name": "Adugna Gizaw",
"avatar_url": "https://avatars.githubusercontent.com/u/18550946?v=4",
"profile": "https://orbalia.pythonanywhere.com/",
"contributions": [
"translation"
]
},
{
"login": "jostrander",
"name": "Jesse Ostrander",
"avatar_url": "https://avatars.githubusercontent.com/u/760989?v=4",
"profile": "https://github.com/jostrander",
"contributions": [
"code"
]
}
]
}

View File

@@ -16,7 +16,7 @@ APP_DEBUG=true
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
APP_URL=http://localhost:8000
APP_TIMEZONE='UTC'
APP_LOCALE=en
APP_LOCALE=en-US
MAX_RESULTS=500
# --------------------------------------------

View File

@@ -25,9 +25,9 @@ jobs:
fail-fast: false
matrix:
php-version:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
name: PHP ${{ matrix.php-version }}

View File

@@ -21,9 +21,10 @@ jobs:
fail-fast: false
matrix:
php-version:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
name: PHP ${{ matrix.php-version }}

View File

@@ -15,7 +15,7 @@ jobs:
fail-fast: false
matrix:
php-version:
- "8.1.1"
- "8.3"
name: PHP ${{ matrix.php-version }}

View File

@@ -3,8 +3,8 @@
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
"DOC4": "You should really just ignore it and run upgrade.php. Really",
"php_min_version": "8.1.0",
"php_max_major_minor": "8.3",
"php_max_wontwork": "8.4.0",
"current_snipeit_version": "7.0"
"php_min_version": "8.2.0",
"php_max_major_minor": "8.4",
"php_max_wontwork": "8.5.0",
"current_snipeit_version": "8.0"
}

View File

@@ -53,7 +53,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") |
| [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") |
| [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/18550946?v=4" width="110px;"/><br /><sub>Adugna Gizaw</sub>](https://orbalia.pythonanywhere.com/)<br />[🌍](#translation-addex12 "Translation") | [<img src="https://avatars.githubusercontent.com/u/760989?v=4" width="110px;"/><br /><sub>Jesse Ostrander</sub>](https://github.com/jostrander)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -1,4 +1,4 @@
FROM ubuntu:22.04
FROM ubuntu:24.04
LABEL maintainer="Brady Wetherington <bwetherington@grokability.com>"
# No need to add `apt-get clean` here, reference:
@@ -14,16 +14,16 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
apt-utils \
apache2 \
apache2-bin \
libapache2-mod-php8.1 \
php8.1-curl \
php8.1-ldap \
php8.1-mysql \
php8.1-gd \
php8.1-xml \
php8.1-mbstring \
php8.1-zip \
php8.1-bcmath \
php8.1-redis \
libapache2-mod-php8.3 \
php8.3-curl \
php8.3-ldap \
php8.3-mysql \
php8.3-gd \
php8.3-xml \
php8.3-mbstring \
php8.3-zip \
php8.3-bcmath \
php8.3-redis \
php-memcached \
patch \
curl \
@@ -40,8 +40,7 @@ autoconf \
libc-dev \
libldap-common \
pkg-config \
libmcrypt-dev \
php8.1-dev \
php8.3-dev \
ca-certificates \
unzip \
dnsutils \
@@ -51,18 +50,13 @@ dnsutils \
RUN curl -L -O https://github.com/pear/pearweb_phars/raw/master/go-pear.phar
RUN php go-pear.phar
RUN pecl install mcrypt
RUN bash -c "echo extension=/usr/lib/php/20210902/mcrypt.so > /etc/php/8.1/mods-available/mcrypt.ini"
RUN phpenmod mcrypt
RUN phpenmod gd
RUN phpenmod bcmath
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.1/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.1/cli/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.3/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.3/cli/php.ini
RUN useradd -m --uid 1000 --gid 50 docker
RUN useradd -m --uid 10000 --gid 50 docker
RUN echo export APACHE_RUN_USER=docker >> /etc/apache2/envvars
RUN echo export APACHE_RUN_GROUP=staff >> /etc/apache2/envvars

View File

@@ -7,7 +7,7 @@
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
It is built on [Laravel 10](http://laravel.com).
It is built on [Laravel 11](http://laravel.com).
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
@@ -94,6 +94,8 @@ Since the release of the JSON REST API, several third-party developers have been
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by [@ReticentRobot](https://github.com/ReticentRobot) - Windows agent for Snipe-IT.
- [Gate Pass Generator](https://github.com/cha7uraAE/snipe-it-gate-pass-system) by [@cha7uraAE](https://github.com/cha7uraAE) - A Streamlit application for generating gate passes based on hardware data from a Snipe-IT API.
We also have a handful of [Google Apps scripts](https://github.com/grokability/google-apps-scripts-for-snipe-it) to help with various tasks.
-----
### Join the Community!

View File

@@ -125,6 +125,10 @@ class LdapSync extends Command
*/
$attributes = array_values(array_filter($ldap_map));
if (Setting::getSettings()->is_ad === 1 && is_null($ldap_map['active_flag'])) {
$attributes[] = 'useraccountcontrol';
}
$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);
} catch (\Exception $e) {

View File

@@ -1,157 +0,0 @@
<?php
namespace App\Console\Commands;
use App\LegacyEncrypter\McryptEncrypter;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\Setting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class RecryptFromMcrypt extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:legacy-recrypt
{--force : Force a re-crypt of encrypted data from MCRYPT.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command allows upgrading users to de-encrypt their deprecated mcrypt encrypted fields and re-encrypt them using the current OpenSSL encryption.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// Check and see if they have a legacy app key listed in their .env
// If not, we can try to use the current APP_KEY if looks like it's old
$legacy_key = env('LEGACY_APP_KEY');
$key_parts = explode(':', $legacy_key);
$legacy_cipher = env('LEGACY_CIPHER', 'rijndael-256');
$errors = [];
if (! $legacy_key) {
$this->error('ERROR: You do not have a LEGACY_APP_KEY set in your .env file. Please locate your old APP_KEY and ADD a line to your .env file like: LEGACY_APP_KEY=YOUR_OLD_APP_KEY');
return false;
}
// Do some basic legacy app key length checks
if (strlen($legacy_key) == 32) {
$legacy_length_check = true;
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1]) == 44)) {
$legacy_key = base64_decode($key_parts[1], true);
$legacy_length_check = true;
} else {
$legacy_length_check = false;
}
// Check that the app key is 32 characters
if ($legacy_length_check === true) {
$this->comment('INFO: Your LEGACY_APP_KEY looks correct. Okay to continue.');
} else {
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters or base64 followed by 44 characters for later versions). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
return false;
}
$this->error('================================!!!! WARNING !!!!================================');
$this->error('================================!!!! WARNING !!!!================================');
$this->comment("This tool will attempt to decrypt your old Snipe-IT (mcrypt, now deprecated) encrypted data and re-encrypt it using OpenSSL. \n\nYou should only continue if you have backed up any and all old APP_KEYs and have backed up your data.");
$force = ($this->option('force')) ? true : false;
if ($force || ($this->confirm('Are you SURE you wish to continue?'))) {
$backup_file = 'backups/env-backups/'.'app_key-'.date('Y-m-d-gis');
try {
Storage::disk('local')->put($backup_file, 'APP_KEY: '.config('app.key'));
Storage::disk('local')->append($backup_file, 'LEGACY_APP_KEY: '.$legacy_key);
} catch (\Exception $e) {
$this->info('WARNING: Could not backup app keys');
}
if ($legacy_cipher) {
$mcrypter = new McryptEncrypter($legacy_key, $legacy_cipher);
} else {
$mcrypter = new McryptEncrypter($legacy_key);
}
$settings = Setting::getSettings();
if ($settings->ldap_pword == '') {
$this->comment('INFO: No LDAP password found. Skipping... ');
} else {
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
$settings->ldap_pword = Crypt::encrypt($decrypted_ldap_pword);
$settings->save();
}
/** @var CustomField[] $custom_fields */
$custom_fields = CustomField::where('field_encrypted', '=', 1)->get();
$this->comment('INFO: Retrieving encrypted custom fields...');
$query = Asset::withTrashed();
foreach ($custom_fields as $custom_field) {
$this->comment('FIELD TO RECRYPT: '.$custom_field->name.' ('.$custom_field->db_column.')');
$query->orWhereNotNull($custom_field->db_column);
}
// Get all assets with a value in any of the fields that were encrypted
/** @var Asset[] $assets */
$assets = $query->get();
$bar = $this->output->createProgressBar(count($assets));
foreach ($assets as $asset) {
foreach ($custom_fields as $encrypted_field) {
$columnName = $encrypted_field->db_column;
// Make sure the value isn't null
if ($asset->{$columnName} != '') {
// Try to decrypt the payload using the legacy app key
try {
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
$asset->{$columnName} = Crypt::encrypt($decrypted_field);
$this->comment($decrypted_field);
} catch (\Exception $e) {
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
}
}
}
$asset->save();
$bar->advance();
}
$bar->finish();
if (count($errors) > 0) {
$this->comment("\n\n");
$this->error("The decrypter encountered some errors: \n");
foreach ($errors as $error) {
$this->error($error);
}
}
}
}
}

View File

@@ -2,13 +2,13 @@
namespace App\Console\Commands;
use App\Mail\ExpiringAssetsMail;
use App\Mail\ExpiringLicenseMail;
use App\Models\Asset;
use App\Models\License;
use App\Models\Recipients\AlertRecipient;
use App\Models\Setting;
use App\Notifications\ExpiringAssetsNotification;
use App\Notifications\ExpiringLicenseNotification;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendExpirationAlerts extends Command
{
@@ -47,22 +47,22 @@ class SendExpirationAlerts extends Command
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {
// Send a rollup to the admin, if settings dictate
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
return new AlertRecipient($item);
});
$recipients = collect(explode(',', $settings->alert_email))
->map(fn($item) => trim($item)) // Trim each email
->all();
// Expiring Assets
$assets = Asset::getExpiringWarrantee($threshold);
if ($assets->count() > 0) {
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
\Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $threshold));
}
// Expiring licenses
$licenses = License::getExpiringLicenses($threshold);
if ($licenses->count() > 0) {
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold]));
\Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold));
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $threshold));
}
} else {
if ($settings->alert_email == '') {

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NoteAdded
{
use Dispatchable, SerializesModels;
public $itemNoteAddedOn;
public $note;
public $noteAddedBy;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($itemNoteAddedOn, User $noteAddedBy, $note)
{
$this->itemNoteAddedOn = $itemNoteAddedOn;
$this->note = $note;
$this->noteAddedBy = $noteAddedBy;
}
}

View File

@@ -122,6 +122,27 @@ class Handler extends ExceptionHandler
}
// This is traaaaash but it handles models that are not found while using route model binding :(
// The only alternative is to set that at *each* route, which is crazypants
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
$model_name = last(explode('\\', $e->getModel()));
$route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index';
// Sigh.
if ($route == 'assets.index') {
$route = 'hardware.index';
} elseif ($route == 'reporttemplates.index') {
$route = 'reports/custom';
} elseif ($route == 'assetmodels.index') {
$route = 'models.index';
} elseif ($route == 'predefinedkits.index') {
$route = 'kits.index';
}
return redirect()
->route($route)
->withError(trans('general.generic_model_not_found', ['model' => $model_name]));
}
if ($this->isHttpException($e) && (isset($statusCode)) && ($statusCode == '404' )) {

View File

@@ -1520,11 +1520,11 @@ class Helper
if ($redirect_option == 'target') {
switch ($checkout_to_type) {
case 'user':
return route('users.show', ['user' => $request->assigned_user]);
return route('users.show', $request->assigned_user);
case 'location':
return route('locations.show', ['location' => $request->assigned_location]);
return route('locations.show', $request->assigned_location);
case 'asset':
return route('hardware.show', ['hardware' => $request->assigned_asset]);
return route('hardware.show', $request->assigned_asset);
}
}
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));

View File

@@ -59,6 +59,8 @@ class IconHelper
return 'fas fa-cog';
case 'angle-left':
return 'fas fa-angle-left';
case 'angle-right':
return 'fas fa-angle-right';
case 'warning':
return 'fas fa-exclamation-triangle';
case 'kits':
@@ -184,6 +186,8 @@ class IconHelper
return 'fa-regular fa-id-card';
case 'department' :
return 'fa-solid fa-building-user';
case 'home' :
return 'fa-solid fa-house';
case 'note':
case 'notes':
return 'fas fa-sticky-note';

View File

@@ -95,16 +95,10 @@ class AccessoriesController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
*/
public function edit($accessoryId = null) : View | RedirectResponse
public function edit(Accessory $accessory) : View | RedirectResponse
{
if ($item = Accessory::find($accessoryId)) {
$this->authorize($item);
return view('accessories.edit', compact('item'))->with('category_type', 'accessory');
}
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
$this->authorize('update', Accessory::class);
return view('accessories.edit')->with('item', $accessory)->with('category_type', 'accessory');
}
/**
@@ -114,19 +108,12 @@ class AccessoriesController extends Controller
* @param int $accessoryId
* @since [v6.0]
*/
public function getClone($accessoryId = null) : View | RedirectResponse
public function getClone(Accessory $accessory) : View | RedirectResponse
{
$this->authorize('create', Accessory::class);
// Check if the asset exists
if (is_null($accessory_to_clone = Accessory::find($accessoryId))) {
// Redirect to the asset management page
return redirect()->route('accessories.index')
->with('error', trans('admin/accessories/message.does_not_exist', ['id' => $accessoryId]));
}
$accessory = clone $accessory_to_clone;
$accessory = clone $accessory;
$accessory->id = null;
$accessory->location_id = null;
@@ -142,9 +129,9 @@ class AccessoriesController extends Controller
* @param ImageUploadRequest $request
* @param int $accessoryId
*/
public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse
public function update(ImageUploadRequest $request, Accessory $accessory) : RedirectResponse
{
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId)) {
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id)) {
$this->authorize($accessory);
@@ -231,14 +218,10 @@ class AccessoriesController extends Controller
* @see AccessoriesController::getDataView() method that generates the JSON response
* @since [v1.0]
*/
public function show($accessoryID = null) : View | RedirectResponse
public function show(Accessory $accessory) : View | RedirectResponse
{
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryID);
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id);
$this->authorize('view', $accessory);
if (isset($accessory->id)) {
return view('accessories.view', compact('accessory'));
}
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist', ['id' => $accessoryID]));
return view('accessories.view', compact('accessory'));
}
}

View File

@@ -55,11 +55,11 @@ class AccessoriesFilesController extends Controller
}
return redirect()->route('accessories.show', $accessory->id)->with('error', trans('general.no_files_uploaded'));
return redirect()->route('accessories.show', $accessory->id)->withFragment('files')->with('error', trans('general.no_files_uploaded'));
}
// Prepare the error message
return redirect()->route('accessories.index')
->with('error', trans('general.file_does_not_exist'));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
/**
@@ -72,29 +72,27 @@ class AccessoriesFilesController extends Controller
*/
public function destroy($accessoryId = null, $fileId = null) : RedirectResponse
{
$accessory = Accessory::find($accessoryId);
// the asset is valid
if (isset($accessory->id)) {
if ($accessory = Accessory::find($accessoryId)) {
$this->authorize('update', $accessory);
$log = Actionlog::find($fileId);
// Remove the file if one exists
if (Storage::exists('accessories/'.$log->filename)) {
try {
Storage::delete('accessories/'.$log->filename);
} catch (\Exception $e) {
Log::debug($e);
if ($log = Actionlog::find($fileId)) {
if (Storage::exists('private_uploads/accessories/'.$log->filename)) {
try {
Storage::delete('private_uploads/accessories/' . $log->filename);
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
} catch (\Exception $e) {
Log::debug($e);
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
}
}
}
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
}
// Redirect to the licence management page
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
/**
@@ -124,10 +122,11 @@ class AccessoriesFilesController extends Controller
}
}
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.log_record_not_found'));
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('accessories.index')->with('error', trans('general.file_not_found'));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
}

View File

@@ -765,9 +765,13 @@ class AssetsController extends Controller
}
if ($problems_updating_encrypted_custom_fields) {
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.encrypted_warning')));
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.encrypted_warning')));
} else {
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
/// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
}
}
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
@@ -1226,7 +1230,10 @@ class AssetsController extends Controller
{
$this->authorize('view', Asset::class);
$this->authorize('view', $asset);
$accessory_checkouts = AccessoryCheckout::AssetsAssigned()->with('adminuser')->with('accessories');
$accessory_checkouts = AccessoryCheckout::AssetsAssigned()
->where('assigned_to', $asset->id)
->with('adminuser')
->with('accessories');
$offset = ($request->input('offset') > $accessory_checkouts->count()) ? $accessory_checkouts->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -1235,6 +1242,8 @@ class AssetsController extends Controller
$accessory_checkouts = $accessory_checkouts->skip($offset)->take($limit)->get();
return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total);
}
/**
* Generate asset labels by tag
*

View File

@@ -39,6 +39,7 @@ class CategoriesController extends Controller
'components_count',
'licenses_count',
'image',
'notes',
];
$categories = Category::select([
@@ -52,6 +53,7 @@ class CategoriesController extends Controller
'require_acceptance',
'checkin_email',
'image',
'notes',
])
->with('adminuser')
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');

View File

@@ -38,11 +38,12 @@ class CompaniesController extends Controller
'accessories_count',
'consumables_count',
'components_count',
'notes',
];
$companies = Company::withCount(['assets as assets_count' => function ($query) {
$query->AssetsForShow();
}])->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
if ($request->filled('search')) {
$companies->TextSearch($request->input('search'));

View File

@@ -48,7 +48,8 @@ class ComponentsController extends Controller
];
$components = Component::select('components.*')
->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer');
->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets')
->withSum('uncontrainedAssets', 'components_assets.assigned_qty');
if ($request->filled('search')) {
$components = $components->TextSearch($request->input('search'));
@@ -197,6 +198,11 @@ class ComponentsController extends Controller
$this->authorize('delete', Component::class);
$component = Component::findOrFail($id);
$this->authorize('delete', $component);
if ($component->numCheckedOut() > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.delete.error_qty')));
}
$component->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.delete.success')));

View File

@@ -23,7 +23,7 @@ class DepartmentsController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', Department::class);
$allowed_columns = ['id', 'name', 'image', 'users_count'];
$allowed_columns = ['id', 'name', 'image', 'users_count', 'notes'];
$departments = Department::select(
'departments.id',
@@ -35,7 +35,8 @@ class DepartmentsController extends Controller
'departments.manager_id',
'departments.created_at',
'departments.updated_at',
'departments.image'
'departments.image',
'departments.notes',
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
if ($request->filled('search')) {

View File

@@ -24,7 +24,7 @@ class GroupsController extends Controller
$this->authorize('view', Group::class);
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
$groups = Group::select('id', 'name', 'permissions', 'notes', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search'));
@@ -81,6 +81,7 @@ class GroupsController extends Controller
$group->name = $request->input('name');
$group->created_by = auth()->id();
$group->notes = $request->input('notes');
$group->permissions = json_encode($request->input('permissions', $groupPermissions));
if ($group->save()) {
@@ -118,6 +119,7 @@ class GroupsController extends Controller
$group = Group::findOrFail($id);
$group->name = $request->input('name');
$group->notes = $request->input('notes');
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
if ($group->save()) {

View File

@@ -53,6 +53,7 @@ class LocationsController extends Controller
'updated_at',
'users_count',
'zip',
'notes',
];
$locations = Location::with('parent', 'manager', 'children')->select([
@@ -73,6 +74,7 @@ class LocationsController extends Controller
'locations.image',
'locations.ldap_ou',
'locations.currency',
'locations.notes',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
@@ -190,6 +192,7 @@ class LocationsController extends Controller
'locations.updated_at',
'locations.image',
'locations.currency',
'locations.notes',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
@@ -255,7 +258,7 @@ class LocationsController extends Controller
{
$this->authorize('view', Accessory::class);
$this->authorize('view', $location);
$accessory_checkouts = AccessoryCheckout::LocationAssigned()->with('adminuser')->with('accessories');
$accessory_checkouts = AccessoryCheckout::LocationAssigned()->where('assigned_to', $location->id)->with('adminuser')->with('accessories');
$offset = ($request->input('offset') > $accessory_checkouts->count()) ? $accessory_checkouts->count() : app('api_offset_value');
$limit = app('api_limit_value');

View File

@@ -39,7 +39,8 @@ class ManufacturersController extends Controller
'assets_count',
'consumables_count',
'components_count',
'licenses_count'
'licenses_count',
'notes',
];
$manufacturers = Manufacturer::select([
@@ -55,6 +56,7 @@ class ManufacturersController extends Controller
'updated_at',
'image',
'deleted_at',
'notes',
])
->with('adminuser')
->withCount('assets as assets_count')

View File

@@ -1,43 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Events\NoteAdded;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class NotesController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'note' => 'required|string|max:500',
'type' => [
'required',
Rule::in(['asset']),
],
]);
// This can be made dynamic by using $request->input('type') to determine which model type to add the note to.
// For now, we are only placing this on Assets
$item = Asset::findOrFail($request->input("id"));
$this->authorize('update', $item);
event(new NoteAdded($item, Auth::user(), $validated['note']));
return response()->json(Helper::formatStandardApiResponse('success'));
}
public function update(Request $request)
{
}
public function destroy(Request $request)
{
}
}

View File

@@ -139,19 +139,12 @@ class AssetMaintenancesController extends Controller
* @version v1.0
* @since [v1.8]
*/
public function edit($assetMaintenanceId = null) : View | RedirectResponse
public function edit(AssetMaintenance $maintenance) : View | RedirectResponse
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
// Redirect to the asset maintenance management page
if ((!$maintenance->asset) || ($maintenance->asset->deleted_at!='')) {
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
} elseif (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
@@ -161,7 +154,7 @@ class AssetMaintenancesController extends Controller
return view('asset_maintenances/edit')
->with('selectedAsset', null)
->with('assetMaintenanceType', $assetMaintenanceType)
->with('item', $assetMaintenance);
->with('item', $maintenance);
}
/**
@@ -174,24 +167,20 @@ class AssetMaintenancesController extends Controller
* @version v1.0
* @since [v1.8]
*/
public function update(Request $request, $assetMaintenanceId = null) : View | RedirectResponse
public function update(Request $request, AssetMaintenance $maintenance) : View | RedirectResponse
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
// Redirect to the asset maintenance management page
if ((!$maintenance->asset) || ($maintenance->asset->deleted_at!='')) {
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
} elseif (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
$assetMaintenance->supplier_id = $request->input('supplier_id');
$assetMaintenance->is_warranty = $request->input('is_warranty');
$assetMaintenance->cost = $request->input('cost');
$assetMaintenance->notes = $request->input('notes');
$maintenance->supplier_id = $request->input('supplier_id');
$maintenance->is_warranty = $request->input('is_warranty');
$maintenance->cost = $request->input('cost');
$maintenance->notes = $request->input('notes');
$asset = Asset::find(request('asset_id'));
@@ -200,39 +189,39 @@ class AssetMaintenancesController extends Controller
}
// Save the asset maintenance data
$assetMaintenance->asset_id = $request->input('asset_id');
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
$assetMaintenance->title = $request->input('title');
$assetMaintenance->start_date = $request->input('start_date');
$assetMaintenance->completion_date = $request->input('completion_date');
$maintenance->asset_id = $request->input('asset_id');
$maintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
$maintenance->title = $request->input('title');
$maintenance->start_date = $request->input('start_date');
$maintenance->completion_date = $request->input('completion_date');
if (($assetMaintenance->completion_date == null)
if (($maintenance->completion_date == null)
) {
if (($assetMaintenance->asset_maintenance_time !== 0)
|| (! is_null($assetMaintenance->asset_maintenance_time))
if (($maintenance->asset_maintenance_time !== 0)
|| (! is_null($maintenance->asset_maintenance_time))
) {
$assetMaintenance->asset_maintenance_time = null;
$maintenance->asset_maintenance_time = null;
}
}
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')
&& ($assetMaintenance->start_date !== '0000-00-00')
if (($maintenance->completion_date !== null)
&& ($maintenance->start_date !== '')
&& ($maintenance->start_date !== '0000-00-00')
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
$startDate = Carbon::parse($maintenance->start_date);
$completionDate = Carbon::parse($maintenance->completion_date);
$maintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
// Was the asset maintenance created?
if ($assetMaintenance->save()) {
if ($maintenance->save()) {
// Redirect to the new asset maintenance page
return redirect()->route('maintenances.index')
->with('success', trans('admin/asset_maintenances/message.edit.success'));
->with('success', trans('admin/asset_maintenances/message.edit.success'));
}
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
return redirect()->back()->withInput()->withErrors($maintenance->getErrors());
}
/**
@@ -271,19 +260,13 @@ class AssetMaintenancesController extends Controller
* @version v1.0
* @since [v1.8]
*/
public function show($assetMaintenanceId) : View | RedirectResponse
public function show(AssetMaintenance $maintenance) : View | RedirectResponse
{
$this->authorize('view', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
return view('asset_maintenances/view')->with('assetMaintenance', $assetMaintenance);
return view('asset_maintenances/view')->with('assetMaintenance', $maintenance);
}
}

View File

@@ -109,16 +109,11 @@ class AssetModelsController extends Controller
* @since [v1.0]
* @param int $modelId
*/
public function edit($modelId = null) : View | RedirectResponse
public function edit(AssetModel $model) : View | RedirectResponse
{
$this->authorize('update', AssetModel::class);
if ($item = AssetModel::find($modelId)) {
$category_type = 'asset';
return view('models/edit', compact('item', 'category_type'))->with('depreciation_list', Helper::depreciationList());
}
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
$category_type = 'asset';
return view('models/edit', compact('category_type'))->with('item', $model)->with('depreciation_list', Helper::depreciationList());
}
@@ -133,16 +128,11 @@ class AssetModelsController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(StoreAssetModelRequest $request, $modelId) : RedirectResponse
public function update(StoreAssetModelRequest $request, AssetModel $model) : RedirectResponse
{
$this->authorize('update', AssetModel::class);
if (is_null($model = AssetModel::find($modelId))) {
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
$model = $request->handleImages($model);
$model->depreciation_id = $request->input('depreciation_id');
$model->eol = $request->input('eol');
$model->name = $request->input('name');
@@ -188,28 +178,16 @@ class AssetModelsController extends Controller
* @since [v1.0]
* @param int $modelId
*/
public function destroy($modelId) : RedirectResponse
public function destroy(AssetModel $model) : RedirectResponse
{
$this->authorize('delete', AssetModel::class);
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
if ($model->assets()->count() > 0) {
// Throw an error that this model is associated with assets
return redirect()->route('models.index')->with('error', trans('admin/models/message.assoc_users'));
}
if ($model->image) {
try {
Storage::disk('public')->delete('models/'.$model->image);
$model->update(['image' => null]);
} catch (\Exception $e) {
Log::info($e);
}
}
// Delete the model
$model->delete();
@@ -267,16 +245,10 @@ class AssetModelsController extends Controller
* @since [v1.0]
* @param int $modelId
*/
public function show($modelId = null) : View | RedirectResponse
public function show(AssetModel $model) : View | RedirectResponse
{
$this->authorize('view', AssetModel::class);
$model = AssetModel::withTrashed()->find($modelId);
if (isset($model->id)) {
return view('models/view', compact('model'));
}
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
return view('models/view', compact('model'));
}
/**
@@ -286,23 +258,20 @@ class AssetModelsController extends Controller
* @since [v1.0]
* @param int $modelId
*/
public function getClone($modelId = null) : View | RedirectResponse
public function getClone(AssetModel $model) : View | RedirectResponse
{
$this->authorize('create', AssetModel::class);
// Check if the model exists
if (is_null($model_to_clone = AssetModel::find($modelId))) {
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
$model = clone $model_to_clone;
$cloned_model = clone $model;
$model->id = null;
$model->deleted_at = null;
// Show the page
return view('models/edit')
->with('depreciation_list', Helper::depreciationList())
->with('item', $model)
->with('model_id', $model_to_clone->id)
->with('clone_model', $model_to_clone);
->with('model_id', $model->id)
->with('clone_model', $cloned_model);
}
@@ -321,7 +290,7 @@ class AssetModelsController extends Controller
/**
* Returns a view that allows the user to bulk edit model attrbutes
* Returns a view that allows the user to bulk edit model attributes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.7]

View File

@@ -58,11 +58,9 @@ class AssetModelsFilesController extends Controller
* @param int $fileId
* @since [v1.0]
*/
public function show($modelId = null, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
public function show(AssetModel $model, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
{
$model = AssetModel::find($modelId);
// the asset is valid
if (isset($model->id)) {
$this->authorize('view', $model);
if (! $log = Actionlog::find($fileId)) {
@@ -87,12 +85,6 @@ class AssetModelsFilesController extends Controller
}
return StorageHelper::downloader($file);
}
// Prepare the error message
$error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]);
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', $error);
}
/**
@@ -103,29 +95,21 @@ class AssetModelsFilesController extends Controller
* @param int $fileId
* @since [v1.0]
*/
public function destroy($modelId = null, $fileId = null) : RedirectResponse
public function destroy(AssetModel $model, $fileId = null) : RedirectResponse
{
$model = AssetModel::find($modelId);
$this->authorize('update', $model);
$rel_path = 'private_uploads/assetmodels';
// the asset is valid
if (isset($model->id)) {
$this->authorize('update', $model);
$log = Actionlog::find($fileId);
if ($log) {
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
$this->authorize('update', $model);
$log = Actionlog::find($fileId);
if ($log) {
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
}

View File

@@ -27,18 +27,12 @@ class AssetCheckinController extends Controller
* @param string $backto
* @since [v1.0]
*/
public function create($assetId, $backto = null) : View | RedirectResponse
public function create(Asset $asset, $backto = null) : View | RedirectResponse
{
// Check if the asset exists
if (is_null($asset = Asset::find($assetId))) {
// Redirect to the asset management page with error
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('checkin', $asset);
// This asset is already checked in, redirect
if (is_null($asset->assignedTo)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
}
@@ -47,7 +41,11 @@ class AssetCheckinController extends Controller
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto)->with('table_name', 'Assets');
return view('hardware/checkin', compact('asset'))
->with('item', $asset)
->with('statusLabel_list', Helper::statusLabelList())
->with('backto', $backto)
->with('table_name', 'Assets');
}
/**
@@ -91,6 +89,9 @@ class AssetCheckinController extends Controller
$asset->status_id = e($request->get('status_id'));
}
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkin');
$this->migrateLegacyLocations($asset);
$asset->location_id = $asset->rtd_location_id;
@@ -128,6 +129,9 @@ class AssetCheckinController extends Controller
session()->put('redirect_option', $request->get('redirect_option'));
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkin');
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));

View File

@@ -26,27 +26,25 @@ class AssetCheckoutController extends Controller
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
*/
public function create($assetId) : View | RedirectResponse
public function create(Asset $asset) : View | RedirectResponse
{
// Check if the asset exists
if (is_null($asset = Asset::with('company')->find(e($assetId)))) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('checkout', $asset);
if (!$asset->model) {
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
return redirect()->route('hardware.show', $asset)
->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
if ($asset->availableForCheckout()) {
return view('hardware/checkout', compact('asset'))
->with('statusLabel_list', Helper::deployableStatusLabelList())
->with('table_name', 'Assets');
->with('table_name', 'Assets')
->with('item', $asset);
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
return redirect()->route('hardware.index')
->with('error', trans('admin/hardware/message.checkout.not_available'));
}
/**
@@ -68,7 +66,7 @@ class AssetCheckoutController extends Controller
$this->authorize('checkout', $asset);
if (!$asset->model) {
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
return redirect()->route('hardware.show', $asset)->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
$admin = auth()->user();
@@ -91,6 +89,7 @@ class AssetCheckoutController extends Controller
$asset->status_id = $request->get('status_id');
}
if(!empty($asset->licenseseats->all())){
if(request('checkout_to_type') == 'user') {
foreach ($asset->licenseseats as $seat){
@@ -100,23 +99,26 @@ class AssetCheckoutController extends Controller
}
}
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkout');
$settings = \App\Models\Setting::getSettings();
// We have to check whether $target->company_id is null here since locations don't have a company yet
if (($settings->full_multiple_companies_support) && ((!is_null($target->company_id)) && (!is_null($asset->company_id)))) {
if ($target->company_id != $asset->company_id){
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
return redirect()->route('hardware.checkout.create', $asset)->with('error', trans('general.error_user_company'));
}
}
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success', trans('admin/hardware/message.checkout.success'));
}
// Redirect to the asset management page with error
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
return redirect()->route("hardware.checkout.create", $asset)->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
} catch (ModelNotFoundException $e) {
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($asset->getErrors());
} catch (CheckoutNotAllowed $e) {

View File

@@ -26,11 +26,8 @@ class AssetFilesController extends Controller
*@since [v1.0]
* @author [A. Gianotto] [<snipe@snipe.net>]
*/
public function store(UploadFileRequest $request, $assetId = null) : RedirectResponse
public function store(UploadFileRequest $request, Asset $asset) : RedirectResponse
{
if (! $asset = Asset::find($assetId)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('update', $asset);
@@ -59,31 +56,28 @@ class AssetFilesController extends Controller
* @param int $fileId
* @since [v1.0]
*/
public function show($assetId = null, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
public function show(Asset $asset, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
{
if ($asset = Asset::find($assetId)) {
$this->authorize('view', $asset);
$this->authorize('view', $asset);
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
$file = 'private_uploads/assets/'.$log->filename;
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.file_not_found'));
}
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
$file = 'private_uploads/assets/'.$log->filename;
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('hardware.show', $asset)->with('error', trans('general.file_not_found'));
}
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
}
@@ -95,23 +89,20 @@ class AssetFilesController extends Controller
* @param int $fileId
* @since [v1.0]
*/
public function destroy($assetId = null, $fileId = null) : RedirectResponse
public function destroy(Asset $asset, $fileId = null) : RedirectResponse
{
if ($asset = Asset::find($assetId)) {
$this->authorize('update', $asset);
$rel_path = 'private_uploads/assets';
$this->authorize('update', $asset);
$rel_path = 'private_uploads/assets';
if ($log = Actionlog::find($fileId)) {
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
if ($log = Actionlog::find($fileId)) {
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
}
}

View File

@@ -30,6 +30,7 @@ use Illuminate\Http\Response;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use TypeError;
/**
* This class controls all actions related to assets for
@@ -201,7 +202,7 @@ class AssetsController extends Controller
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
}
$successes[] = "<a href='" . route('hardware.show', ['hardware' => $asset->id]) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
} else {
$failures[] = join(",", $asset->getErrors()->all());
@@ -222,7 +223,7 @@ class AssetsController extends Controller
//the most common case, keeping it so we don't have to make every use of that translation string be trans_choice'ed
//and re-translated
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', ['hardware' => $asset->id]), 'id', 'tag' => e($asset->asset_tag)]));
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset), 'id', 'tag' => e($asset->asset_tag)]));
} else {
//multi-success
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
@@ -240,20 +241,14 @@ class AssetsController extends Controller
* Returns a view that presents a form to edit an existing asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $assetId
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
*/
public function edit($assetId = null) : View | RedirectResponse
public function edit(Asset $asset) : View | RedirectResponse
{
if (! $item = Asset::find($assetId)) {
// Redirect to the asset management page with error
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
//Handles company checks and permissions.
$this->authorize($item);
return view('hardware/edit', compact('item'))
$this->authorize($asset);
return view('hardware/edit')
->with('item', $asset)
->with('statuslabel_list', Helper::statusLabelList())
->with('statuslabel_types', Helper::statusTypeList());
}
@@ -267,15 +262,14 @@ class AssetsController extends Controller
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
*/
public function show($assetId = null) : View | RedirectResponse
public function show(Asset $asset) : View | RedirectResponse
{
$asset = Asset::withTrashed()->find($assetId);
$this->authorize('view', $asset);
$settings = Setting::getSettings();
if (isset($asset)) {
$audit_log = Actionlog::where('action_type', '=', 'audit')
->where('item_id', '=', $assetId)
->where('item_id', '=', $asset->id)
->where('item_type', '=', Asset::class)
->orderBy('created_at', 'DESC')->first();
@@ -291,7 +285,7 @@ class AssetsController extends Controller
$qr_code = (object) [
'display' => $settings->qr_code == '1',
'url' => route('qr_code/hardware', $asset->id),
'url' => route('qr_code/hardware', $asset),
];
return view('hardware/view', compact('asset', 'qr_code', 'settings'))
@@ -308,14 +302,9 @@ class AssetsController extends Controller
* @since [v1.0]
* @author [A. Gianotto] [<snipe@snipe.net>]
*/
public function update(ImageUploadRequest $request, $assetId = null) : RedirectResponse
public function update(ImageUploadRequest $request, Asset $asset) : RedirectResponse
{
// Check if the asset exists
if (! $asset = Asset::find($assetId)) {
// Redirect to the asset management page with error
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize($asset);
$asset->status_id = $request->input('status_id', null);
@@ -430,7 +419,7 @@ class AssetsController extends Controller
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
if ($asset->save()) {
return redirect()->to(Helper::getRedirectOption($request, $assetId, 'Assets'))
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success', trans('admin/hardware/message.update.success'));
}
@@ -531,12 +520,12 @@ class AssetsController extends Controller
* @param int $assetId
* @since [v1.0]
*/
public function getQrCode($assetId = null) : Response | BinaryFileResponse | string | bool
public function getQrCode(Asset $asset) : Response | BinaryFileResponse | string | bool
{
$settings = Setting::getSettings();
if ($settings->qr_code == '1') {
$asset = Asset::withTrashed()->find($assetId);
if (($settings->qr_code == '1') && ($settings->label2_2d_type !== 'none')) {
if ($asset) {
$size = Helper::barcodeDimensions($settings->label2_2d_type);
$qr_file = public_path().'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png';
@@ -590,7 +579,7 @@ class AssetsController extends Controller
file_put_contents($barcode_file, $barcode_obj->getPngData());
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
} catch (\Exception $e) {
} catch (\Exception|TypeError $e) {
Log::debug('The barcode format is invalid.');
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
@@ -877,12 +866,11 @@ class AssetsController extends Controller
return view('hardware/quickscan-checkin')->with('statusLabel_list', Helper::statusLabelList());
}
public function audit($id)
public function audit(Asset $asset)
{
$settings = Setting::getSettings();
$this->authorize('audit', Asset::class);
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
$asset = Asset::findOrFail($id);
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
@@ -901,7 +889,7 @@ class AssetsController extends Controller
}
public function auditStore(UploadFileRequest $request, $id)
public function auditStore(UploadFileRequest $request, Asset $asset)
{
$this->authorize('audit', Asset::class);
@@ -916,8 +904,6 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
}
$asset = Asset::findOrFail($id);
/**
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
* which would trigger the Asset Observer and would log an asset *update* log entry (because the

View File

@@ -525,21 +525,31 @@ class BulkAssetsController extends Controller
$this->authorize('delete', Asset::class);
$bulk_back_url = route('hardware.index');
if ($request->session()->has('bulk_back_url')) {
$bulk_back_url = $request->session()->pull('bulk_back_url');
}
$assetIds = $request->get('ids');
if ($request->filled('ids')) {
$assets = Asset::find($request->get('ids'));
foreach ($assets as $asset) {
$asset->delete();
} // endforeach
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
// no values given, nothing to update
if(empty($assetIds)) {
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.delete.nothing_updated'));
}
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.delete.nothing_updated'));
$assignedAssets = Asset::whereIn('id', $assetIds)->whereNotNull('assigned_to')->get();
if($assignedAssets->isNotEmpty()) {
//if assets are checked out, return a list of asset tags that would need to be checked in first.
$assetTags = $assignedAssets->pluck('asset_tag')->implode(', ');
return redirect($bulk_back_url)->with('error', trans_choice('admin/hardware/message.delete.assigned_to_error', $assignedAssets->count(), ['asset_tag' => $assetTags] ));
}
foreach (Asset::wherein('id', $assetIds)->get() as $asset) {
$asset->delete();
}
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
// no values given, nothing to update
}
/**

View File

@@ -69,6 +69,7 @@ class CategoriesController extends Controller
$category->use_default_eula = $request->input('use_default_eula', '0');
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$category->notes = $request->input('notes');
$category->created_by = auth()->id();
$category = $request->handleImages($category);
@@ -87,14 +88,10 @@ class CategoriesController extends Controller
* @param int $categoryId
* @since [v1.0]
*/
public function edit($categoryId = null) : RedirectResponse | View
public function edit(Category $category) : RedirectResponse | View
{
$this->authorize('update', Category::class);
if (is_null($item = Category::find($categoryId))) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
}
return view('categories/edit', compact('item'))
return view('categories/edit')->with('item', $category)
->with('category_types', Helper::categoryTypeList());
}
@@ -107,19 +104,10 @@ class CategoriesController extends Controller
* @param int $categoryId
* @since [v1.0]
*/
public function update(ImageUploadRequest $request, $categoryId = null) : RedirectResponse
public function update(ImageUploadRequest $request, Category $category) : RedirectResponse
{
$this->authorize('update', Category::class);
if (is_null($category = Category::find($categoryId))) {
// Redirect to the categories management page
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
}
// Update the category data
$category->name = $request->input('name');
// If the item count is > 0, we disable the category type in the edit. Disabled items
// don't POST, so if the category_type is blank we just set it to the default.
// Don't allow the user to change the category_type once it's been created
if (($request->filled('category_type') && ($category->itemCount() > 0))) {
@@ -134,6 +122,7 @@ class CategoriesController extends Controller
$category->use_default_eula = $request->input('use_default_eula', '0');
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$category->notes = $request->input('notes');
$category = $request->handleImages($category);
@@ -179,10 +168,10 @@ class CategoriesController extends Controller
* @param $id
* @since [v1.8]
*/
public function show($id) : View | RedirectResponse
public function show(Category $category) : View | RedirectResponse
{
$this->authorize('view', Category::class);
if ($category = Category::find($id)) {
if ($category->category_type == 'asset') {
$category_type = 'hardware';
$category_type_route = 'assets';
@@ -197,8 +186,5 @@ class CategoriesController extends Controller
return view('categories/view', compact('category'))
->with('category_type', $category_type)
->with('category_type_route', $category_type_route);
}
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
}
}

View File

@@ -60,6 +60,7 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone');
$company->fax = $request->input('fax');
$company->email = $request->input('email');
$company->notes = $request->input('notes');
$company->created_by = auth()->id();
$company = $request->handleImages($company);
@@ -79,16 +80,10 @@ final class CompaniesController extends Controller
* @since [v1.8]
* @param int $companyId
*/
public function edit($companyId) : View | RedirectResponse
public function edit(Company $company) : View | RedirectResponse
{
if (is_null($item = Company::find($companyId))) {
return redirect()->route('companies.index')
->with('error', trans('admin/companies/message.does_not_exist'));
}
$this->authorize('update', $item);
return view('companies/edit')->with('item', $item);
$this->authorize('update', $company);
return view('companies/edit')->with('item', $company);
}
/**
@@ -99,18 +94,15 @@ final class CompaniesController extends Controller
* @param ImageUploadRequest $request
* @param int $companyId
*/
public function update(ImageUploadRequest $request, $companyId) : RedirectResponse
public function update(ImageUploadRequest $request, Company $company) : RedirectResponse
{
if (is_null($company = Company::find($companyId))) {
return redirect()->route('companies.index')->with('error', trans('admin/companies/message.does_not_exist'));
}
$this->authorize('update', $company);
$company->name = $request->input('name');
$company->phone = $request->input('phone');
$company->fax = $request->input('fax');
$company->email = $request->input('email');
$company->notes = $request->input('notes');
$company = $request->handleImages($company);
@@ -156,15 +148,9 @@ final class CompaniesController extends Controller
->with('success', trans('admin/companies/message.delete.success'));
}
public function show($id) : View | RedirectResponse
public function show(Company $company) : View | RedirectResponse
{
$this->authorize('view', Company::class);
if (is_null($company = Company::find($id))) {
return redirect()->route('companies.index')
->with('error', trans('admin/companies/message.not_found'));
}
return view('companies/view')->with('company', $company);
}
}

View File

@@ -107,15 +107,13 @@ class ComponentsController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($componentId = null)
public function edit(Component $component)
{
if ($item = Component::find($componentId)) {
$this->authorize('update', $item);
return view('components/edit', compact('item'))->with('category_type', 'component');
}
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
$this->authorize('update', $component);
return view('components/edit')
->with('item', $component)
->with('category_type', 'component');
}
@@ -130,11 +128,8 @@ class ComponentsController extends Controller
* @throws \Illuminate\Auth\Access\AuthorizationException
* @since [v3.0]
*/
public function update(ImageUploadRequest $request, $componentId = null)
public function update(ImageUploadRequest $request, Component $component)
{
if (is_null($component = Component::find($componentId))) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
}
$min = $component->numCheckedOut();
$validator = Validator::make($request->all(), [
'qty' => "required|numeric|min:$min",
@@ -201,6 +196,10 @@ class ComponentsController extends Controller
}
}
if ($component->numCheckedOut() > 0) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.delete.error_qty'));
}
$component->delete();
return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success'));
@@ -216,17 +215,9 @@ class ComponentsController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($componentId = null)
public function show(Component $component)
{
$component = Component::find($componentId);
if (isset($component->id)) {
$this->authorize('view', $component);
return view('components/view', compact('component'));
}
// Redirect to the user management page
return redirect()->route('components.index')
->with('error', trans('admin/components/message.does_not_exist'));
}
}

View File

@@ -104,15 +104,13 @@ class ConsumablesController extends Controller
* @see ConsumablesController::postEdit() method that stores the form data.
* @since [v1.0]
*/
public function edit($consumableId = null) : View | RedirectResponse
public function edit(Consumable $consumable) : View | RedirectResponse
{
if ($item = Consumable::find($consumableId)) {
$this->authorize($item);
$this->authorize($consumable);
return view('consumables/edit')
->with('item', $consumable)
->with('category_type', 'consumable');
return view('consumables/edit', compact('item'))->with('category_type', 'consumable');
}
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
/**
@@ -126,11 +124,8 @@ class ConsumablesController extends Controller
* @see ConsumablesController::getEdit() method that stores the form data.
* @since [v1.0]
*/
public function update(StoreConsumableRequest $request, $consumableId = null)
public function update(StoreConsumableRequest $request, Consumable $consumable)
{
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
$min = $consumable->numCheckedOut();
$validator = Validator::make($request->all(), [
@@ -202,16 +197,11 @@ class ConsumablesController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($consumableId = null)
public function show(Consumable $consumable)
{
$consumable = Consumable::withCount('users as users_consumables')->find($consumableId);
$consumable = Consumable::withCount('users as users_consumables')->find($consumable->id);
$this->authorize($consumable);
if (isset($consumable->id)) {
return view('consumables/view', compact('consumable'));
}
return redirect()->route('consumables.index')
->with('error', trans('admin/consumables/message.does_not_exist'));
return view('consumables/view', compact('consumable'));
}
public function clone(Consumable $consumable) : View

View File

@@ -104,6 +104,8 @@ class CustomFieldsController extends Controller
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
"show_in_listview" => $request->get("show_in_listview", 0),
"show_in_requestable_list" => $request->get("show_in_requestable_list", 0),
"display_checkin" => $request->get("display_checkin", 0),
"display_checkout" => $request->get("display_checkout", 0),
"created_by" => auth()->id()
]);
@@ -193,10 +195,8 @@ class CustomFieldsController extends Controller
* @param int $id
* @since [v4.0]
*/
public function edit(Request $request, $id) : View | RedirectResponse
public function edit(Request $request, CustomField $field) : View | RedirectResponse
{
if ($field = CustomField::find($id)) {
$this->authorize('update', $field);
$fieldsets = CustomFieldset::get();
$customFormat = '';
@@ -210,11 +210,7 @@ class CustomFieldsController extends Controller
'fieldsets' => $fieldsets,
'predefinedFormats' => Helper::predefined_formats(),
]);
}
return redirect()->route("fields.index")
->with("error", trans('admin/custom_fields/message.field.invalid'));
}
@@ -229,13 +225,9 @@ class CustomFieldsController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(CustomFieldRequest $request, $id) : RedirectResponse
public function update(CustomFieldRequest $request, CustomField $field) : RedirectResponse
{
$field = CustomField::find($id);
$this->authorize('update', $field);
$show_in_email = $request->get("show_in_email", 0);
$display_in_user_view = $request->get("display_in_user_view", 0);
@@ -256,6 +248,8 @@ class CustomFieldsController extends Controller
$field->auto_add_to_fieldsets = $request->get("auto_add_to_fieldsets", 0);
$field->show_in_listview = $request->get("show_in_listview", 0);
$field->show_in_requestable_list = $request->get("show_in_requestable_list", 0);
$field->display_checkin = $request->get("display_checkin", 0);
$field->display_checkout = $request->get("display_checkout", 0);
if ($request->get('format') == 'CUSTOM REGEX') {
$field->format = e($request->get('custom_format'));

View File

@@ -35,10 +35,12 @@ class CustomFieldsetsController extends Controller
* @param int $id
* @since [v1.8]
*/
public function show($id) : View | RedirectResponse
public function show(CustomFieldset $fieldset) : View | RedirectResponse
{
$cfset = CustomFieldset::with('fields')
->where('id', '=', $id)->orderBy('id', 'ASC')->first();
->where('id', '=', $fieldset->id)
->orderBy('id', 'ASC')
->first();
$this->authorize('view', $cfset);
@@ -122,16 +124,10 @@ class CustomFieldsetsController extends Controller
* @param int $id
* @since [v6.0.14]
*/
public function edit($id) : View | RedirectResponse
public function edit(CustomFieldset $fieldset) : View | RedirectResponse
{
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
return view('custom_fields.fieldsets.edit')->with('item', $fieldset);
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
return view('custom_fields.fieldsets.edit')->with('item', $fieldset);
}
/**
@@ -141,23 +137,18 @@ class CustomFieldsetsController extends Controller
* @param int $id
* @since [v6.0.14]
*/
public function update(Request $request, $id) : RedirectResponse
public function update(Request $request, CustomFieldset $fieldset) : RedirectResponse
{
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
$fieldset->name = $request->input('name');
if ($fieldset->save()) {
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/general.fieldset_updated'));
}
return redirect()->back()->withInput()->withErrors($fieldset->getErrors());
$fieldset->name = $request->input('name');
if ($fieldset->save()) {
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/general.fieldset_updated'));
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
return redirect()->back()->withInput()->withErrors($fieldset->getErrors());
}
/**

View File

@@ -55,6 +55,7 @@ class DepartmentsController extends Controller
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
$department->location_id = ($request->filled('location_id') ? $request->input('location_id') : null);
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
$department->notes = $request->input('notes');
$department = $request->handleImages($department);
if ($department->save()) {
@@ -72,17 +73,10 @@ class DepartmentsController extends Controller
* @param int $id
* @since [v4.0]
*/
public function show($id) : View | RedirectResponse
public function show(Department $department) : View | RedirectResponse
{
$department = Department::find($id);
$this->authorize('view', $department);
if (isset($department->id)) {
return view('departments/view', compact('department'));
}
return redirect()->route('departments.index')->with('error', trans('admin/departments/message.does_not_exist'));
return view('departments/view', compact('department'));
}
/**
@@ -138,15 +132,10 @@ class DepartmentsController extends Controller
* @param int $departmentId
* @since [v1.0]
*/
public function edit($departmentId = null) : View | RedirectResponse
public function edit(Department $department) : View | RedirectResponse
{
if (is_null($item = Department::find($departmentId))) {
return redirect()->back()->with('error', trans('admin/locations/message.does_not_exist'));
}
$this->authorize('update', $item);
return view('departments/edit', compact('item'));
$this->authorize('update', $department);
return view('departments/edit')->with('item', $department);
}
/**
@@ -157,11 +146,8 @@ class DepartmentsController extends Controller
* @param int $departmentId
* @since [v1.0]
*/
public function update(ImageUploadRequest $request, $id) : RedirectResponse
public function update(ImageUploadRequest $request, Department $department) : RedirectResponse
{
if (is_null($department = Department::find($id))) {
return redirect()->route('departments.index')->with('error', trans('admin/departments/message.does_not_exist'));
}
$this->authorize('update', $department);
@@ -171,7 +157,7 @@ class DepartmentsController extends Controller
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
$department->phone = $request->input('phone');
$department->fax = $request->input('fax');
$department->notes = $request->input('notes');
$department = $request->handleImages($department);
if ($department->save()) {

View File

@@ -95,17 +95,11 @@ class DepreciationsController extends Controller
* @param int $depreciationId
* @since [v1.0]
*/
public function edit($depreciationId = null) : RedirectResponse | View
public function edit(Depreciation $depreciation) : RedirectResponse | View
{
// Check if the depreciation exists
if (is_null($item = Depreciation::find($depreciationId))) {
// Redirect to the blogs management page
return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
$this->authorize('update', $item);
return view('depreciations/edit', compact('item'));
$this->authorize('update', $depreciation);
return view('depreciations/edit')->with('item', $depreciation);
}
/**
@@ -117,17 +111,10 @@ class DepreciationsController extends Controller
* @param int $depreciationId
* @since [v1.0]
*/
public function update(Request $request, $depreciationId = null) : RedirectResponse
public function update(Request $request, Depreciation $depreciation) : RedirectResponse
{
// Check if the depreciation exists
if (is_null($depreciation = Depreciation::find($depreciationId))) {
// Redirect to the blogs management page
return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
$this->authorize('update', $depreciation);
// Depreciation data
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
@@ -191,12 +178,12 @@ class DepreciationsController extends Controller
* @param int $depreciationId
* @since [v1.0]
*/
public function show($id) : View | RedirectResponse
public function show(Depreciation $depreciation) : View | RedirectResponse
{
$depreciation = Depreciation::withCount('assets as assets_count')
->withCount('models as models_count')
->withCount('licenses as licenses_count')
->find($id);
->find($depreciation->id);
$this->authorize('view', $depreciation);

View File

@@ -62,6 +62,7 @@ class GroupsController extends Controller
$group->name = $request->input('name');
$group->permissions = json_encode($request->input('permission'));
$group->created_by = auth()->id();
$group->notes = $request->input('notes');
if ($group->save()) {
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
@@ -78,19 +79,12 @@ class GroupsController extends Controller
* @param int $id
* @since [v1.0]
*/
public function edit($id) : View | RedirectResponse
public function edit(Group $group) : View | RedirectResponse
{
$group = Group::find($id);
if ($group) {
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
/**
@@ -101,13 +95,11 @@ class GroupsController extends Controller
* @param int $id
* @since [v1.0]
*/
public function update(Request $request, $id = null) : RedirectResponse
public function update(Request $request, Group $group) : RedirectResponse
{
if (! $group = Group::find($id)) {
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
}
$group->name = $request->input('name');
$group->permissions = json_encode($request->input('permission'));
$group->notes = $request->input('notes');
if (! config('app.lock_passwords')) {
if ($group->save()) {
@@ -149,14 +141,8 @@ class GroupsController extends Controller
* @param $id
* @since [v4.0.11]
*/
public function show($id) : View | RedirectResponse
public function show(Group $group) : View | RedirectResponse
{
$group = Group::find($id);
if ($group) {
return view('groups/view', compact('group'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
return view('groups/view', compact('group'));
}
}

View File

@@ -4,10 +4,8 @@ namespace App\Http\Controllers\Kits;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Models\PredefinedKit;
use App\Models\Asset;
use App\Models\PredefinedLicence;
use App\Models\PredefinedModel;
use App\Models\PredefinedKit;
use App\Models\User;
use App\Services\PredefinedKitCheckoutService;
use Illuminate\Http\Request;
@@ -35,12 +33,9 @@ class CheckoutKitController extends Controller
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
* @return \Illuminate\Contracts\View\View View to checkout
*/
public function showCheckout($kit_id)
public function showCheckout(PredefinedKit $kit)
{
$this->authorize('checkout', Asset::class);
$kit = PredefinedKit::findOrFail($kit_id);
return view('kits/checkout')->with('kit', $kit);
}

View File

@@ -76,17 +76,15 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Contracts\View\View
*/
public function edit($kit_id = null)
public function edit(PredefinedKit $kit)
{
$this->authorize('update', PredefinedKit::class);
if ($kit = PredefinedKit::find($kit_id)) {
return view('kits/edit')
->with('item', $kit)
->with('models', $kit->models)
->with('licenses', $kit->licenses);
}
return redirect()->route('kits.index')->with('error', trans('admin/kits/general.kit_none'));
}
/**
@@ -98,15 +96,9 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Http\RedirectResponse
*/
public function update(ImageUploadRequest $request, $kit_id = null)
public function update(ImageUploadRequest $request, PredefinedKit $kit)
{
$this->authorize('update', PredefinedKit::class);
// Check if the kit exists
if (is_null($kit = PredefinedKit::find($kit_id))) {
// Redirect to the kits management page
return redirect()->route('kits.index')->with('error', trans('admin/kits/general.kit_none'));
}
$kit->name = $request->input('name');
if ($kit->save()) {
@@ -153,9 +145,9 @@ class PredefinedKitsController extends Controller
* @param int $modelId
* @return \Illuminate\Contracts\View\View
*/
public function show($kit_id = null)
public function show(PredefinedKit $kit)
{
return $this->edit($kit_id);
return $this->edit($kit);
}
/**

View File

@@ -28,16 +28,11 @@ class LicenseCheckinController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create($seatId = null, $backTo = null)
public function create(LicenseSeat $licenseSeat, $backTo = null)
{
// Check if the asset exists
if (is_null($licenseSeat = LicenseSeat::find($seatId)) || is_null($license = License::find($licenseSeat->license_id))) {
// Redirect to the asset management page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}
$license = License::find($licenseSeat->license_id);
$this->authorize('checkout', $license);
return view('licenses/checkin', compact('licenseSeat'))->with('backto', $backTo);
}

View File

@@ -28,33 +28,24 @@ class LicenseCheckoutController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create($id)
public function create(License $license)
{
$this->authorize('checkout', $license);
if ($license = License::find($id)) {
if ($license->category) {
$this->authorize('checkout', $license);
if ($license->category) {
// Make sure there is at least one available to checkout
if ($license->availCount()->count() < 1){
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}
// Return the checkout view
return view('licenses/checkout', compact('license'));
// Make sure there is at least one available to checkout
if ($license->availCount()->count() < 1) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}
// Invalid category
return redirect()->route('licenses.edit', ['license' => $license->id])
->with('error', trans('general.invalid_item_category_single', ['type' => trans('general.license')]));
// Return the checkout view
return view('licenses/checkout', compact('license'));
}
// Not found
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
// Invalid category
return redirect()->route('licenses.edit', ['license' => $license->id])
->with('error', trans('general.invalid_item_category_single', ['type' => trans('general.license')]));
}

View File

@@ -121,13 +121,10 @@ class LicensesController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($licenseId = null)
public function edit(License $license)
{
if (is_null($item = License::find($licenseId))) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));
}
$this->authorize('update', $item);
$this->authorize('update', $license);
$maintained_list = [
'' => 'Maintained',
@@ -135,7 +132,8 @@ class LicensesController extends Controller
'0' => 'No',
];
return view('licenses/edit', compact('item'))
return view('licenses/edit')
->with('item', $license)
->with('depreciation_list', Helper::depreciationList())
->with('maintained_list', $maintained_list);
}
@@ -153,11 +151,9 @@ class LicensesController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, $licenseId = null)
public function update(Request $request, License $license)
{
if (is_null($license = License::find($licenseId))) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));
}
$this->authorize('update', $license);
@@ -201,10 +197,10 @@ class LicensesController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy($licenseId)
public function destroy(License $license)
{
// Check if the license exists
if (is_null($license = License::find($licenseId))) {
if (is_null($license = License::find($license->id))) {
// Redirect to the license management page
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}
@@ -238,14 +234,9 @@ class LicensesController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($licenseId = null)
public function show(License $license)
{
$license = License::with('assignedusers')->find($licenseId);
if (!$license) {
return redirect()->route('licenses.index')
->with('error', trans('admin/licenses/message.does_not_exist'));
}
$license = License::with('assignedusers')->find($license->id);
$users_count = User::where('autoassign_licenses', '1')->count();
$total_seats_count = $license->totalSeatsByLicenseID();
@@ -267,10 +258,10 @@ class LicensesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $licenseId
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\RedirectResponse | \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function getClone($licenseId = null)
public function getClone($licenseId = null) : \Illuminate\Contracts\View\View | \Illuminate\Http\RedirectResponse
{
if (is_null($license_to_clone = License::find($licenseId))) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));

View File

@@ -78,6 +78,7 @@ class LocationsController extends Controller
$location->created_by = auth()->id();
$location->phone = request('phone');
$location->fax = request('fax');
$location->notes = $request->input('notes');
$location = $request->handleImages($location);
@@ -96,15 +97,10 @@ class LocationsController extends Controller
* @param int $locationId
* @since [v1.0]
*/
public function edit($locationId = null) : View | RedirectResponse
public function edit(Location $location) : View | RedirectResponse
{
$this->authorize('update', Location::class);
// Check if the location exists
if (is_null($item = Location::find($locationId))) {
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
return view('locations/edit', compact('item'));
return view('locations/edit')->with('item', $location);
}
/**
@@ -116,15 +112,10 @@ class LocationsController extends Controller
* @param int $locationId
* @since [v1.0]
*/
public function update(ImageUploadRequest $request, $locationId = null) : RedirectResponse
public function update(ImageUploadRequest $request, Location $location) : RedirectResponse
{
$this->authorize('update', Location::class);
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
// Update the location data
$location->name = $request->input('name');
$location->parent_id = $request->input('parent_id', null);
$location->currency = $request->input('currency', '$');
@@ -138,6 +129,7 @@ class LocationsController extends Controller
$location->fax = request('fax');
$location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id');
$location->notes = $request->input('notes');
$location = $request->handleImages($location);
@@ -192,7 +184,7 @@ class LocationsController extends Controller
* @param int $id
* @since [v1.0]
*/
public function show($id = null) : View | RedirectResponse
public function show(Location $location) : View | RedirectResponse
{
$location = Location::withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
@@ -200,7 +192,7 @@ class LocationsController extends Controller
->withCount('children as children_count')
->withCount('users as users_count')
->withTrashed()
->find($id);
->find($location->id);
if (isset($location->id)) {
return view('locations/view', compact('location'));

View File

@@ -67,6 +67,7 @@ class ManufacturersController extends Controller
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
$manufacturer->support_phone = $request->input('support_phone');
$manufacturer->support_email = $request->input('support_email');
$manufacturer->notes = $request->input('notes');
$manufacturer = $request->handleImages($manufacturer);
if ($manufacturer->save()) {
@@ -84,18 +85,10 @@ class ManufacturersController extends Controller
* @param int $manufacturerId
* @since [v1.0]
*/
public function edit($manufacturerId = null) : View | RedirectResponse
public function edit(Manufacturer $manufacturer) : View | RedirectResponse
{
// Handles manufacturer checks and permissions.
$this->authorize('update', Manufacturer::class);
// Check if the manufacturer exists
if (! $item = Manufacturer::find($manufacturerId)) {
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist'));
}
// Show the page
return view('manufacturers/edit', compact('item'));
return view('manufacturers/edit')->with('item', $manufacturer);
}
/**
@@ -107,22 +100,17 @@ class ManufacturersController extends Controller
* @param int $manufacturerId
* @since [v1.0]
*/
public function update(ImageUploadRequest $request, $manufacturerId = null) : RedirectResponse
public function update(ImageUploadRequest $request, Manufacturer $manufacturer) : RedirectResponse
{
$this->authorize('update', Manufacturer::class);
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturer page
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist'));
}
// Save the data
$manufacturer->name = $request->input('name');
$manufacturer->url = $request->input('url');
$manufacturer->support_url = $request->input('support_url');
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
$manufacturer->support_phone = $request->input('support_phone');
$manufacturer->support_email = $request->input('support_email');
$manufacturer->notes = $request->input('notes');
// Set the model's image property to null if the image is being deleted
if ($request->input('image_delete') == 1) {
@@ -183,18 +171,10 @@ class ManufacturersController extends Controller
* @param int $manufacturerId
* @since [v1.0]
*/
public function show($manufacturerId = null) : View | RedirectResponse
public function show(Manufacturer $manufacturer) : View | RedirectResponse
{
$this->authorize('view', Manufacturer::class);
$manufacturer = Manufacturer::find($manufacturerId);
if (isset($manufacturer->id)) {
return view('manufacturers/view', compact('manufacturer'));
}
$error = trans('admin/manufacturers/message.does_not_exist');
// Redirect to the user management page
return redirect()->route('manufacturers.index')->with('error', $error);
return view('manufacturers/view', compact('manufacturer'));
}
/**

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Http\Controllers;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class NotesController extends Controller
{
public function store(Request $request)
{
$this->authorize('update', Asset::class);
$validated = $request->validate([
'id' => 'required',
'note' => 'required|string|max:50000',
'type' => [
'required',
Rule::in(['asset']),
],
]);
$item = Asset::findOrFail($validated['id']);
$this->authorize('update', $item);
$logaction = new Actionlog;
$logaction->item_id = $item->id;
$logaction->item_type = get_class($item);
$logaction->note = $validated['note'];
$logaction->created_by = Auth::id();
$logaction->logaction('note added');
return redirect()
->route('hardware.show', $validated['id'])
->withFragment('history')
->with('success', trans('general.note_added'));
}
}

View File

@@ -800,6 +800,7 @@ class SettingsController extends Controller
}
if ($setting->save()) {
return redirect()->route('settings.labels.index')
->with('success', trans('admin/settings/message.update.success'));
}
@@ -869,7 +870,6 @@ class SettingsController extends Controller
}
if ($setting->save()) {
$setting->update_client_side_cert_files();
return redirect()->route('settings.ldap.index')
->with('success', trans('admin/settings/message.update.success'));
}

View File

@@ -26,14 +26,10 @@ class StatuslabelsController extends Controller
return view('statuslabels.index');
}
public function show($id) : View | RedirectResponse
public function show(Statuslabel $statuslabel) : View | RedirectResponse
{
$this->authorize('view', Statuslabel::class);
if ($statuslabel = Statuslabel::find($id)) {
return view('statuslabels.view')->with('statuslabel', $statuslabel);
}
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
return view('statuslabels.view')->with('statuslabel', $statuslabel);
}
/**
@@ -91,20 +87,15 @@ class StatuslabelsController extends Controller
*
* @param int $statuslabelId
*/
public function edit($statuslabelId = null) : View | RedirectResponse
public function edit(Statuslabel $statuslabel) : View | RedirectResponse
{
$this->authorize('update', Statuslabel::class);
// Check if the Statuslabel exists
if (is_null($item = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
$use_statuslabel_type = $item->getStatuslabelType();
$statuslabel_types = ['' => trans('admin/hardware/form.select_statustype')] + ['undeployable' => trans('admin/hardware/general.undeployable')] + ['pending' => trans('admin/hardware/general.pending')] + ['archived' => trans('admin/hardware/general.archived')] + ['deployable' => trans('admin/hardware/general.deployable')];
return view('statuslabels/edit', compact('item', 'statuslabel_types'))->with('use_statuslabel_type', $use_statuslabel_type);
return view('statuslabels/edit', compact('statuslabel_types'))
->with('item', $statuslabel)
->with('use_statuslabel_type', $statuslabel);
}
/**
@@ -112,14 +103,9 @@ class StatuslabelsController extends Controller
*
* @param int $statuslabelId
*/
public function update(Request $request, $statuslabelId = null) : RedirectResponse
public function update(Request $request, Statuslabel $statuslabel) : RedirectResponse
{
$this->authorize('update', Statuslabel::class);
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
if (! $request->filled('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);

View File

@@ -77,17 +77,10 @@ class SuppliersController extends Controller
*
* @param int $supplierId
*/
public function edit($supplierId = null) : View | RedirectResponse
public function edit(Supplier $supplier) : View | RedirectResponse
{
$this->authorize('update', Supplier::class);
// Check if the supplier exists
if (is_null($item = Supplier::find($supplierId))) {
// Redirect to the supplier page
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.does_not_exist'));
}
// Show the page
return view('suppliers/edit', compact('item'));
return view('suppliers/edit')->with('item', $supplier);
}
/**
@@ -95,14 +88,9 @@ class SuppliersController extends Controller
*
* @param int $supplierId
*/
public function update($supplierId, ImageUploadRequest $request) : RedirectResponse
public function update(ImageUploadRequest $request, Supplier $supplier) : RedirectResponse
{
$this->authorize('update', Supplier::class);
if (is_null($supplier = Supplier::find($supplierId))) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.does_not_exist'));
}
// Save the data
$supplier->name = request('name');
$supplier->address = request('address');
@@ -163,15 +151,10 @@ class SuppliersController extends Controller
* @param null $supplierId
* @internal param int $assetId
*/
public function show($supplierId = null) : View | RedirectResponse
public function show(Supplier $supplier) : View | RedirectResponse
{
$this->authorize('view', Supplier::class);
$supplier = Supplier::find($supplierId);
return view('suppliers/view', compact('supplier'));
if (isset($supplier->id)) {
return view('suppliers/view', compact('supplier'));
}
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.does_not_exist'));
}
}

View File

@@ -15,6 +15,7 @@ use App\Models\ConsumableAssignment;
use App\Models\Consumable;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\CurrentInventory;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@@ -52,6 +53,28 @@ class BulkUsersController extends Controller
return view('users/bulk-edit', compact('users'))
->with('groups', Group::pluck('name', 'id'));
// bulk send assigned inventory
} elseif ($request->input('bulk_actions') == 'send_assigned') {
$this->authorize('update', User::class);
$users_without_email = 0;
foreach ($users as $user) {
if (empty($user->email)) {
$users_without_email++;
} else {
$user->notify((new CurrentInventory($user)));
}
}
if ($users_without_email == 0) {
return redirect()->back()->with('success', trans_choice('admin/users/general.users_notified', $users->count()));
} else {
return redirect()->back()->with('warning', trans_choice('admin/users/general.users_notified_warning', $users->count(), ['no_email' => $users_without_email]));
}
// bulk delete, display the bulk delete confirmation form
} elseif ($request->input('bulk_actions') == 'delete') {
$this->authorize('delete', User::class);

View File

@@ -22,43 +22,34 @@ class UserFilesController extends Controller
*@author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.6]
*/
public function store(UploadFileRequest $request, $userId = null)
public function store(UploadFileRequest $request, User $user)
{
$user = User::find($userId);
$destinationPath = config('app.private_uploads').'/users';
$this->authorize('update', $user);
$files = $request->file('file');
if (isset($user->id)) {
$this->authorize('update', $user);
$logActions = [];
$files = $request->file('file');
if (is_null($files)) {
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
}
foreach ($files as $file) {
$file_name = $request->handleFile('private_uploads/users/', 'user-'.$user->id, $file);
//Log the uploaded file to the log
$logAction = new Actionlog();
$logAction->item_id = $user->id;
$logAction->item_type = User::class;
$logAction->created_by = auth()->id();
$logAction->note = $request->input('notes');
$logAction->target_id = null;
$logAction->created_at = date("Y-m-d H:i:s");
$logAction->filename = $file_name;
$logAction->action_type = 'uploaded';
if (! $logAction->save()) {
return JsonResponse::create(['error' => 'Failed validation: '.print_r($logAction->getErrors(), true)], 500);
}
$logActions[] = $logAction;
}
// dd($logActions);
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.upload.success'));
if (is_null($files)) {
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
}
foreach ($files as $file) {
$file_name = $request->handleFile('private_uploads/users/', 'user-'.$user->id, $file);
//Log the uploaded file to the log
$logAction = new Actionlog();
$logAction->item_id = $user->id;
$logAction->item_type = User::class;
$logAction->created_by = auth()->id();
$logAction->note = $request->input('notes');
$logAction->target_id = null;
$logAction->created_at = date("Y-m-d H:i:s");
$logAction->filename = $file_name;
$logAction->action_type = 'uploaded';
if (! $logAction->save()) {
return JsonResponse::create(['error' => 'Failed validation: '.print_r($logAction->getErrors(), true)], 500);
}
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.upload.success'));
}
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
}
@@ -110,7 +101,7 @@ class UserFilesController extends Controller
* @return mixed
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($userId = null, $fileId = null)
public function show(User $user, $fileId = null)
{
@@ -118,29 +109,21 @@ class UserFilesController extends Controller
return redirect()->route('users.show')->with('error', 'Invalid file request');
}
if ($user = User::find($userId)) {
$this->authorize('view', $user);
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
$file = 'private_uploads/users/'.$log->filename;
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
$file = 'private_uploads/users/'.$log->filename;
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.file_not_found'));
}
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.file_not_found'));
}
// The log record doesn't exist somehow
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.log_record_not_found'));
return redirect()->back()->with('error', trans('general.file_not_found'));
}
// Redirect to the user management page if the user doesn't exist
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', ['id' => $userId]));
// The log record doesn't exist somehow
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.log_record_not_found'));
}
}

View File

@@ -182,11 +182,11 @@ class UsersController extends Controller
* @internal param int $id
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($id)
public function edit(User $user)
{
$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($user->id);
if ($user) {
@@ -198,7 +198,7 @@ class UsersController extends Controller
$userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions);
$permissions = $this->filterDisplayable($permissions);
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user);
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'));
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
@@ -324,7 +324,7 @@ class UsersController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy(DeleteUserRequest $request, $id = null)
public function destroy(DeleteUserRequest $request, $id)
{
$this->authorize('delete', User::class);
@@ -333,13 +333,6 @@ class UsersController extends Controller
$this->authorize('delete', $user);
if ($user->delete()) {
if (Storage::disk('public')->exists('avatars/' . $user->avatar)) {
try {
Storage::disk('public')->delete('avatars/' . $user->avatar);
} catch (\Exception $e) {
Log::debug($e);
}
}
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.delete'));
}
}
@@ -398,23 +391,18 @@ class UsersController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($userId = null)
public function show(User $user)
{
// Make sure the user can view users at all
$this->authorize('view', User::class);
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($userId);
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($user->id);
// Make sure they can view this particular user
$this->authorize('view', $user);
if ($user) {
$userlog = $user->userlog->load('item');
return view('users/view', compact('user', 'userlog'))->with('settings', Setting::getSettings());
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', ['id' => $userId]));
}
@@ -428,7 +416,7 @@ class UsersController extends Controller
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function getClone(Request $request, $id = null)
public function getClone(Request $request, User $user)
{
$this->authorize('create', User::class);
@@ -438,7 +426,7 @@ class UsersController extends Controller
app('request')->request->set('permissions', $permissions);
$user_to_clone = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id);
$user_to_clone = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($user->id);
// Make sure they can view this particular user
$this->authorize('view', $user_to_clone);

View File

@@ -24,7 +24,7 @@ class DeleteUserRequest extends FormRequest
public function prepareForValidation(): void
{
$user_to_delete = User::withTrashed()->find(request()->route('user'));
$user_to_delete = User::withTrashed()->with('managesUsers')->find(request()->route('user'));
if ($user_to_delete) {
$this->merge([
@@ -61,7 +61,8 @@ class DeleteUserRequest extends FormRequest
public function messages(): array
{
$user_to_delete = User::withTrashed()->find(request()->route('user'));
$user_to_delete = User::withTrashed()->with('managesUsers')->find(request()->route('user'));
$messages = [];
if ($user_to_delete) {

View File

@@ -62,7 +62,7 @@ class SettingsSamlRequest extends FormRequest
$custom_privateKey = '';
$custom_x509certNew = '';
if (! empty($this->input('saml_custom_settings'))) {
$req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings'));
$req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings', ''));
$custom_settings = [];
foreach ($req_custom_settings as $custom_setting) {

View File

@@ -2,8 +2,11 @@
namespace App\Http\Requests;
use App\Models\Labels\Label;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
class StoreLabelSettings extends FormRequest
{
@@ -22,6 +25,10 @@ class StoreLabelSettings extends FormRequest
*/
public function rules(): array
{
$names = Label::find()?->map(function ($label) {
return $label->getName();
})->values()->toArray();
return [
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
@@ -36,6 +43,10 @@ class StoreLabelSettings extends FormRequest
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'qr_text' => 'max:31|nullable',
'label2_template' => [
'required',
Rule::in($names),
],
];
}
}

View File

@@ -28,7 +28,7 @@ class StoreNotificationSettings extends FormRequest
'admin_cc_email' => 'email_array|nullable',
'alert_threshold' => 'numeric|nullable|gt:0',
'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable',
'due_checkin_days' => 'numeric|nullable|gt:0',
'audit_interval' => 'numeric|nullable|gt:0',
];

View File

@@ -140,13 +140,13 @@ class ActionlogsTransformer
} else {
if ($actionlog->item) {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
$file_url = route('show/assetfile', ['asset' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'accessory') {
$file_url = route('show.accessoryfile', ['accessoryId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'license') {
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'user') {
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
$file_url = route('show/userfile', ['user' => $actionlog->item->id, 'fileId' => $actionlog->id]);
}
}
}

View File

@@ -309,6 +309,7 @@ class AssetsTransformer
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,
],
'assigned_to' => $accessory_checkout->assigned_to,
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory_checkout->accessory->image)) : null,
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
'created_by' => $accessory_checkout->adminuser ? [

View File

@@ -66,6 +66,7 @@ class CategoriesTransformer
'id' => (int) $category->adminuser->id,
'name'=> e($category->adminuser->present()->fullName()),
] : null,
'notes' => Helper::parseEscapedMarkedownInline($category->notes),
'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'),
];

View File

@@ -40,6 +40,7 @@ class CompaniesTransformer
'id' => (int) $company->adminuser->id,
'name'=> e($company->adminuser->present()->fullName()),
] : null,
'notes' => Helper::parseEscapedMarkedownInline($company->notes),
'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
];

View File

@@ -62,7 +62,7 @@ class ComponentsTransformer
'checkout' => Gate::allows('checkout', Component::class),
'checkin' => Gate::allows('checkin', Component::class),
'update' => Gate::allows('update', Component::class),
'delete' => Gate::allows('delete', Component::class),
'delete' => $component->isDeletable(),
];
$array += $permissions_array;

View File

@@ -44,6 +44,7 @@ class DepartmentsTransformer
'name' => e($department->location->name),
] : null,
'users_count' => e($department->users_count),
'notes' => Helper::parseEscapedMarkedownInline($department->notes),
'created_at' => Helper::getFormattedDateObject($department->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($department->updated_at, 'datetime'),
];

View File

@@ -26,6 +26,7 @@ class GroupsTransformer
'name' => e($group->name),
'permissions' => json_decode($group->permissions),
'users_count' => (int) $group->users_count,
'notes' => Helper::parseEscapedMarkedownInline($group->notes),
'created_by' => ($group->adminuser) ? [
'id' => (int) $group->adminuser->id,
'name'=> e($group->adminuser->present()->fullName()),

View File

@@ -55,6 +55,7 @@ class LocationsTransformer
'users_count' => (int) $location->users_count,
'currency' => ($location->currency) ? e($location->currency) : null,
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
'parent' => ($location->parent) ? [
@@ -99,6 +100,7 @@ class LocationsTransformer
$array = [
'id' => $accessory_checkout->id,
'assigned_to' => $accessory_checkout->assigned_to,
'accessory' => [
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,

View File

@@ -37,6 +37,7 @@ class ManufacturersTransformer
'consumables_count' => (int) $manufacturer->consumables_count,
'accessories_count' => (int) $manufacturer->accessories_count,
'components_count' => (int) $manufacturer->components_count,
'notes' => Helper::parseEscapedMarkedownInline($manufacturer->notes),
'created_by' => ($manufacturer->adminuser) ? [
'id' => (int) $manufacturer->adminuser->id,
'name'=> e($manufacturer->adminuser->present()->fullName()),

View File

@@ -74,6 +74,8 @@ class LocationImporter extends ItemImporter
$this->item['ldap_ou'] = trim($this->findCsvMatch($row, 'ldap_ou'));
$this->item['manager'] = trim($this->findCsvMatch($row, 'manager'));
$this->item['manager_username'] = trim($this->findCsvMatch($row, 'manager_username'));
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
if ($this->findCsvMatch($row, 'parent_location')) {
$this->item['parent_id'] = $this->createOrFetchLocation(trim($this->findCsvMatch($row, 'parent_location')));

View File

@@ -1,81 +0,0 @@
<?php
namespace App\LegacyEncrypter;
use Illuminate\Contracts\Encryption\DecryptException;
abstract class BaseEncrypter
{
/**
* The encryption key.
*
* @var string
*/
protected $key;
/**
* Create a MAC for the given value.
*
* @param string $iv
* @param string $value
* @return string
*/
protected function hash($iv, $value)
{
return hash_hmac('sha256', $iv.$value, $this->key);
}
/**
* Get the JSON array from the given payload.
*
* @param string $payload
* @return array
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function getJsonPayload($payload)
{
$payload = json_decode(base64_decode($payload), true);
// If the payload is not valid JSON or does not have the proper keys set we will
// assume it is invalid and bail out of the routine since we will not be able
// to decrypt the given value. We'll also check the MAC for this encryption.
if (! $payload || $this->invalidPayload($payload)) {
throw new DecryptException('The payload is invalid.');
}
if (! $this->validMac($payload)) {
throw new DecryptException('The MAC is invalid.');
}
return $payload;
}
/**
* Verify that the encryption payload is valid.
*
* @param array|mixed $data
* @return bool
*/
protected function invalidPayload($data)
{
return ! is_array($data) || ! isset($data['iv']) || ! isset($data['value']) || ! isset($data['mac']);
}
/**
* Determine if the MAC for the given payload is valid.
*
* @param array $payload
* @return bool
*
* @throws \RuntimeException
*/
protected function validMac(array $payload)
{
$bytes = random_bytes(16);
$calcMac = hash_hmac('sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true);
return hash_equals(hash_hmac('sha256', $payload['mac'], $bytes, true), $calcMac);
}
}

View File

@@ -1,214 +0,0 @@
<?php
namespace App\LegacyEncrypter;
use Exception;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;
use Illuminate\Contracts\Encryption\EncryptException;
use RuntimeException;
/**
* @deprecated since version 5.1. Use Illuminate\Encryption\Encrypter.
*/
class McryptEncrypter extends BaseEncrypter implements EncrypterContract
{
/**
* The algorithm used for encryption.
*
* @var string
*/
protected $cipher;
/**
* The block size of the cipher.
*
* @var int
*/
protected $block;
/**
* Create a new encrypter instance.
*
* @param string $key
* @param string $cipher
* @return void
*
* @throws \RuntimeException
*/
public function __construct($key, $cipher = MCRYPT_RIJNDAEL_128)
{
$key = (string) $key;
if (static::supported($key, $cipher)) {
$this->key = $key;
$this->cipher = $cipher;
$this->block = mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
} else {
throw new RuntimeException('The only supported ciphers are MCRYPT_RIJNDAEL_128 and MCRYPT_RIJNDAEL_256.');
}
}
/**
* Determine if the given key and cipher combination is valid.
*
* @param string $key
* @param string $cipher
* @return bool
*/
public static function supported($key, $cipher)
{
return defined('MCRYPT_RIJNDAEL_128') &&
($cipher === MCRYPT_RIJNDAEL_128 || $cipher === MCRYPT_RIJNDAEL_256);
}
/**
* Encrypt the given value.
*
* @param string $value
* @return string
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function encrypt($value, $serialize = true)
{
$iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
$value = base64_encode($this->padAndMcrypt($value, $iv));
// Once we have the encrypted value we will go ahead base64_encode the input
// vector and create the MAC for the encrypted value so we can verify its
// authenticity. Then, we'll JSON encode the data in a "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
$json = json_encode(compact('iv', 'value', 'mac'));
if (! is_string($json)) {
throw new EncryptException('Could not encrypt the data.');
}
return base64_encode($json);
}
/**
* Pad and use mcrypt on the given value and input vector.
*
* @param string $value
* @param string $iv
* @return string
*/
protected function padAndMcrypt($value, $iv)
{
$value = $this->addPadding(serialize($value));
return mcrypt_encrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
}
/**
* Decrypt the given value.
*
* @param string $payload
* @return string
*/
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
// We'll go ahead and remove the PKCS7 padding from the encrypted value before
// we decrypt it. Once we have the de-padded value, we will grab the vector
// and decrypt the data, passing back the unserialized from of the value.
$value = base64_decode($payload['value']);
$iv = base64_decode($payload['iv']);
return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
}
/**
* Run the mcrypt decryption routine for the value.
*
* @param string $value
* @param string $iv
* @return string
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function mcryptDecrypt($value, $iv)
{
try {
return mcrypt_decrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
} catch (Exception $e) {
throw new DecryptException($e->getMessage());
}
}
/**
* Add PKCS7 padding to a given value.
*
* @param string $value
* @return string
*/
protected function addPadding($value)
{
$pad = $this->block - (strlen($value) % $this->block);
return $value.str_repeat(chr($pad), $pad);
}
/**
* Remove the padding from the given value.
*
* @param string $value
* @return string
*/
protected function stripPadding($value)
{
$pad = ord($value[($len = strlen($value)) - 1]);
return $this->paddingIsValid($pad, $value) ? substr($value, 0, $len - $pad) : $value;
}
/**
* Determine if the given padding for a value is valid.
*
* @param string $pad
* @param string $value
* @return bool
*/
protected function paddingIsValid($pad, $value)
{
$beforePad = strlen($value) - $pad;
return substr($value, $beforePad) == str_repeat(substr($value, -1), $pad);
}
/**
* Get the IV size for the cipher.
*
* @return int
*/
protected function getIvSize()
{
return mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
}
/**
* Get the random data source available for the OS.
*
* @return int
*/
protected function getRandomizer()
{
if (defined('MCRYPT_DEV_URANDOM')) {
return MCRYPT_DEV_URANDOM;
}
if (defined('MCRYPT_DEV_RANDOM')) {
return MCRYPT_DEV_RANDOM;
}
mt_srand();
return MCRYPT_RAND;
}
}

View File

@@ -106,7 +106,13 @@ class CheckoutableListener
}
}
} catch (ClientException $e) {
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
Log::warning(Setting::getSettings()->webhook_selected." notification failed: " . $e->getMessage());
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_channel_not_found') );
}
else {
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
}
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail') );
} catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
@@ -156,7 +162,7 @@ class CheckoutableListener
$ccEmails = array_filter($adminCcEmailsArray);
$mailable = $this->getCheckinMailType($event);
$notifiable = $this->getNotifiables($event);
if ($event->checkedOutTo->locale){
if ($event->checkedOutTo?->locale) {
$mailable->locale($event->checkedOutTo->locale);
}
// Send email notifications
@@ -196,8 +202,14 @@ class CheckoutableListener
}
}
} catch (ClientException $e) {
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail'));
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
Log::warning(Setting::getSettings()->webhook_selected." notification failed: " . $e->getMessage());
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_channel_not_found') );
}
else {
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
}
} catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(),

View File

@@ -17,7 +17,6 @@ use App\Events\ItemAccepted;
use App\Events\ItemDeclined;
use App\Events\LicenseCheckedIn;
use App\Events\LicenseCheckedOut;
use App\Events\NoteAdded;
use App\Models\Actionlog;
use App\Models\User;
use App\Models\LicenseSeat;
@@ -129,23 +128,6 @@ class LogListener
}
/**
* Note is added to action log
*
*/
public function onNoteAdded(NoteAdded $event)
{
$logaction = new Actionlog();
$logaction->item_id = $event->itemNoteAddedOn->id;
$logaction->item_type = get_class($event->itemNoteAddedOn);
$logaction->note = $event->note; //this is the received alphanumeric text from the box
$logaction->created_by = $event->noteAddedBy->id;
$logaction->action_type = 'note_added';
$logaction->save();
}
/**
* Register the listeners for the subscriber.
*

View File

@@ -342,6 +342,7 @@ class Importer extends Component
'manager_username' => trans('general.importer.manager_username'),
'manager' => trans('general.importer.manager_full_name'),
'parent_location' => trans('admin/locations/table.parent'),
'notes' => trans('general.notes'),
];
$this->assetmodels_fields = [

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ExpiringAssetsMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct($params, $threshold)
{
$this->assets = $params;
$this->threshold = $threshold;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
$from = new Address(config('mail.from.address'), config('mail.from.name'));
return new Envelope(
from: $from,
subject: trans('mail.Expiring_Assets_Report'),
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'notifications.markdown.report-expiring-assets',
with: [
'assets' => $this->assets,
'threshold' => $this->threshold,
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ExpiringLicenseMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct($params, $threshold)
{
$this->licenses = $params;
$this->threshold = $threshold;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
$from = new Address(config('mail.from.address'), config('mail.from.name'));
return new Envelope(
from: $from,
subject: trans('mail.Expiring_Licenses_Report'),
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'notifications.markdown.report-expiring-licenses',
with: [
'licenses' => $this->licenses,
'threshold' => $this->threshold,
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@@ -57,7 +57,7 @@ class AccessoryCheckout extends Model
*/
public function adminuser()
{
return $this->hasOne(\App\Models\User::class, 'created_by');
return $this->hasOne(\App\Models\User::class, 'id', 'created_by');
}
/**
@@ -118,7 +118,7 @@ class AccessoryCheckout extends Model
$query->where('assigned_type', '=', Location::class);
}
public function scopeAssetAssigned(Builder $query): void
public function scopeAssetsAssigned(Builder $query): void
{
$query->where('assigned_type', '=', Asset::class);
}

View File

@@ -413,6 +413,17 @@ class Asset extends Depreciable
return $this->rules;
}
public function customFieldsForCheckinCheckout($checkin_checkout) {
// Check to see if any of the custom fields were included on the form and if they have any values
if (($this->model) && ($this->model->fieldset) && ($this->model->fieldset->fields)) {
foreach ($this->model->fieldset->fields as $field) {
if (($field->{$checkin_checkout} == 1) && (request()->has($field->db_column))){
$this->{$field->db_column} = request()->get($field->db_column);
}
}
}
}
/**
* Establishes the asset -> depreciation relationship
@@ -523,6 +534,18 @@ class Asset extends Depreciable
return $this->morphMany(self::class, 'assigned', 'assigned_type', 'assigned_to')->withTrashed();
}
/**
* Establishes the accessory -> asset assignment relationship
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v3.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function assignedAccessories()
{
return $this->morphMany(\App\Models\AccessoryCheckout::class, 'assigned', 'assigned_type', 'assigned_to');
}
/**
* Get the asset's location based on the assigned user

View File

@@ -71,6 +71,7 @@ class Category extends SnipeModel
'require_acceptance',
'use_default_eula',
'created_by',
'notes',
];
use Searchable;
@@ -80,7 +81,7 @@ class Category extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'category_type'];
protected $searchableAttributes = ['name', 'category_type', 'notes'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -6,6 +6,7 @@ use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate;
use Watson\Validating\ValidatingTrait;
/**
@@ -104,6 +105,13 @@ class Component extends SnipeModel
];
public function isDeletable()
{
return Gate::allows('delete', $this)
&& ($this->numCheckedOut() === 0)
&& ($this->deleted_at == '');
}
/**
* Establishes the components -> action logs -> uploads relationship
*
@@ -234,13 +242,24 @@ class Component extends SnipeModel
// In case there are elements checked out to assets that belong to a different company
// than this asset and full multiple company support is on we'll remove the global scope,
// so they are included in the count.
foreach ($this->assets()->withoutGlobalScope(new CompanyableScope)->get() as $checkout) {
$checkedout += $checkout->pivot->assigned_qty;
}
return $checkedout;
return $this->uncontrainedAssets->sum('pivot.assigned_qty');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*
* This allows us to get the assets with assigned components without the company restriction
*/
public function uncontrainedAssets() {
return $this->belongsToMany(\App\Models\Asset::class, 'components_assets')
->withPivot('id', 'assigned_qty', 'created_at', 'created_by', 'note')
->withoutGlobalScope(new CompanyableScope);
}
/**
* Check how many items within a component are remaining
*

View File

@@ -307,7 +307,7 @@ class CustomField extends Model
public function formatFieldValuesAsArray()
{
$result = [];
$arr = preg_split('/\\r\\n|\\r|\\n/', $this->field_values);
$arr = preg_split('/\\r\\n|\\r|\\n/', $this->field_values ?? '');
if (($this->element != 'checkbox') && ($this->element != 'radio')) {
$result[''] = 'Select '.strtolower($this->format);

View File

@@ -18,7 +18,8 @@ class Group extends SnipeModel
protected $fillable = [
'name',
'permissions'
'permissions',
'notes',
];
/**
@@ -37,7 +38,7 @@ class Group extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'created_at'];
protected $searchableAttributes = ['name', 'created_at', 'notes'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -411,14 +411,14 @@ abstract class Label
/**
* Checks the template is internally valid
*/
public final function validate() {
public final function validate() : void {
$this->validateUnits();
$this->validateSize();
$this->validateMargins();
$this->validateSupport();
}
private function validateUnits() {
private function validateUnits() : void {
$validUnits = [ 'pt', 'mm', 'cm', 'in' ];
$unit = $this->getUnit();
if (!in_array(strtolower($unit), $validUnits)) {
@@ -430,7 +430,7 @@ abstract class Label
}
}
private function validateSize() {
private function validateSize() : void {
$width = $this->getWidth();
if (!is_numeric($width) || is_string($width)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
@@ -450,7 +450,7 @@ abstract class Label
}
}
private function validateMargins() {
private function validateMargins() : void {
$marginTop = $this->getMarginTop();
if (!is_numeric($marginTop) || is_string($marginTop)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
@@ -488,7 +488,7 @@ abstract class Label
}
}
private function validateSupport() {
private function validateSupport() : void {
$support1D = $this->getSupport1DBarcode();
if (!is_bool($support1D)) {
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [

View File

@@ -72,6 +72,7 @@ class Location extends SnipeModel
'currency',
'manager_id',
'image',
'notes',
];
protected $hidden = ['user_id'];
@@ -82,7 +83,7 @@ class Location extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'address', 'city', 'state', 'zip', 'created_at', 'ldap_ou', 'phone', 'fax'];
protected $searchableAttributes = ['name', 'address', 'city', 'state', 'zip', 'created_at', 'ldap_ou', 'phone', 'fax', 'notes'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -34,7 +34,11 @@ trait Loggable
*/
public function logCheckout($note, $target, $action_date = null, $originalValues = [])
{
$log = new Actionlog;
$fields_array = [];
$log = $this->determineLogItemType($log);
if (auth()->user()) {
$log->created_by = auth()->id();
@@ -55,6 +59,7 @@ trait Loggable
$log->target_type = get_class($target);
$log->target_id = $target->id;
// Figure out what the target is
if ($log->target_type == Location::class) {
$log->location_id = $target->id;
@@ -64,6 +69,21 @@ trait Loggable
$log->location_id = $target->location_id;
}
if (static::class == Asset::class) {
if ($asset = Asset::find($log->item_id)) {
// add the custom fields that were changed
if ($asset->model->fieldset) {
$fields_array = [];
foreach ($asset->model->fieldset->fields as $field) {
if ($field->display_checkout == 1) {
$fields_array[$field->db_column] = $asset->{$field->db_column};
}
}
}
}
}
$log->note = $note;
$log->action_date = $action_date;
@@ -72,7 +92,10 @@ trait Loggable
}
$changed = [];
$originalValues = array_intersect_key($originalValues, array_flip(['action_date','name','status_id','location_id','expected_checkin']));
$array_to_flip = array_keys($fields_array);
$array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
$originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
foreach ($originalValues as $key => $value) {
if ($key == 'action_date' && $value != $action_date) {
@@ -119,6 +142,8 @@ trait Loggable
{
$log = new Actionlog;
$fields_array = [];
if($target != null){
$log->target_type = get_class($target);
$log->target_id = $target->id;
@@ -135,6 +160,16 @@ trait Loggable
if (static::class == Asset::class) {
if ($asset = Asset::find($log->item_id)) {
$asset->increment('checkin_counter', 1);
// add the custom fields that were changed
if ($asset->model->fieldset) {
$fields_array = [];
foreach ($asset->model->fieldset->fields as $field) {
if ($field->display_checkin == 1) {
$fields_array[$field->db_column] = $asset->{$field->db_column};
}
}
}
}
}
}
@@ -152,9 +187,14 @@ trait Loggable
}
$changed = [];
$originalValues = array_intersect_key($originalValues, array_flip(['action_date','name','status_id','location_id','rtd_location_id','expected_checkin']));
$array_to_flip = array_keys($fields_array);
$array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
$originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
foreach ($originalValues as $key => $value) {
if ($key == 'action_date' && $value != $action_date) {
$changed[$key]['old'] = $value;
$changed[$key]['new'] = is_string($action_date) ? $action_date : $action_date->format('Y-m-d H:i:s');

View File

@@ -53,6 +53,7 @@ class Manufacturer extends SnipeModel
'support_url',
'url',
'warranty_lookup_url',
'notes',
];
use Searchable;
@@ -62,7 +63,7 @@ class Manufacturer extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'created_at'];
protected $searchableAttributes = ['name', 'created_at', 'notes'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -2,6 +2,7 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
@@ -339,6 +340,33 @@ class Setting extends Model
return collect($ldapSettings);
}
/**
* For a particular cache-file, refresh it if the settings have
* been updated more recently than the file. Then return the
* full filepath
*/
public static function get_fresh_file_path($attribute, $path)
{
$full_path = storage_path().'/'.$path;
$file_exists = file_exists($full_path);
if ($file_exists) {
$statblock = stat($full_path);
}
if (!$file_exists || Carbon::createFromTimestamp($statblock['mtime']) < Setting::getSettings()->updated_at) {
if (Setting::getSettings()->{$attribute}) {
file_put_contents($full_path, Setting::getSettings()->{$attribute});
} else {
//this doesn't fire when you might expect it to because a lot of the time we do something like:
// if ($settings->ldap_client_tls_cert && ...
// so we never get a chance to 'uncache' the file.
if ($file_exists) {
unlink($full_path);
}
}
}
return $full_path;
}
/**
* Return the filename for the client-side SSL cert
*
@@ -346,7 +374,7 @@ class Setting extends Model
*/
public static function get_client_side_cert_path()
{
return storage_path().'/ldap_client_tls.cert';
return self::get_fresh_file_path('ldap_client_tls_cert', 'ldap_client_tls.cert');
}
/**
@@ -356,36 +384,7 @@ class Setting extends Model
*/
public static function get_client_side_key_path()
{
return storage_path().'/ldap_client_tls.key';
return self::get_fresh_file_path('ldap_client_tls_key', 'ldap_client_tls.key');
}
public function update_client_side_cert_files()
{
/**
* I'm not sure if it makes sense to have a cert but no key
* nor vice versa, but for now I'm just leaving it like this.
*
* Also, we could easily set this up with an event handler and
* self::saved() or something like that but there's literally only
* one place where we will do that, so I'll just explicitly call
* this method at that spot instead. It'll be easier to debug and understand.
*/
if ($this->ldap_client_tls_cert) {
file_put_contents(self::get_client_side_cert_path(), $this->ldap_client_tls_cert);
} else {
if (file_exists(self::get_client_side_cert_path())) {
unlink(self::get_client_side_cert_path());
}
}
if ($this->ldap_client_tls_key) {
file_put_contents(self::get_client_side_key_path(), $this->ldap_client_tls_key);
} else {
if (file_exists(self::get_client_side_key_path())) {
unlink(self::get_client_side_key_path());
}
}
}
}

View File

@@ -626,6 +626,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
$username = str_slug(substr($first_name, 0, 1).'.'.str_slug($last_name));
} elseif ($format == 'lastname_firstinitial') {
$username = str_slug($last_name).'_'.str_slug(substr($first_name, 0, 1));
} elseif ($format == 'lastname.firstinitial') {
$username = str_slug($last_name).'.'.str_slug(substr($first_name, 0, 1));
} elseif ($format == 'firstnamelastname') {
$username = str_slug($first_name).str_slug($last_name);
} elseif ($format == 'firstnamelastinitial') {

View File

@@ -79,7 +79,7 @@ class CheckinAssetNotification extends Notification
$fields = [
trans('general.administrator') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>',
trans('general.status') => $item->assetstatus->name,
trans('general.status') => $item->assetstatus?->name,
trans('general.location') => ($item->location) ? $item->location->name : '',
];
@@ -106,9 +106,9 @@ class CheckinAssetNotification extends Notification
->title(trans('mail.Asset_Checkin_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->present()->fullName())
->fact(trans('admin/hardware/form.status'), $item->assetstatus->name)
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
->fact(trans('mail.notes'), $note ?: '');
}
@@ -116,9 +116,9 @@ class CheckinAssetNotification extends Notification
$message = trans('mail.Asset_Checkin_Notification');
$details = [
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
trans('mail.Asset_Checkin_Notification')." by " => $admin->present()->fullName(),
trans('admin/hardware/form.status') => $item->assetstatus->name,
trans('admin/hardware/form.status') => $item->assetstatus?->name,
trans('mail.notes') => $note ?: '',
];
@@ -142,8 +142,8 @@ class CheckinAssetNotification extends Notification
Section::create(
KeyValue::create(
trans('mail.checked_into') ?: '',
$item->location->name ? $item->location->name : '',
trans('admin/hardware/form.status').": ".$item->assetstatus->name,
($item->location) ? $item->location->name : '',
trans('admin/hardware/form.status').": ".$item->assetstatus?->name,
)
->onClick(route('hardware.show', $item->id))
)

View File

@@ -20,6 +20,7 @@ class AssetAuditPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
],
[
'field' => 'id',

View File

@@ -22,6 +22,15 @@ class AssetMaintenancesPresenter extends Presenter
'title' => trans('general.id'),
'visible' => false,
], [
'field' => 'title',
'searchable' => true,
'sortable' => true,
'switchable' => true,
'title' => trans('general.name'),
'visible' => true,
'formatter' => 'maintenancesLinkFormatter',
],
[
'field' => 'company',
'searchable' => true,
'sortable' => true,

View File

@@ -15,6 +15,7 @@ class AssetModelPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
],
[
'field' => 'id',

View File

@@ -21,6 +21,7 @@ class AssetPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
], [
'field' => 'id',
'searchable' => false,
@@ -35,7 +36,7 @@ class AssetPresenter extends Presenter
'switchable' => true,
'title' => trans('general.company'),
'visible' => false,
'formatter' => 'assetCompanyObjFilterFormatter',
'formatter' => 'companiesLinkObjFormatter',
], [
'field' => 'name',
'searchable' => true,
@@ -352,6 +353,74 @@ class AssetPresenter extends Presenter
return json_encode($layout);
}
public static function assignedAccessoriesDataTableLayout()
{
$layout = [
[
'field' => 'id',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.id'),
'visible' => false,
],
[
'field' => 'accessory',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.accessory'),
'visible' => true,
'formatter' => 'accessoriesLinkObjFormatter',
],
[
'field' => 'image',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.image'),
'visible' => true,
'formatter' => 'imageFormatter',
],
[
'field' => 'note',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('general.notes'),
'visible' => true,
],
[
'field' => 'created_at',
'searchable' => false,
'sortable' => false,
'switchable' => true,
'title' => trans('admin/hardware/table.checkout_date'),
'visible' => true,
'formatter' => 'dateDisplayFormatter',
],
[
'field' => 'created_by',
'searchable' => false,
'sortable' => false,
'title' => trans('general.created_by'),
'visible' => false,
'formatter' => 'usersLinkObjFormatter',
],
[
'field' => 'available_actions',
'searchable' => false,
'sortable' => false,
'switchable' => false,
'title' => trans('table.actions'),
'formatter' => 'accessoriesInOutFormatter',
],
];
return json_encode($layout);
}
/**
* Generate html link to this items name.
* @return string

View File

@@ -77,7 +77,13 @@ class CategoryPresenter extends Presenter
"title" => trans('admin/categories/general.use_default_eula_column'),
'visible' => true,
"formatter" => 'trueFalseFormatter',
],[
], [
'field' => 'notes',
'searchable' => true,
'sortable' => true,
'visible' => false,
'title' => trans('general.notes'),
], [
'field' => 'created_by',
'searchable' => false,
'sortable' => true,

View File

@@ -105,7 +105,13 @@ class CompanyPresenter extends Presenter
'title' => trans('general.components'),
'visible' => true,
'class' => 'css-component',
],[
], [
'field' => 'notes',
'searchable' => true,
'sortable' => true,
'visible' => false,
'title' => trans('general.notes'),
], [
'field' => 'created_by',
'searchable' => false,
'sortable' => true,

View File

@@ -102,13 +102,13 @@ class LocationPresenter extends Presenter
'titleTooltip' => trans('general.people'),
'visible' => true,
'class' => 'css-house-user',
// 'data-tooltip' => true, - not working, but I want to try to use regular tooltips here
], [
'field' => 'currency',
'searchable' => true,
'sortable' => true,
'switchable' => true,
'title' => trans('general.currency'),
'title' => trans('general.currency_text'),
'titleTooltip' => trans('general.currency_text'),
'visible' => true,
'class' => 'css-currency',
], [
@@ -184,6 +184,12 @@ class LocationPresenter extends Presenter
'title' => trans('admin/users/table.manager'),
'visible' => false,
'formatter' => 'usersLinkObjFormatter',
], [
'field' => 'notes',
'searchable' => true,
'sortable' => true,
'visible' => false,
'title' => trans('general.notes'),
], [
'field' => 'created_at',
'searchable' => true,

View File

@@ -28,7 +28,7 @@ class StatusLabelPresenter extends Presenter
'switchable' => false,
'title' => trans('general.name'),
'visible' => true,
'formatter' => 'statuslabelsAssetLinkFormatter',
'formatter' => 'statuslabelsLinkFormatter',
],[
'field' => 'type',
'searchable' => false,

Some files were not shown because too many files have changed in this diff Show More