Compare commits

...

392 Commits

Author SHA1 Message Date
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 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
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
1086 changed files with 13261 additions and 5407 deletions
+1 -1
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 }}
+2 -1
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 }}
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
fail-fast: false
matrix:
php-version:
- "8.1.1"
- "8.3"
name: PHP ${{ matrix.php-version }}
+3 -3
View File
@@ -4,7 +4,7 @@
"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_max_major_minor": "8.4",
"php_max_wontwork": "8.5.0",
"current_snipeit_version": "8.0"
}
+16 -16
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 \
@@ -41,7 +41,7 @@ libc-dev \
libldap-common \
pkg-config \
libmcrypt-dev \
php8.1-dev \
php8.3-dev \
ca-certificates \
unzip \
dnsutils \
@@ -53,16 +53,16 @@ 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 bash -c "echo extension=/usr/lib/php/20210902/mcrypt.so > /etc/php/8.3/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
@@ -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 == '') {
-28
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;
}
}
+21
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' )) {
+3 -3
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'));
+4
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';
@@ -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'));
}
}
@@ -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'));
}
}
+12 -3
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
*
@@ -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');
@@ -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'));
@@ -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')));
@@ -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')) {
@@ -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()) {
@@ -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');
@@ -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')
@@ -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)
{
}
}
@@ -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);
}
}
+14 -45
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]
@@ -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'));
}
}
@@ -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));
@@ -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) {
@@ -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', ['hardware' => $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', ['hardware' => $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', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
}
}
@@ -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
@@ -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
}
/**
+7 -21
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'));
}
}
+7 -21
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);
}
}
@@ -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'));
}
}
@@ -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
@@ -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'));
@@ -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());
}
/**
+8 -22
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()) {
@@ -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);
+10 -24
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'));
}
}
@@ -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);
}
@@ -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);
}
/**
@@ -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);
}
@@ -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')]));
}
@@ -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'));
+7 -15
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');
}
/**
@@ -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'));
@@ -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'));
}
/**
+42
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'));
}
}
+1 -1
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'));
}
@@ -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')]);
+5 -22
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'));
}
}
@@ -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);
@@ -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'));
}
}
+8 -20
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);
+3 -2
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) {
+1 -1
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) {
+11
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),
],
];
}
}
@@ -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]);
}
}
}
@@ -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 ? [
@@ -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'),
];
@@ -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'),
];
@@ -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;
@@ -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'),
];
@@ -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()),
@@ -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,
@@ -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()),
+2
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')));
+16 -4
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(),
-18
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.
*
+1
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 = [
+62
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 [];
}
}
+62
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 [];
}
}
+2 -2
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);
}
+23
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
+2 -1
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.
+24 -5
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
*
+1 -1
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);
+3 -2
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.
+5 -5
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', [
+2 -1
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.
+42 -2
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');
+2 -1
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.
+30 -31
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());
}
}
}
}
+2
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') {
@@ -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))
)
+1
View File
@@ -20,6 +20,7 @@ class AssetAuditPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
],
[
'field' => 'id',
@@ -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,
+1
View File
@@ -15,6 +15,7 @@ class AssetModelPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
],
[
'field' => 'id',
+70 -1
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
+7 -1
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,
+7 -1
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,
+8 -2
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,
+1 -1
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,
+1
View File
@@ -24,6 +24,7 @@ class UserPresenter extends Presenter
[
'field' => 'checkbox',
'checkbox' => true,
'titleTooltip' => trans('general.select_all_none'),
],
[
'field' => 'id',
+3 -3
View File
@@ -87,9 +87,9 @@ class AuthServiceProvider extends ServiceProvider
]);
$this->registerPolicies();
Passport::tokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
Passport::refreshTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
Passport::personalAccessTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
Passport::tokensExpireIn(Carbon::now()->addYears((int)config('passport.expiration_years')));
Passport::refreshTokensExpireIn(Carbon::now()->addYears((int)config('passport.expiration_years')));
Passport::personalAccessTokensExpireIn(Carbon::now()->addYears((int)config('passport.expiration_years')));
Passport::cookie(config('passport.cookie_name'));
@@ -0,0 +1,555 @@
<?php namespace App\Providers;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use App\Models\Department;
use App\Models\Depreciation;
use App\Models\Group;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\PredefinedKit;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Support\ServiceProvider;
use Tabuna\Breadcrumbs\Breadcrumbs;
use Tabuna\Breadcrumbs\Trail;
class BreadcrumbsServiceProvider extends ServiceProvider
{
/**
* Handles the resource routes for first-class objects
*
* @return void
*/
public function boot()
{
// Default home
Breadcrumbs::for('home', fn (Trail $trail) =>
$trail->push('<x-icon type="home" /><span class="sr-only">'.trans('general.dashboard').'</span>', route('home'))
);
/**
* Asset Breadcrumbs
*/
if ((request()->is('hardware*')) && (request()->status!='')) {
Breadcrumbs::for('hardware.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.assets'), route('hardware.index'))
->push(request()->status.' '.trans('general.assets'), route('hardware.index', ['status' => request()->status]))
);
} else {
Breadcrumbs::for('hardware.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.assets'), route('hardware.index'))
);
}
Breadcrumbs::for('hardware.create', fn (Trail $trail) =>
$trail->parent('hardware.index', route('hardware.index'))
->push(trans('general.create'), route('hardware.create'))
);
Breadcrumbs::for('hardware.show', fn (Trail $trail, Asset $asset) =>
$trail->parent('hardware.index', route('hardware.index'))
->push($asset->present()->fullName(), route('hardware.show', $asset))
);
Breadcrumbs::for('hardware.edit', fn (Trail $trail, Asset $asset) =>
$trail->parent('hardware.index', route('hardware.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $asset->asset_tag]), route('hardware.edit', $asset))
);
/**
* Asset Model Breadcrumbs
*/
if ((request()->is('models*')) && (request()->status=='deleted')) {
Breadcrumbs::for('models.index', fn (Trail $trail) =>
$trail->parent('hardware.index', route('hardware.index'))
->push(trans('general.asset_models'), route('models.index'))
->push(trans('general.deleted_models'), route('models.index', ['status' => request()->status]))
);
} else {
Breadcrumbs::for('models.index', fn (Trail $trail) =>
$trail->parent('hardware.index', route('hardware.index'))
->push(trans('general.asset_models'), route('models.index'))
);
}
Breadcrumbs::for('models.create', fn (Trail $trail) =>
$trail->parent('models.index', route('models.index'))
->push(trans('general.create'), route('models.create'))
);
Breadcrumbs::for('models.show', fn (Trail $trail, AssetModel $model) =>
$trail->parent('models.index', route('models.index'))
->push($model->name, route('models.show', $model))
);
Breadcrumbs::for('models.edit', fn (Trail $trail, AssetModel $model) =>
$trail->parent('models.index', route('models.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $model->name]), route('models.edit', $model))
);
/**
* Accessories Breadcrumbs
*/
Breadcrumbs::for('accessories.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.accessories'), route('accessories.index'))
);
Breadcrumbs::for('accessories.create', fn (Trail $trail) =>
$trail->parent('accessories.index', route('accessories.index'))
->push(trans('general.create'), route('accessories.create'))
);
Breadcrumbs::for('accessories.show', fn (Trail $trail, Accessory $accessory) =>
$trail->parent('accessories.index', route('accessories.index'))
->push($accessory->name, route('accessories.show', $accessory))
);
Breadcrumbs::for('accessories.edit', fn (Trail $trail, Accessory $accessory) =>
$trail->parent('accessories.index', route('accessories.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $accessory->name]), route('accessories.edit', $accessory))
);
/**
* Categories Breadcrumbs
*/
Breadcrumbs::for('categories.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.categories'), route('categories.index'))
);
Breadcrumbs::for('categories.create', fn (Trail $trail) =>
$trail->parent('categories.index', route('categories.index'))
->push(trans('general.create'), route('categories.create'))
);
Breadcrumbs::for('categories.show', fn (Trail $trail, Category $category) =>
$trail->parent('categories.index', route('categories.index'))
->push($category->name, route('categories.show', $category))
);
Breadcrumbs::for('categories.edit', fn (Trail $trail, Category $category) =>
$trail->parent('categories.index', route('categories.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $category->name]), route('categories.edit', $category))
);
/**
* Company Breadcrumbs
*/
Breadcrumbs::for('companies.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.companies'), route('companies.index'))
);
Breadcrumbs::for('companies.create', fn (Trail $trail) =>
$trail->parent('companies.index', route('companies.index'))
->push(trans('general.create'), route('companies.create'))
);
Breadcrumbs::for('companies.show', fn (Trail $trail, Company $company) =>
$trail->parent('companies.index', route('companies.index'))
->push($company->name, route('companies.show', $company))
);
Breadcrumbs::for('companies.edit', fn (Trail $trail, Company $company) =>
$trail->parent('companies.index', route('companies.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $company->name]), route('companies.edit', $company))
);
/**
* Components Breadcrumbs
*/
Breadcrumbs::for('components.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.components'), route('components.index'))
);
Breadcrumbs::for('components.create', fn (Trail $trail) =>
$trail->parent('components.index', route('components.index'))
->push(trans('general.create'), route('components.create'))
);
Breadcrumbs::for('components.show', fn (Trail $trail, Component $component) =>
$trail->parent('components.index', route('components.index'))
->push($component->name, route('components.show', $component))
);
Breadcrumbs::for('components.edit', fn (Trail $trail, Component $component) =>
$trail->parent('components.index', route('components.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $component->name]), route('components.edit', $component))
);
/**
* Consumables Breadcrumbs
*/
Breadcrumbs::for('consumables.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.consumables'), route('consumables.index'))
);
Breadcrumbs::for('consumables.create', fn (Trail $trail) =>
$trail->parent('consumables.index', route('consumables.index'))
->push(trans('general.create'), route('consumables.create'))
);
Breadcrumbs::for('consumables.show', fn (Trail $trail, Consumable $consumable) =>
$trail->parent('consumables.index', route('consumables.index'))
->push($consumable->name, route('consumables.show', $consumable))
);
Breadcrumbs::for('consumables.edit', fn (Trail $trail, Consumable $consumable) =>
$trail->parent('consumables.index', route('consumables.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $consumable->name]), route('consumables.edit', $consumable))
);
/**
* Custom fields Breadcrumbs
*/
Breadcrumbs::for('fields.index', fn (Trail $trail) =>
$trail->parent('models.index', route('models.index'))
->push(trans('admin/custom_fields/general.custom_fields'), route('fields.index'))
);
Breadcrumbs::for('fields.create', fn (Trail $trail) =>
$trail->parent('fields.index', route('fields.index'))
->push(trans('general.create'), route('fields.create'))
);
Breadcrumbs::for('fields.edit', fn (Trail $trail, CustomField $field) =>
$trail->parent('fields.index', route('fields.index'))
->push($field->name, route('fields.edit', $field))
);
/**
* Custom fieldsets Breadcrumbs
*/
Breadcrumbs::for('fieldsets.create', fn (Trail $trail) =>
$trail->parent('fields.index', route('fields.index'))
->push(trans('general.create'), route('fieldsets.create'))
);
Breadcrumbs::for('fieldsets.show', fn (Trail $trail, CustomFieldset $fieldset) =>
$trail->parent('fields.index', route('fields.index'))
->push($fieldset->name, route('fields.index'))
);
Breadcrumbs::for('fieldsets.edit', fn (Trail $trail, CustomFieldset $fieldset) =>
$trail->parent('fields.index', route('fields.index'))
->push($fieldset->name, route('fieldsets.edit', $fieldset))
);
/**
* Department Breadcrumbs
*/
Breadcrumbs::for('departments.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.departments'), route('departments.index'))
);
Breadcrumbs::for('departments.create', fn (Trail $trail) =>
$trail->parent('departments.index', route('departments.index'))
->push(trans('general.create'), route('departments.create'))
);
Breadcrumbs::for('departments.show', fn (Trail $trail, Department $department) =>
$trail->parent('departments.index', route('departments.index'))
->push($department->name, route('home'))
);
Breadcrumbs::for('departments.edit', fn (Trail $trail, Department $department) =>
$trail->parent('departments.index', route('departments.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $department->name]), route('departments.edit', $department))
);
/**
* Department Breadcrumbs
*/
Breadcrumbs::for('depreciations.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.depreciations'), route('depreciations.index'))
);
Breadcrumbs::for('depreciations.create', fn (Trail $trail) =>
$trail->parent('depreciations.index', route('depreciations.index'))
->push(trans('general.create'), route('depreciations.create'))
);
Breadcrumbs::for('depreciations.show', fn (Trail $trail, Depreciation $depreciation) =>
$trail->parent('depreciations.index', route('depreciations.index'))
->push($depreciation->name, route('depreciations.show', $depreciation))
);
Breadcrumbs::for('depreciations.edit', fn (Trail $trail, Depreciation $depreciation) =>
$trail->parent('depreciations.index', route('depreciations.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $depreciation->name]), route('depreciations.edit', $depreciation))
);
/**
* Groups Breadcrumbs
*/
Breadcrumbs::for('groups.index', fn (Trail $trail) =>
$trail->parent('settings.index', route('settings.index'))
->push(trans('general.groups'), route('groups.index'))
);
Breadcrumbs::for('groups.create', fn (Trail $trail) =>
$trail->parent('groups.index', route('groups.index'))
->push(trans('general.create'), route('groups.create'))
);
Breadcrumbs::for('groups.show', fn (Trail $trail, Group $group) =>
$trail->parent('groups.index', route('groups.index'))
->push($group->name, route('groups.show', $group))
);
Breadcrumbs::for('groups.edit', fn (Trail $trail, Group $group) =>
$trail->parent('groups.index', route('groups.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $group->name]), route('groups.edit', $group))
);
/**
* Licenses Breadcrumbs
*/
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.licenses'), route('licenses.index'))
);
Breadcrumbs::for('licenses.create', fn (Trail $trail) =>
$trail->parent('licenses.index', route('licenses.index'))
->push(trans('general.create'), route('licenses.create'))
);
Breadcrumbs::for('licenses.show', fn (Trail $trail, License $license) =>
$trail->parent('licenses.index', route('licenses.index'))
->push($license->name, route('licenses.show', $license))
);
Breadcrumbs::for('licenses.edit', fn (Trail $trail, License $license) =>
$trail->parent('licenses.index', route('licenses.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $license->name]), route('licenses.edit', $license))
);
/**
* Locations Breadcrumbs
*/
Breadcrumbs::for('locations.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.locations'), route('locations.index'))
);
Breadcrumbs::for('locations.create', fn (Trail $trail) =>
$trail->parent('locations.index', route('locations.index'))
->push(trans('general.create'), route('locations.create'))
);
Breadcrumbs::for('locations.show', fn (Trail $trail, Location $location) =>
$trail->parent('locations.index', route('locations.index'))
->push($location->name, route('locations.show', $location))
);
Breadcrumbs::for('locations.edit', fn (Trail $trail, Location $location) =>
$trail->parent('locations.index', route('locations.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $location->name]), route('locations.edit', $location))
);
/**
* Maintenances Breadcrumbs
*/
Breadcrumbs::for('maintenances.index', fn (Trail $trail) =>
$trail->parent('hardware.index', route('hardware.index'))
->push(trans('general.maintenances'), route('maintenances.index'))
);
Breadcrumbs::for('maintenances.create', fn (Trail $trail) =>
$trail->parent('maintenances.index', route('maintenances.index'))
->push(trans('general.create'), route('maintenances.create'))
);
Breadcrumbs::for('maintenances.show', fn (Trail $trail, AssetMaintenance $maintenance) =>
$trail->parent('maintenances.index', route('locations.index'))
->push($maintenance->title, route('maintenances.show', $maintenance))
);
Breadcrumbs::for('manufacturers.edit', fn (Trail $trail, Manufacturer $manufacturer) =>
$trail->parent('manufacturers.index', route('manufacturers.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $manufacturer->name]), route('manufacturers.edit', $manufacturer))
);
/**
* Manufacturers Breadcrumbs
*/
Breadcrumbs::for('manufacturers.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.manufacturers'), route('manufacturers.index'))
);
Breadcrumbs::for('manufacturers.create', fn (Trail $trail) =>
$trail->parent('manufacturers.index', route('manufacturers.index'))
->push(trans('general.create'), route('manufacturers.create'))
);
Breadcrumbs::for('manufacturers.show', fn (Trail $trail, Manufacturer $manufacturer) =>
$trail->parent('manufacturers.index', route('manufacturers.index'))
->push($manufacturer->name, route('home'))
);
Breadcrumbs::for('manufacturers.edit', fn (Trail $trail, Manufacturer $manufacturer) =>
$trail->parent('manufacturers.index', route('manufacturers.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $manufacturer->name]), route('manufacturers.edit', $manufacturer))
);
/**
* Predefined Kits Breadcrumbs
*/
Breadcrumbs::for('kits.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.kits'), route('kits.index'))
);
Breadcrumbs::for('kits.create', fn (Trail $trail) =>
$trail->parent('kits.index', route('kits.index'))
->push(trans('general.create'), route('kits.create'))
);
Breadcrumbs::for('kits.show', fn (Trail $trail, PredefinedKit $kit) =>
$trail->parent('kits.index', route('kits.index'))
->push($kit->name, route('kits.show', $kit))
);
Breadcrumbs::for('kits.edit', fn (Trail $trail, PredefinedKit $kit) =>
$trail->parent('kits.index', route('kits.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $kit->name]), route('kits.edit', $kit))
);
/**
* Status Labels Breadcrumbs
*/
Breadcrumbs::for('statuslabels.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.status_labels'), route('statuslabels.index'))
);
Breadcrumbs::for('statuslabels.create', fn (Trail $trail) =>
$trail->parent('statuslabels.index', route('statuslabels.index'))
->push(trans('general.create'), route('statuslabels.create'))
);
Breadcrumbs::for('statuslabels.show', fn (Trail $trail, Statuslabel $statuslabel) =>
$trail->parent('statuslabels.index', route('statuslabels.index'))
->push($statuslabel->name, route('statuslabels.show', $statuslabel))
);
Breadcrumbs::for('statuslabels.edit', fn (Trail $trail, Statuslabel $statuslabel) =>
$trail->parent('statuslabels.index', route('statuslabels.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $statuslabel->name]), route('statuslabels.edit', $statuslabel))
);
/**
* Settings Breadcrumbs
*/
Breadcrumbs::for('settings.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.admin'), route('settings.index'))
);
/**
* Suppliers Breadcrumbs
*/
Breadcrumbs::for('suppliers.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.suppliers'), route('suppliers.index'))
);
Breadcrumbs::for('suppliers.create', fn (Trail $trail) =>
$trail->parent('suppliers.index', route('suppliers.index'))
->push(trans('general.create'), route('suppliers.create'))
);
Breadcrumbs::for('suppliers.show', fn (Trail $trail, Supplier $supplier) =>
$trail->parent('suppliers.index', route('suppliers.index'))
->push($supplier->name, route('home'))
);
Breadcrumbs::for('suppliers.edit', fn (Trail $trail, Supplier $supplier) =>
$trail->parent('suppliers.index', route('suppliers.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $supplier->name]), route('suppliers.edit', $supplier))
);
/**
* Users Breadcrumbs
*/
if ((request()->is('users*')) && (request()->status=='deleted')) {
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
->push(trans('general.users'), route('users.index'))
->push(trans('general.deleted_users'), route('users.index'))
);
} else {
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
->push(trans('general.users'), route('users.index'))
);
}
Breadcrumbs::for('users.create', fn (Trail $trail) =>
$trail->parent('users.index', route('users.index'))
->push(trans('general.create'), route('users.create'))
);
Breadcrumbs::for('users.show', fn (Trail $trail, User $user) =>
$trail->parent('users.index', route('users.index'))
->push($user->username, route('users.show', $user))
);
Breadcrumbs::for('users.edit', fn (Trail $trail, User $user) =>
$trail->parent('users.index', route('users.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $user->name]), route('users.edit', $user))
);
}
}
-4
View File
@@ -49,10 +49,6 @@ class SamlServiceProvider extends ServiceProvider
'uses' => 'Auth\SamlController@login', ]
);
Route::group(['prefix' => 'admin', 'middleware' => ['web', 'auth', 'authorize:superuser']], function () {
Route::get('saml', ['as' => 'settings.saml.index', 'uses' => 'SettingsController@getSamlSettings']);
Route::post('saml', ['as' => 'settings.saml.save', 'uses' => 'SettingsController@postSamlSettings']);
});
});
}
+1 -1
View File
@@ -209,7 +209,7 @@ class Saml
}
}
$custom_settings = preg_split('/\r\n|\r|\n/', $setting->saml_custom_settings);
$custom_settings = preg_split('/\r\n|\r|\n/', $setting->saml_custom_settings ?? '');
if ($custom_settings) {
foreach ($custom_settings as $custom_setting) {
$split = explode('=', $custom_setting, 2);
+5 -3
View File
@@ -26,17 +26,19 @@ class SnipeTranslator extends Translator {
public function choice($key, $number, array $replace = [], $locale = null)
{
$line = $this->get(
$key, $replace, $locale = $this->localeForChoice($locale)
$key, [], $locale = $this->localeForChoice($key, $locale)
);
// If the given "number" is actually an array or countable we will simply count the
// number of elements in an instance. This allows developers to pass an array of
// items without having to count it on their end first which gives bad syntax.
if (is_array($number) || $number instanceof Countable) {
if (is_countable($number)) {
$number = count($number);
}
$replace['count'] = $number;
if (!isset($replace['count'])) {
$replace['count'] = $number;
}
$underscored_locale = str_replace("-","_",$locale); // OUR CHANGE.
return $this->makeReplacements( // BELOW - that $underscored_locale is the *ONLY* modified part
+10 -6
View File
@@ -7,6 +7,7 @@ use App\Models\Labels\Label as LabelModel;
use App\Models\Labels\Sheet;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Traits\Macroable;
use TCPDF;
@@ -38,7 +39,7 @@ class Label implements View
$settings = $this->data->get('settings');
$assets = $this->data->get('assets');
$offset = $this->data->get('offset');
$template = LabelModel::find($settings->label2_template);
// If disabled, pass to legacy view
if ((!$settings->label2_enable)) {
@@ -49,6 +50,12 @@ class Label implements View
->with('count', $this->data->get('count'));
}
$template = LabelModel::find($settings->label2_template);
if ($template === null) {
return redirect()->route('settings.labels.index')->with('error', trans('admin/settings/message.labels.null_template'));
}
$template->validate();
$pdf = new TCPDF(
@@ -116,12 +123,9 @@ class Label implements View
}
}
if ($template->getSupport2DBarcode()) {
if ($template->getSupport2DBarcode()) {
$barcode2DType = $settings->label2_2d_type;
$barcode2DType = ($barcode2DType == 'default') ?
$settings->barcode_type :
$barcode2DType;
if (($barcode2DType != 'none') && (!is_null($barcode2DType))) {
if (($barcode2DType != 'none') && (!is_null($barcode2DType))) {
switch ($settings->label2_2d_target) {
case 'ht_tag':
$barcode2DTarget = route('ht/assetTag', $asset->asset_tag);
+14 -10
View File
@@ -14,10 +14,14 @@
{
"type": "vcs",
"url": "https://github.com/grokability/laravel-scim-server"
},
{
"type": "vcs",
"url": "https://github.com/grokability/html"
}
],
"require": {
"php": "^8.1",
"php": "^8.2",
"ext-curl": "*",
"ext-fileinfo": "*",
"ext-iconv": "*",
@@ -25,7 +29,7 @@
"ext-mbstring": "*",
"ext-pdo": "*",
"alek13/slack": "^2.0",
"arietimmerman/laravel-scim-server": "dev-master",
"arietimmerman/laravel-scim-server": "dev-laravel_11_compatibility",
"bacon/bacon-qr-code": "^2.0",
"barryvdh/laravel-debugbar": "^3.13",
"barryvdh/laravel-dompdf": "^2.0",
@@ -40,20 +44,20 @@
"javiereguiluz/easyslugger": "^1.0",
"laravel-notification-channels/google-chat": "^3.0",
"laravel-notification-channels/microsoft-teams": "^1.2",
"laravel/framework": "^10.0",
"laravel/framework": "^11.0",
"laravel/helpers": "^1.4",
"laravel/passport": "^11.0",
"laravel/slack-notification-channel": "^2.3",
"laravel/passport": "^12.0",
"laravel/slack-notification-channel": "^3.4",
"laravel/socialite": "^5.6",
"laravel/tinker": "^2.6",
"laravel/ui": "^4.0",
"laravelcollective/html": "^6.2",
"laravelcollective/html": "6.x-dev",
"league/csv": "^9.7",
"league/flysystem-aws-s3-v3": "^3.0",
"livewire/livewire": "^3.5",
"neitanod/forceutf8": "^2.0",
"nesbot/carbon": "^2.32",
"nunomaduro/collision": "^7.0",
"nesbot/carbon": "^3.0",
"nunomaduro/collision": "^8.1",
"okvpn/clock-lts": "^1.0",
"onelogin/php-saml": "^3.4",
"onnov/detect-encoding": "^2.0",
@@ -66,6 +70,7 @@
"rollbar/rollbar-laravel": "^8.0",
"spatie/laravel-backup": "^8.8",
"spatie/laravel-ignition": "^2.0",
"tabuna/breadcrumbs": "^4.2",
"tecnickcom/tc-lib-barcode": "^1.15",
"tecnickcom/tcpdf": "^6.5",
"unicodeveloper/laravel-password": "^1.0",
@@ -85,8 +90,7 @@
"phpunit/phpunit": "^10.0",
"squizlabs/php_codesniffer": "^3.5",
"symfony/css-selector": "^4.4",
"symfony/dom-crawler": "^4.4",
"vimeo/psalm": "^5.13"
"symfony/dom-crawler": "^4.4"
},
"extra": {
"laravel": {
Generated
+1126 -1526
View File
File diff suppressed because it is too large Load Diff

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