Compare commits

..

932 Commits

Author SHA1 Message Date
snipe
8a206e6c8e Beginning refactor
Signed-off-by: snipe <snipe@snipe.net>
2022-03-19 22:26:23 +00:00
snipe
73acf6e5e8 Squashed commit of the following:
commit d55c176199
Merge: 93ff9524d c0451fe17
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 18:35:42 2022 +0000

    Merge pull request #10831 from snipe/merges/master_down_to_develop_march_16

    v6.0.0-RC-5 - Merges master down to develop

commit c0451fe17a
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 18:10:17 2022 +0000

    Bumped version to v6.0.0-RC-5

    Signed-off-by: snipe <snipe@snipe.net>

commit 0f95802699
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 18:05:47 2022 +0000

    Fixed mis-automerge

    Signed-off-by: snipe <snipe@snipe.net>

commit 9db8bd782d
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 18:02:07 2022 +0000

    Merging master down into develop

    Signed-off-by: snipe <snipe@snipe.net>

commit 93ff9524d6
Merge: 40a947077 89ddbddad
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 10:04:58 2022 -0700

    Merge pull request #10829 from snipe/features/add_statuslabel_filter_by_type_in_api

    Added filter by status_type in StatusLabels API index endpoint

commit 89ddbddada
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 16:53:18 2022 +0000

    Fixed comment

    Signed-off-by: snipe <snipe@snipe.net>

commit 7498fe36e9
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 16:45:03 2022 +0000

    Removed extra space because pedantry

    Signed-off-by: snipe <snipe@snipe.net>

commit babf7c064b
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 16:38:45 2022 +0000

    Added ability to filter status label index endpoint by status type

    Signed-off-by: snipe <snipe@snipe.net>

commit 40a9470770
Merge: f499dcf7c 781b42601
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 08:54:10 2022 -0700

    Merge pull request #10828 from snipe/fixes/10826_parse_error_on_print_all

    Fixed #10826 - parse error on translation string for print all assets

commit 781b426018
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 08:50:47 2022 -0700

    Fixed #10826 - parse error on translation string for print all assets

    Signed-off-by: snipe <snipe@snipe.net>

commit f499dcf7c3
Merge: 84aa26dd5 54d6a4d97
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 08:25:29 2022 -0700

    Merge pull request #10827 from snipe/fixes/modal_dropdowns_broken

    Fixed #10825 - selectlists in modals b0rked

commit 54d6a4d978
Author: snipe <snipe@snipe.net>
Date:   Wed Mar 16 08:23:50 2022 -0700

    Fixed #10825 - selectlists in modals b0rked

    Signed-off-by: snipe <snipe@snipe.net>

commit 84aa26dd50
Merge: 8984b3a59 14bd07e97
Author: snipe <snipe@snipe.net>
Date:   Thu Mar 10 13:02:45 2022 -0800

    Merge pull request #10728 from Godmartinz/gh10191-css-dropdownmenu

    Fixed #10191 - font color contrast on mobile menu

commit 8984b3a59d
Merge: d06ef4bde cdc0805fc
Author: snipe <snipe@snipe.net>
Date:   Thu Mar 10 10:40:33 2022 -0800

    Merge pull request #10812 from inietov/fixes/CarbonExceptions_InvalidFormatException_DateTime_develop

    Fixes Carbon\Exceptions\InvalidFormatException: DateTime::__construct(): Failed to parse time string develop

commit cdc0805fc4
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Thu Mar 10 12:07:07 2022 -0600

    Sanitize dates input in the importer before saving

commit 14bd07e97d
Merge: 4435ea95f 16fd10954
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Mar 3 10:14:30 2022 -0800

    gerge branchevelop' into gh10191-css-dropdownmenu

commit 4435ea95fd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Mar 3 09:47:11 2022 -0800

    removes changes to mix-manifest

commit f115385243
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Mar 3 09:32:05 2022 -0800

    C&P mix-manifest to be tracked

commit 708dc08b4f
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Feb 23 11:17:44 2022 -0800

    mixes color contrast on dropdown menu from navbar
    on file

Signed-off-by: snipe <snipe@snipe.net>
2022-03-16 20:31:14 +00:00
snipe
9ae2d17579 Minor changes
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 20:06:20 -08:00
snipe
3404b63922 Removed stray echo
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 18:12:23 -08:00
snipe
b1796e6ff2 Make the box header colors different if they are superadmin or admin permisions
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 18:10:54 -08:00
snipe
471527dfc6 Removed unneeded title
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 18:09:57 -08:00
snipe
12c24d7c0f Some jquery fixes
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 17:40:05 -08:00
snipe
5651d060d8 Initial rework of UI for groups
Signed-off-by: snipe <snipe@snipe.net>
2022-03-09 17:10:42 -08:00
snipe
d06ef4bdef Bumped lockfile
Signed-off-by: snipe <snipe@snipe.net>
2022-03-08 22:17:46 -08:00
snipe
c817daa4da Merge pull request #10767 from uberbrady/fix_double_request_datatable
One attempt to fix the 'datatable double-request' problem.
2022-03-08 20:34:15 -08:00
snipe
1b3631d57d Merge pull request #10806 from snipe/fixes/removed_experimental_content_policies
Removed experimental feature policies
2022-03-08 20:32:39 -08:00
snipe
e3d2f7cc96 Missed a few
Signed-off-by: snipe <snipe@snipe.net>
2022-03-08 20:05:17 -08:00
snipe
d1358b6249 Removed experimental feature policies
Signed-off-by: snipe <snipe@snipe.net>
2022-03-08 16:58:24 -08:00
snipe
95d6e1a402 Merge pull request #10805 from inietov/fixes/date_localization_not_working_custom_fields_develop
Fixes #8143 Date localization not work in custom fields for develop branch
2022-03-08 16:36:31 -08:00
Ivan Nieto Vivanco
657cfddd3c Add a condition to show customfields as the user wants in localization settings 2022-03-08 18:28:13 -06:00
snipe
9311584f43 Merge pull request #10033 from uberbrady/ldap_troubleshooter_cherrypicked
Fixed [ch14855] - create LDAP troubleshooter
2022-03-07 20:24:11 -08:00
Brady Wetherington
ab7bf3c5d4 Get rid of stale commented-out line 2022-03-07 20:22:23 -08:00
Brady Wetherington
0556c7653a Implement a generic timeout function, and run methods that need to run with a timeout using it. 2022-03-07 19:51:21 -08:00
Brady Wetherington
b96303cb38 Clean up errors, add new required package to Dockerfile 2022-03-07 19:51:21 -08:00
Brady Wetherington
312a90ce77 Add start of Tracing to LDAP troubleshooter 2022-03-07 19:51:21 -08:00
Brady Wetherington
71b5c0e80f Add new LDAP troubleshoot ldapsearch subcommand, broaden out troubleshooting 2022-03-07 19:51:21 -08:00
Brady Wetherington
519bd00bef WIP - just need to get authed connections to work 2022-03-07 19:51:21 -08:00
Brady Wetherington
ffd8f583b4 Got most of the stages working for the LDAP troubleshooter 2022-03-07 19:51:21 -08:00
Brady Wetherington
8cd5ec6799 Most of the host-port-tls discovery stuff is in-place now 2022-03-07 19:51:20 -08:00
Brady Wetherington
ef0e9a3c93 WIP: Enhancing stage 2 of LDAP troubleshooter 2022-03-07 19:51:20 -08:00
Brady Wetherington
8aa975e959 First pass at Artisan-based LDAP troubleshooter 2022-03-07 19:51:20 -08:00
Brady Wetherington
8d49d35463 Remove another data-toggle="table" - possibly the last one 2022-03-07 12:52:57 -08:00
Brady Wetherington
6f3e9033c2 One attempt to fix the 'datatable double-request' problem. 2022-03-07 12:52:57 -08:00
snipe
0c520476a3 Removed namespace
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 12:30:47 -08:00
snipe
ba010618f7 Throttle got merged out - re-adding it
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 12:15:09 -08:00
snipe
2d7a8b5e15 Merge pull request #10776 from snipe/added_trim_to_email_and_username
Added trim to email and username
2022-03-04 11:57:33 -08:00
snipe
1dabd6cc71 Merge pull request #10777 from snipe/added_remote_to_bulk_user_edit
Add remote user setting to bulk edit
2022-03-04 10:35:07 -08:00
snipe
9a358087ec Add remote user to bulk edit
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 06:47:23 -08:00
snipe
b6a1d245e8 Added trim to CC email as well
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 06:20:34 -08:00
snipe
67134ca387 Do a trim() before inserting/updating
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 06:18:52 -08:00
snipe
0dfc27f56e Added remote to allowed_columns for sorting
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 05:44:46 -08:00
snipe
eb8b4a2aa5 Merge pull request #10775 from snipe/features/add_remote_checkbox_to_user
Added remote checkbox to user
2022-03-04 05:39:23 -08:00
snipe
06a05e6340 Added remote to view
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 05:37:28 -08:00
snipe
43c1949092 Add remote option to user
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 05:35:26 -08:00
snipe
a9069e65e5 Don’t show groups in menu if there are none yet
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 04:39:39 -08:00
snipe
1400c610a1 Use correct button translation
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 04:22:44 -08:00
snipe
67ed0d91c0 Handle file_get_contents more gracefully
Signed-off-by: snipe <snipe@snipe.net>
2022-03-04 02:54:37 -08:00
snipe
349715576a Bumped RC version
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 22:23:24 -08:00
snipe
0d787fcc94 Updated language files
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 22:21:44 -08:00
snipe
b876d0abb0 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.env.example
#	app/Http/Controllers/Auth/LoginController.php
#	app/Http/Kernel.php
#	app/Http/Transformers/ActionlogsTransformer.php
#	app/Importer/AssetImporter.php
#	app/Models/Accessory.php
#	app/Models/Consumable.php
#	app/Presenters/AccessoryPresenter.php
#	app/Presenters/ComponentPresenter.php
#	app/Presenters/ConsumablePresenter.php
#	app/Providers/AuthServiceProvider.php
#	composer.json
#	composer.lock
#	config/app.php
#	config/cors.php
#	config/version.php
#	package-lock.json
#	public/js/build/app.js
#	public/js/build/app.js.LICENSE.txt
#	public/js/dist/all.js
#	public/mix-manifest.json
#	resources/views/accessories/view.blade.php
#	resources/views/consumables/view.blade.php
#	resources/views/settings/saml.blade.php
#	routes/api.php
2022-03-03 21:59:38 -08:00
snipe
afd83311aa Fixed version number (vV)
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:58:54 -08:00
snipe
29a2e80984 Merge pull request #10771 from uberbrady/retry_fix_bad_metadata_display
Retry fix bad metadata display
2022-03-03 20:49:30 -08:00
snipe
fa576bc78f Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:45:34 -08:00
snipe
3e22dce117 Merge pull request #10774 from snipe/features/added_notes_to_accessories_etc
Fixed #6918 - added notes to accessories, components, consumables
2022-03-03 20:41:18 -08:00
snipe
9adcf58ae5 Added notes migration
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:30:58 -08:00
snipe
5266b2c71f Added notes field to view blades
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:30:27 -08:00
snipe
94dded3785 Added notes field to presenters for table view show/hide columns
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:30:07 -08:00
snipe
ac8a7d0bc9 Made notes field fillable and searchable
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:29:48 -08:00
snipe
6fca8350f9 Added notes field to transformers
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:29:35 -08:00
snipe
9acb5413f6 Added notes field to controllers
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 20:29:25 -08:00
snipe
08a2fe4edb Merge pull request #10773 from snipe/features/adds_ldap_import_and_assets_count_to_user_api
Features/adds ldap import and assets count to user api
2022-03-03 19:15:14 -08:00
snipe
6abe8f296b We don’t need the users table here
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 19:12:03 -08:00
snipe
a53a67be4a Added consumables, licenses, accessories count filters too
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 19:08:08 -08:00
snipe
b72cac3511 Adds ldap_import and assets_count filter to user API endpoint
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 19:03:35 -08:00
snipe
698b7301b6 Merge pull request #10772 from snipe/fixes/use_correct_gate_for_maintainances
Use “update” instead of edit in gate
2022-03-03 18:50:33 -08:00
snipe
c940d36fff Updated maintenance gate in API
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 18:49:54 -08:00
snipe
cd12028845 Use “update” instead of edit in gate
Signed-off-by: snipe <snipe@snipe.net>
2022-03-03 18:47:20 -08:00
Brady Wetherington
3225605ef3 Handling the old weirdly-formatted data wasn't quite working. 2022-03-03 18:17:29 -08:00
Brady Wetherington
31dde20a2b Actually, re-introduce this code comment as it's still relevant and tricky 2022-03-03 15:48:04 -08:00
Brady Wetherington
aa36ebc947 Merge branch 'fix_bad_metadata_display' into retry_fix_bad_metadata_display 2022-03-03 15:46:19 -08:00
Brady Wetherington
92434fa943 Revert "Revert "refactor and clean up attribute-changing logic for assets""
This reverts commit bdc737ce0c.
2022-03-03 15:45:54 -08:00
Brady Wetherington
0164354463 Fix for the weird error that blew up the demo when my PR got merged 2022-03-02 15:15:16 -08:00
snipe
bdc737ce0c Revert "refactor and clean up attribute-changing logic for assets"
This reverts commit 290baf1c8d.

Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:45:14 -08:00
snipe
733b3a7550 Merge pull request #10682 from uberbrady/fix_bad_metadata_display
Fixed weird JSON-handling on log_meta updates
2022-03-02 14:36:38 -08:00
snipe
16fd109540 Merge pull request #10417 from inietov/fixes/trying_to_get_property_id_of_nonobject
Fixes trying to get property 'id' of non-object when running develop seeders.
2022-03-02 14:35:53 -08:00
snipe
2b4ee4827f Merge branch 'develop' into fixes/trying_to_get_property_id_of_nonobject 2022-03-02 14:35:35 -08:00
snipe
3339a691e1 Merge pull request #10721 from snipe/features/adds_users_consumables_endpoint
Added consumables endpoint to user API
2022-03-02 14:33:45 -08:00
snipe
dc1e0ecdb7 Merge pull request #10739 from insert-waffle/fixes/prevent_double_values_email
Feature: Prevent showing of double values in a checkin or checkout email
2022-03-02 14:28:22 -08:00
snipe
2eef43e8bf Applies develop fix to master for location drop downs 2022-03-01 12:43:35 -08:00
snipe
5d1cd89838 Merge pull request #10751 from aranar-pro/bug_fix/location-drop-down-#10701
Fix for location and model drop down with granular permissions.
2022-02-28 16:33:12 -08:00
Andrew Roth
74248a4314 removing composer.lock from PR 2022-02-28 19:30:32 -05:00
Andrew Roth
2e60420aeb Fix for location and model drop down with granular permissions. 2022-02-28 17:38:38 -05:00
Jens Maes
9b88f650d2 Prevents showing double values
- If the asset name and tag are the same, the tag does not get shown in an email.
- If the model name is the same as the model number (when importing from LanSweeper for example), do not show the model number.
2022-02-25 08:19:46 +01:00
snipe
336d8e6574 Updated version 2022-02-24 18:17:15 -08:00
snipe
a5c16c6a9c Update @insert-waffle as a contributor 2022-02-24 14:47:48 -08:00
snipe
1ee37212f1 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2022-02-24 14:47:14 -08:00
snipe
ed43d36895 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 14:47:09 -08:00
snipe
d243b822e7 Merge pull request #10729 from insert-waffle/fix-10708
Fixes 10708: removed line height of manufacturer and changed size of fa-hdd to 2x
2022-02-24 14:46:51 -08:00
snipe
dfbff27483 Updated sample CSVs
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 14:19:35 -08:00
snipe
24ce34c8d7 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 14:19:27 -08:00
snipe
7abb1f960c Merge branch 'master' of https://github.com/snipe/snipe-it 2022-02-24 14:16:00 -08:00
snipe
ec7df11d73 Merge pull request #10736 from inietov/fixes/imported_assets_duplicate_model_notes_from_assets_master
Separate notes on assets and asset models on master branch [sc-18810]
2022-02-24 14:15:48 -08:00
snipe
f077d096e2 Merge pull request #10735 from inietov/fixes/imported_assets_duplicate_model_notes_from_assets
Separate notes on assets and asset models [sc-18810]
2022-02-24 14:15:13 -08:00
Ivan Nieto Vivanco
64fa7e23fc Separate notes on assets and asset models 2022-02-24 16:05:03 -06:00
snipe
93ad59466b Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 13:52:33 -08:00
Ivan Nieto Vivanco
577dc6b02c Separate notes on assets and asset models 2022-02-24 15:50:59 -06:00
snipe
4b7f45a15e Merge pull request #10734 from snipe/fixes/api_throttling
Fixed API throttling
2022-02-24 13:43:49 -08:00
snipe
83f21d0ddf Added a comment about why we use the middleware there
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 13:41:16 -08:00
snipe
2906a89442 Make the 429 error less stupid
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 13:10:34 -08:00
snipe
50f55b4308 Fixes broken API throttling
Signed-off-by: snipe <snipe@snipe.net>
2022-02-24 13:10:10 -08:00
Jens Maes
57e93e4e92 Fixes 10708: change size of fa-hdd to 2x 2022-02-24 11:05:40 +01:00
Jens Maes
c0893c44a3 Fixes 10708: Removed line heigt from manufacturer list item. 2022-02-24 10:29:39 +01:00
snipe
a8028e7dd0 Merge pull request #10727 from uberbrady/master
Fix for negative CORS/SAML interaction
2022-02-23 11:17:17 -08:00
Brady Wetherington
15abc84ab0 Migrate to Fruitcake/laravel-cors which has path-exclusion built-in 2022-02-23 11:06:19 -08:00
snipe
8a09211310 Merge pull request #10722 from snipe/features/add_force_saml_to_master
Fixes Restricted Logins to SAML controlled via environment variable #10436 - applies #10449 to master
2022-02-22 21:45:19 -08:00
snipe
42fcd29200 Fixed #10436 on master, applies #10449
Signed-off-by: snipe <snipe@snipe.net>
2022-02-22 21:06:54 -08:00
snipe
dc2e6c2b06 Adds consumables endpoint to user API
Signed-off-by: snipe <snipe@snipe.net>
2022-02-22 20:44:34 -08:00
snipe
0cfc0a4bee Merge pull request #10718 from uberbrady/fix_cors_option_1_master
Fix CORS requests on master (option *ONE*)
2022-02-22 19:24:18 -08:00
snipe
292bf21e7d Merge pull request #10720 from uberbrady/fix_cors_develop
Fix cors develop
2022-02-22 19:23:43 -08:00
Brady Wetherington
294606fb0b Move new CORS library to global middleware, the only place it works 2022-02-22 19:07:23 -08:00
Brady Wetherington
cd2c92fd6c Cors should respect the .env var for CORS domains 2022-02-22 19:00:59 -08:00
Brady Wetherington
64f83f9a5f Move HandleCors middleware to be universal 2022-02-22 17:43:40 -08:00
snipe
6ef053bc52 Merge pull request #10713 from snipe/fixes/error_handler
Added use statement
2022-02-22 10:46:58 -08:00
snipe
0a4a548f9c Added use statement
Signed-off-by: snipe <snipe@snipe.net>
2022-02-22 10:46:02 -08:00
snipe
784bf6f223 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-02-20 13:30:24 -08:00
snipe
dd5f812d88 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	README.md
#	app/Console/Commands/FixDoubleEscape.php
#	app/Console/Commands/LdapSync.php
#	app/Exceptions/Handler.php
#	app/Http/Controllers/Api/AssetMaintenancesController.php
#	app/Http/Controllers/Api/AssetModelsController.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/Api/CategoriesController.php
#	app/Http/Controllers/Api/CompaniesController.php
#	app/Http/Controllers/Api/DepartmentsController.php
#	app/Http/Controllers/Api/LicensesController.php
#	app/Http/Controllers/Api/LocationsController.php
#	app/Http/Controllers/Api/ManufacturersController.php
#	app/Http/Controllers/Api/SettingsController.php
#	app/Http/Controllers/Api/SuppliersController.php
#	app/Http/Controllers/AssetModelsController.php
#	app/Http/Controllers/Auth/LoginController.php
#	app/Http/Controllers/CustomFieldsController.php
#	app/Http/Controllers/SettingsController.php
#	app/Models/Loggable.php
#	app/Providers/AuthServiceProvider.php
#	config/version.php
#	database/migrations/2014_11_04_231416_update_group_field_for_reporting.php
#	database/migrations/2015_11_08_222305_add_ldap_fields_to_settings.php
#	package-lock.json
#	package.json
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
#	resources/assets/js/components/forms/asset-models/fieldset-default-values.vue
#	resources/views/hardware/view.blade.php
2022-02-20 13:29:12 -08:00
snipe
cbfb8283f3 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2022-02-20 11:29:55 -08:00
snipe
dc2b58f865 Merge pull request #10691 from snipe/fixes/update_audit_date_when_settings_update
Fixed #10690 - Initial audit date fix
2022-02-20 11:16:54 -08:00
snipe
34ebc629c2 Remove unusued translation string
Signed-off-by: snipe <snipe@snipe.net>
2022-02-20 11:15:56 -08:00
snipe
21a6bdabc6 Add @insert-waffle as a contributor 2022-02-20 11:12:52 -08:00
snipe
eaf4fefc90 Merge pull request #10700 from insert-waffle/develop
Fixes #10699: Added 2 breaks in message.blade.php
2022-02-20 11:12:20 -08:00
snipe
19b25a39ea Merge pull request #10697 from inietov/features/save_loggedin_user_after_restore
Feature Save logged in user data and re-add them after restore if they don't exist [ch-17664]
2022-02-20 11:11:54 -08:00
Jens Maes
e5f6b48115 🧑‍🔧 Added 2 breaks in message.blade.php
The uploaded logo does not align properly, therefor I added 2 breaks which make sure the site title is BELOW the logo and not next to it.
2022-02-18 10:27:12 +01:00
Ivan Nieto Vivanco
f1ba5c7742 Changed the warning message in the Backups page 2022-02-17 22:47:35 -06:00
Ivan Nieto Vivanco
23a6907975 Some minor stylistic changes 2022-02-17 18:05:06 -06:00
Ivan Nieto Vivanco
5b2a5ff124 Put the 'remember_token' column as null in the users table 2022-02-17 18:03:00 -06:00
Ivan Nieto Vivanco
548b172744 Logout every connected user 2022-02-17 18:00:24 -06:00
Ivan Nieto Vivanco
263893b3c6 Search logged in user that made the restore, if they doesn't exist in the restored system, add it again 2022-02-17 17:42:06 -06:00
Ivan Nieto Vivanco
811ca51c4f Wipe database before restoration 2022-02-17 16:59:44 -06:00
snipe
d1b45a83b8 Blergh, one more linebreak
Signed-off-by: snipe <snipe@snipe.net>
2022-02-17 14:51:06 -08:00
snipe
01a8701a8c Removed extra linebreaks
Signed-off-by: snipe <snipe@snipe.net>
2022-02-17 14:50:38 -08:00
snipe
67fe53e32a Removed debugging, added comments
Signed-off-by: snipe <snipe@snipe.net>
2022-02-17 14:50:07 -08:00
snipe
7f6b8cc43d Removed carbon, since we went with PHP's datetime instead
Signed-off-by: snipe <snipe@snipe.net>
2022-02-17 14:48:12 -08:00
snipe
5fe999eb02 Shored up the date math, updated the explanation
Signed-off-by: snipe <snipe@snipe.net>
2022-02-17 14:34:33 -08:00
snipe
ea429d650e Initial audit date fix
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 20:19:38 -08:00
snipe
a71911eba2 Merge pull request #10688 from snipe/features/add_unique_option_to_custom_fields
Fixes #9592 - Added unique option to custom fields
2022-02-16 16:22:19 -07:00
snipe
13832856f1 Added strings for unique
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:47:59 -08:00
snipe
824eedf7c2 Added UI elements for is_unique
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:47:48 -08:00
snipe
a4a0aa5124 Removed debugging line
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:47:22 -08:00
snipe
6a91d4d19e Check for uniqueness constraint
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:46:22 -08:00
snipe
41778980bc Add migration for is_unique
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:45:59 -08:00
snipe
ea8f9a6dd9 Make is_unique fillable
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 13:45:44 -08:00
snipe
b78f32e876 Merge pull request #10655 from inietov/fixes/trying_to_get_property_checkin_email_of_non-object_develop
Fixes ErrorException: Trying to get property 'checkin_email' of non-object for develop[sc-17568]
2022-02-16 11:19:14 -07:00
snipe
7fe7d56999 Merge pull request #10656 from snipe/snyk-upgrade-0005397ba83c98631126ff98d5471e6d
[Snyk] Upgrade jquery-ui from 1.13.0 to 1.13.1
2022-02-16 11:19:00 -07:00
snipe
592f66bd0c Merge pull request #10670 from Godmartinz/gh10639/linear-depreciation-calculation
Fixed #10639 - incorrect linear depreciation calculation
2022-02-16 11:18:27 -07:00
snipe
4f89dfee49 Merge pull request #10679 from snipe/fixes/timing_attack_mitigation_for_forgot_password
Added usleep random to forgotten password method to mitigate timing attacks
2022-02-16 11:17:00 -07:00
snipe
017534bc07 Added deleted_at to license transformer
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 09:33:28 -08:00
snipe
5540069cce Be more specific with deleted license point
Require this value to be "true" speciically to get the deleted list

Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 09:14:04 -08:00
snipe
e9a4ff8e74 Merge pull request #10683 from snipe/features/add_deleted_only_endpoint_for_licenses
Adds delete endpoint for licenses
2022-02-16 10:10:22 -07:00
snipe
1ad56760ce Adds delete endpoint for licenses
Signed-off-by: snipe <snipe@snipe.net>
2022-02-16 09:08:50 -08:00
snipe
5582949008 Merge pull request #10681 from snipe/fixes/2fa_cookie_fix
Fixes 2FA cookie -> user issue
2022-02-15 19:34:13 -07:00
Brady Wetherington
290baf1c8d refactor and clean up attribute-changing logic for assets 2022-02-15 18:29:45 -08:00
snipe
f878e0ad66 Fixes 2FA cookie -> user issue
Signed-off-by: snipe <snipe@snipe.net>
2022-02-15 18:29:23 -08:00
snipe
178e440951 Added usleep :(
Signed-off-by: snipe <snipe@snipe.net>
2022-02-15 18:09:58 -08:00
snipe
321be4733d Merge pull request #10672 from snipe/fixes/missing_gates_for_maintenances
Added Asset edit/delete gates to maintenances
2022-02-14 15:58:19 -08:00
snipe
cab4fa1687 Fixes some conceptual gates
Signed-off-by: snipe <snipe@snipe.net>
2022-02-14 15:42:23 -08:00
snipe
4804e5b3ab Added Asset edit/delete gates to maintenances
Signed-off-by: snipe <snipe@snipe.net>
2022-02-14 15:34:06 -08:00
Godfrey M
7b9a2ae909 added rounding 2022-02-14 09:34:42 -08:00
Godfrey M
6e204a20ca fixed current value formula 2022-02-14 09:28:35 -08:00
Godfrey M
e6e68934f7 adds a months depreciated variable 2022-02-14 09:13:14 -08:00
Godfrey M
cdc402fa04 WIP formula for linear Depreciation has been corrected. still one variable left to fix. 2022-02-14 09:01:42 -08:00
snipe
885ab64c2e Merge branch 'master' of https://github.com/snipe/snipe-it 2022-02-13 12:01:59 -07:00
snipe
8624531f78 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-02-13 12:01:37 -07:00
snipe
1c0a96b0ce Added gate to supplier
Signed-off-by: snipe <snipe@snipe.net>
2022-02-13 11:58:12 -07:00
snipe
db0c0e7908 Merge pull request #10665 from snipe/fixes/adds_gate_to_supplier_view
Adds gate to supplier
2022-02-13 10:56:55 -08:00
snipe
d77a47765e Adds gate to supplier
Signed-off-by: snipe <snipe@snipe.net>
2022-02-13 11:53:45 -07:00
snipe
05c0819776 Updated language string
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 15:55:42 -08:00
snipe
16f963fa3d Merge branch 'master' of https://github.com/snipe/snipe-it 2022-02-11 13:07:29 -08:00
snipe
e032cf1fda Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 13:07:26 -08:00
snipe
10c26f38c4 Merge pull request #10662 from snipe/fixes/tighter_security_on_select_lists
Added additional gate for selectlists
2022-02-11 12:48:55 -08:00
snipe
d6b8222371 Refactor to combine permissions
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 12:48:30 -08:00
snipe
2c5abaaea4 Fixed copypasta
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 12:32:09 -08:00
snipe
c1a0653847 Restrict to update or create gate methods for select lists
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 12:31:11 -08:00
snipe
9226c8292d Fixed typos in comments
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 12:02:14 -08:00
snipe
5fafa81dc1 Forgot components
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 11:57:29 -08:00
snipe
b30d1dce89 Removed selectlist
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 11:55:24 -08:00
snipe
2dad27eed6 Added additional gate for selectlists
Signed-off-by: snipe <snipe@snipe.net>
2022-02-11 11:46:14 -08:00
snipe
de6f922e54 Fixed migration
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 22:44:46 -08:00
snipe
f5ffda8053 Ahem.
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 22:43:51 -08:00
snipe
99541f0bee Fixed string
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 21:05:23 -08:00
snipe
8b8e93d703 Fixed #10659 - wrong translation string reference
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 21:03:09 -08:00
snipe
5703b95de3 Merge pull request #10657 from snipe/fixes/handle_deleted_auditor
Fixed - Check for valid user before trying to present the auditor name
2022-02-10 20:14:24 -08:00
snipe
d406dc43c2 Check for valid user before trying to present the auditor name
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 20:13:02 -08:00
snipe
2ce44bd4e6 Line break for easier debugging
Signed-off-by: snipe <snipe@snipe.net>
2022-02-10 20:06:55 -08:00
snyk-bot
15b96f304b fix: upgrade jquery-ui from 1.13.0 to 1.13.1
Snyk has created this PR to upgrade jquery-ui from 1.13.0 to 1.13.1.

See this package in npm:
https://www.npmjs.com/package/jquery-ui

See this project in Snyk:
https://app.snyk.io/org/snipe/project/3d53e1dd-b8bf-46b5-ba61-18ce26933166?utm_source=github&utm_medium=referral&page=upgrade-pr
2022-02-11 01:11:13 +00:00
snipe
ed931ef0cd Merge pull request #10654 from inietov/fixes/trying_to_get_property_checkin_email_of_non-object
Fixes  ErrorException: Trying to get property 'checkin_email' of non-object [sc-17568]
2022-02-10 12:23:50 -08:00
Ivan Nieto Vivanco
f36de6c670 Validates if model and model->category exist before return the checkin_email property 2022-02-10 13:53:49 -06:00
Ivan Nieto Vivanco
bf4ee18123 Validates if model and model->category exist before return the checkin_email property 2022-02-10 11:58:55 -06:00
snipe
70af10ae6c Merge pull request #10640 from JonathonReinhart/10552-add-checkin-api-date
Fix #10552: Add checkin_at parameter to /hardware/:id/checkin API
2022-02-10 09:54:20 -08:00
snipe
9892e5bf60 Merge pull request #10646 from snipe/fixes/check_field_exist_before_detaching
Check that the field exists before trying to detach it from the fieldset
2022-02-09 16:33:02 -08:00
snipe
b9a8d45c07 Better messaging
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 16:30:42 -08:00
snipe
7794c2f44b Check that the fieldset exists before trying to detach it from the fieldset
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 16:16:16 -08:00
snipe
eedc14401a Switch to searching on semicolon instead of &
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 15:55:22 -08:00
snipe
4e14d70427 Added jobtitle to unescaper
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 15:50:44 -08:00
snipe
2a71690aaf Added license_name to unescaper
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 15:17:57 -08:00
snipe
e4da00ca82 Catch potential validation errors on unescape tool
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 15:09:49 -08:00
snipe
4fd14e5859 Added slightly more output because wtf?
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 15:05:28 -08:00
snipe
441f1fbb64 Remove html_entities_decode restriction
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 14:56:36 -08:00
snipe
bf194d7794 Regenerate JS assets
Signed-off-by: snipe <snipe@snipe.net>
2022-02-09 14:43:30 -08:00
snipe
d06e3dd892 Merge branch 'master' of https://github.com/snipe/snipe-it 2022-02-09 14:40:33 -08:00
snipe
6b25b53462 Merge pull request #10628 from inietov/fixes/default_values_dont_allow_checkbox_radio
Fixes #10299 Default Values do not allow Checkbox/Radio Buttons
2022-02-09 14:39:46 -08:00
Ivan Nieto Vivanco
6d79c9f3e2 Save the default values for custom fields with same format than Assets do for actual values 2022-02-09 13:41:33 -06:00
Ivan Nieto Vivanco
a36957dd77 Finish the implementation of custom fields default values for checkboxes 2022-02-09 13:12:42 -06:00
Ivan Nieto Vivanco
2f3499e4b9 Show checkboxes a little less assy, actually save the data checked by them 2022-02-09 10:49:10 -06:00
Jonathon Reinhart
3536d08477 Add checkin_at parameter to /hardware/:id/checkin API
Fixes #10552
2022-02-08 20:23:09 -05:00
snipe
ee3166cdc2 Add @savornicesei as a contributor 2022-02-08 15:38:20 -08:00
snipe
2852359225 Merge pull request #10638 from uberbrady/report_invalid_json_develop
Report invalid json develop
2022-02-08 12:27:29 -08:00
Brady Wetherington
c300e7c7f6 Remove extraneous backslash 2022-02-08 12:23:15 -08:00
Brady Wetherington
fb890fbc30 Properly alert when invalid JSON is submitted to something that wants JSON 2022-02-08 12:22:59 -08:00
snipe
7a117a22c8 Merge pull request #10637 from uberbrady/report_invalid_json
Alert when invalid JSON is submitted to something that wants it
2022-02-08 12:17:20 -08:00
Brady Wetherington
9a66f6a254 Remove extraneous backslash 2022-02-08 12:09:40 -08:00
Brady Wetherington
5e94726ec1 Properly alert when invalid JSON is submitted to something that wants JSON 2022-02-08 12:05:05 -08:00
snipe
66c3559e1c Merge pull request #10636 from inietov/fixes/inconsistencies_between_checkout_checkin_dates_master
Fixes #10627 Inconsistencies between checkout/checkin dates on asset history and activity log for master branch
2022-02-08 10:19:16 -08:00
snipe
ad52f9df72 Merge pull request #10635 from inietov/fixes/inconsistencies_between_checkout_checkin_dates
Fixes #10627 Inconsistencies between checkout/checkin dates on asset history and activity log
2022-02-08 10:18:52 -08:00
Ivan Nieto Vivanco
413e44be2f Add custom date to checkin actionlogs and show it in the history of the asset tab 2022-02-08 11:58:23 -06:00
Ivan Nieto Vivanco
d71aa859fc Add custom date to checkin actionlogs and show it in the history of the asset tab 2022-02-08 11:43:24 -06:00
snipe
ebc35c4519 Merge pull request #10630 from JonathonReinhart/10629-checkin-API-error-status
Fix /hardware/{id}/checkin API response on error
2022-02-08 08:54:17 -08:00
Jonathon Reinhart
cd963179fd Fix /hardware/{id}/checkin API response on error
Fixes #10629
2022-02-08 01:08:42 -05:00
Ivan Nieto Vivanco
796a0ebdaa Add initial support for default values in checkboxes customfields 2022-02-07 22:17:40 -06:00
snipe
474f24e40e Merge branch 'master' of https://github.com/snipe/snipe-it 2022-02-07 18:27:59 -08:00
snipe
b3a0f86431 Temp fix for weird JSON format in history
Signed-off-by: snipe <snipe@snipe.net>
2022-02-07 18:27:55 -08:00
snipe
959074f836 Merge pull request #10625 from inietov/fixes/checkin_checkout_api_routes_broken
Fixes #10614 Checkin/Checkout API route's broken
2022-02-07 11:56:48 -08:00
Ivan Nieto Vivanco
b4d2b1322f Pass ID of the checkin/checkout assets in API 2022-02-07 13:43:13 -06:00
snipe
a77c51c5f2 Merge pull request #10624 from uberbrady/develop_fix_secure_hosts_in_subdirectory
(Develop) fix secure hosts in subdirectory
2022-02-07 11:41:33 -08:00
Brady Wetherington
a15c0adc79 Fix "secure hostnames" feature for subdirectory-based Snipe-IT installs 2022-02-07 11:33:38 -08:00
snipe
1a31231569 Merge pull request #10623 from uberbrady/fix_secure_hosts_in_subdirectory
Fixes #10577 - Fix "secure hostnames" feature for subdirectory-based Snipe-IT installs
2022-02-07 11:33:33 -08:00
Brady Wetherington
f1d4087317 Fix "secure hostnames" feature for subdirectory-based Snipe-IT installs 2022-02-07 11:26:54 -08:00
snipe
f2b8091b31 Merge pull request #10622 from Godmartinz/bug/sc-18678/add-required-field-marker-to-default-currency
Fixed Bug/sc 18678/add required field marker to default currency
2022-02-07 10:34:27 -08:00
Godfrey M
67882f5531 Removed untracked fileseetvert "adding untracked files"
This reverts commit 9d0b163c11.
2022-02-07 10:23:24 -08:00
Godfrey M
5a70bba51b changed model for default currency requirement check 2022-02-07 09:51:35 -08:00
Godfrey M
9d0b163c11 adding untracked files 2022-02-07 08:58:49 -08:00
snipe
f4069e00cd Merge pull request #10611 from uberbrady/master
D'oh! Migration fails on empty settings table :(
2022-02-03 20:07:01 -08:00
Brady Wetherington
8650faf0d8 D'oh! Migration fails on empty settings table :( 2022-02-03 20:04:33 -08:00
snipe
796ef741e8 Merge pull request #10610 from uberbrady/fixes/ldap_active_status
Fixes #10563 - Rework the LDAP sync command to better handle the active flag
2022-02-03 19:45:41 -08:00
Brady Wetherington
36ae6f9430 Yanked debugging code, tightened up comments. 2022-02-03 19:41:16 -08:00
Brady Wetherington
1945b97b72 Just trying to really tighten up on the LDAP Active Flag and how we parse it. 2022-02-03 19:04:56 -08:00
Brady Wetherington
392e61688d Rework the LDAP sync command to better handle the active flag 2022-02-03 15:01:45 -08:00
snipe
db82e06665 Fixed migration with invalid LDAP prepopulation value
Signed-off-by: snipe <snipe@snipe.net>
2022-02-02 18:22:51 -08:00
snipe
ac5c6123bc Fixes #10563 - LDAP active flag - hopefully?
Signed-off-by: snipe <snipe@snipe.net>
2022-02-02 18:07:34 -08:00
snipe
8add47739e Merge pull request #10604 from inietov/fixes/column_activated_cannot_be_null
Fixes: Column activated cannot be null [sc-18528]
2022-02-02 12:21:31 -08:00
snipe
c0cc90066f Merge pull request #10605 from inietov/fixes/column_activated_cannot_be_null_develop
Fixes: Column activated cannot be null for develop [sc-18528]
2022-02-02 12:16:39 -08:00
Ivan Nieto Vivanco
fa2f8409f9 Add a casting to a truthy/falsy that needs to be integer 2022-02-02 14:09:23 -06:00
Ivan Nieto Vivanco
eac8e0bdba Add a casting to a truthy/falsy that needs to be integer 2022-02-02 13:54:57 -06:00
snipe
ce154a2382 Merge pull request #10455 from adagioajanes/features/quickscan_checkin
Added #10454: Quick Scan Checkin
2022-02-01 20:19:45 -08:00
snipe
06a5ea1530 Fixed duplicate use statement
Signed-off-by: snipe <snipe@snipe.net>
2022-02-01 18:57:45 -08:00
snipe
99c4fd8f84 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2022-02-01 18:56:18 -08:00
snipe
d2655c1092 Bumped RC version
Signed-off-by: snipe <snipe@snipe.net>
2022-02-01 18:54:46 -08:00
snipe
5fded57ec6 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	README.md
#	app/Console/Commands/LdapSync.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/ProfileController.php
#	app/Importer/ItemImporter.php
#	app/Importer/UserImporter.php
#	app/Models/Asset.php
#	app/Models/License.php
#	app/Providers/AppServiceProvider.php
#	app/Services/LdapAd.php
#	config/version.php
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
#	resources/lang/ar/button.php
#	resources/lang/de/admin/companies/general.php
#	resources/lang/de/admin/custom_fields/general.php
#	resources/lang/de/admin/groups/titles.php
#	resources/lang/de/admin/hardware/form.php
#	resources/lang/de/admin/hardware/general.php
#	resources/lang/de/admin/hardware/message.php
#	resources/lang/de/admin/hardware/table.php
#	resources/lang/de/admin/kits/general.php
#	resources/lang/de/admin/locations/table.php
#	resources/lang/de/admin/reports/general.php
#	resources/lang/de/admin/settings/general.php
#	resources/lang/de/admin/settings/message.php
#	resources/lang/de/admin/users/general.php
#	resources/lang/de/general.php
#	resources/lang/de/mail.php
#	resources/lang/en/admin/asset_maintenances/message.php
#	resources/lang/en/admin/asset_maintenances/table.php
#	resources/lang/en/admin/companies/general.php
#	resources/lang/en/admin/companies/message.php
#	resources/lang/en/admin/custom_fields/general.php
#	resources/lang/en/admin/depreciations/general.php
#	resources/lang/en/admin/groups/titles.php
#	resources/lang/en/admin/hardware/form.php
#	resources/lang/en/admin/hardware/general.php
#	resources/lang/en/admin/hardware/table.php
#	resources/lang/en/admin/kits/general.php
#	resources/lang/en/admin/locations/table.php
#	resources/lang/en/admin/reports/general.php
#	resources/lang/en/admin/settings/general.php
#	resources/lang/en/admin/settings/message.php
#	resources/lang/en/admin/users/general.php
#	resources/lang/en/button.php
#	resources/lang/en/general.php
#	resources/lang/en/help.php
#	resources/lang/en/mail.php
#	resources/lang/en/passwords.php
#	resources/lang/hu/admin/hardware/general.php
#	resources/lang/hu/admin/hardware/table.php
#	resources/lang/hu/admin/locations/table.php
#	resources/lang/is/admin/locations/table.php
#	resources/lang/ko/admin/custom_fields/general.php
#	resources/lang/ko/general.php
#	resources/lang/nl/admin/hardware/general.php
#	resources/lang/nl/admin/hardware/message.php
#	resources/lang/nl/admin/hardware/table.php
#	resources/lang/nl/admin/locations/table.php
#	resources/lang/nl/admin/statuslabels/message.php
#	resources/lang/nl/admin/users/general.php
#	resources/lang/no/admin/companies/general.php
#	resources/lang/no/admin/custom_fields/general.php
#	resources/lang/no/admin/depreciations/general.php
#	resources/lang/no/admin/depreciations/table.php
#	resources/lang/no/admin/groups/titles.php
#	resources/lang/no/admin/hardware/form.php
#	resources/lang/no/admin/hardware/general.php
#	resources/lang/no/admin/hardware/table.php
#	resources/lang/no/admin/kits/general.php
#	resources/lang/no/admin/locations/table.php
#	resources/lang/no/admin/reports/general.php
#	resources/lang/no/admin/settings/general.php
#	resources/lang/no/admin/settings/message.php
#	resources/lang/no/admin/statuslabels/message.php
#	resources/lang/no/admin/users/general.php
#	resources/lang/no/button.php
#	resources/lang/no/general.php
#	resources/lang/no/mail.php
#	resources/lang/no/validation.php
#	resources/lang/pl/admin/companies/general.php
#	resources/lang/pl/admin/custom_fields/general.php
#	resources/lang/pl/admin/depreciations/general.php
#	resources/lang/pl/admin/depreciations/table.php
#	resources/lang/pl/admin/groups/titles.php
#	resources/lang/pl/admin/hardware/form.php
#	resources/lang/pl/admin/hardware/general.php
#	resources/lang/pl/admin/hardware/table.php
#	resources/lang/pl/admin/kits/general.php
#	resources/lang/pl/admin/locations/table.php
#	resources/lang/pl/admin/reports/general.php
#	resources/lang/pl/admin/settings/general.php
#	resources/lang/pl/admin/settings/message.php
#	resources/lang/pl/admin/users/general.php
#	resources/lang/pl/button.php
#	resources/lang/pl/general.php
#	resources/lang/pt-PT/admin/companies/general.php
#	resources/lang/pt-PT/admin/custom_fields/general.php
#	resources/lang/pt-PT/admin/depreciations/general.php
#	resources/lang/pt-PT/admin/depreciations/table.php
#	resources/lang/pt-PT/admin/groups/titles.php
#	resources/lang/pt-PT/admin/hardware/form.php
#	resources/lang/pt-PT/admin/hardware/general.php
#	resources/lang/pt-PT/general.php
#	resources/lang/pt-PT/help.php
#	resources/lang/pt-PT/validation.php
#	resources/lang/ro/admin/companies/general.php
#	resources/lang/ro/admin/custom_fields/general.php
#	resources/lang/ro/admin/groups/titles.php
#	resources/lang/ro/admin/hardware/form.php
#	resources/lang/ro/admin/hardware/general.php
#	resources/lang/ro/admin/hardware/message.php
#	resources/lang/ro/admin/hardware/table.php
#	resources/lang/ro/admin/locations/table.php
#	resources/lang/ro/admin/settings/message.php
#	resources/lang/ru/admin/companies/general.php
#	resources/lang/ru/admin/custom_fields/general.php
#	resources/lang/ru/admin/settings/general.php
#	resources/lang/ru/button.php
#	resources/lang/ru/general.php
#	resources/lang/ru/validation.php
#	resources/lang/sk/admin/settings/general.php
#	resources/lang/sk/button.php
#	resources/lang/sk/general.php
#	resources/lang/tr/admin/hardware/form.php
#	resources/lang/tr/admin/hardware/table.php
#	resources/lang/tr/admin/kits/general.php
#	resources/lang/tr/admin/locations/table.php
#	resources/lang/tr/admin/reports/general.php
#	resources/lang/tr/admin/settings/general.php
#	resources/lang/tr/admin/settings/message.php
#	resources/lang/tr/admin/statuslabels/message.php
#	resources/lang/tr/admin/users/general.php
#	resources/lang/tr/button.php
#	resources/lang/tr/general.php
#	resources/lang/zh-CN/admin/companies/general.php
#	resources/lang/zh-CN/admin/custom_fields/general.php
#	resources/lang/zh-CN/admin/depreciations/general.php
#	resources/lang/zh-CN/admin/depreciations/table.php
#	resources/lang/zh-CN/admin/groups/titles.php
#	resources/lang/zh-CN/admin/hardware/form.php
#	resources/lang/zh-CN/admin/hardware/general.php
#	resources/lang/zh-CN/admin/hardware/message.php
#	resources/lang/zh-CN/admin/hardware/table.php
#	resources/lang/zh-CN/admin/kits/general.php
#	resources/lang/zh-CN/admin/locations/table.php
#	resources/lang/zh-CN/admin/reports/general.php
#	resources/lang/zh-CN/admin/settings/general.php
#	resources/lang/zh-CN/admin/settings/message.php
#	resources/lang/zh-CN/admin/statuslabels/message.php
#	resources/lang/zh-CN/admin/users/general.php
#	resources/lang/zh-CN/button.php
#	resources/lang/zh-CN/general.php
#	resources/lang/zh-CN/mail.php
#	resources/views/depreciations/edit.blade.php
2022-02-01 18:53:05 -08:00
snipe
2815e0d36e Fixed audit email template (applies #10592 to master)
Signed-off-by: snipe <snipe@snipe.net>
2022-02-01 17:27:32 -08:00
snipe
cda13f69ae Merge pull request #10592 from uberbrady/fix_upcoming_audits_email
Fixed markdown upcoming audits email table
2022-02-01 17:25:46 -08:00
snipe
669826f6b2 Merge pull request #10574 from uberbrady/fix_force_root_url_v6
Add some guardrails around very-badly formatted APP_URL settings
2022-02-01 16:14:48 -08:00
snipe
a7d34dfb19 Merge pull request #10579 from misilot/fix-10176-webui
Replace .my.cnf with column-statistics.cnf at the system level for mysqldump
2022-02-01 16:14:37 -08:00
snipe
8083ba8dca Merge pull request #10590 from inietov/fixes/bulkedit_does_not_show_in_history_develop
Fixes Bulk edit doesn't show in Asset's history nor Activity report for develop [sc-16550]
2022-02-01 16:14:25 -08:00
snipe
237bc22a5c Merge pull request #10591 from uberbrady/allow_invalid_app_urls_develop
Allow invalid app urls develop
2022-02-01 14:17:08 -08:00
Brady Wetherington
eaba560877 We had a markdown failure in the upcoming audits table, this fixes it. 2022-02-01 14:06:01 -08:00
snipe
2e998b110f Add @TenOfTens as a contributor 2022-02-01 13:40:31 -08:00
Brady Wetherington
f70c238b1c Merge remote-tracking branch 'upstream/develop' into develop 2022-02-01 11:53:33 -08:00
Ivan Nieto Vivanco
3ef775533a Adds actionlog for bulk edits 2022-02-01 12:10:46 -06:00
snipe
b9d6708181 Merge pull request #10588 from TenOfTens/develop
Typo found in snipeit/routes/api.php @ line 391
2022-02-01 07:21:08 -08:00
TenOfTens
70eeafd2a3 Update api.php
Typo at line 391 GroupsCOntroller to GroupsController. Was causing an error with the groups view not reflecting the actual groups seen from the database.
2022-02-01 08:51:34 -06:00
snipe
f45c963428 Merge pull request #10586 from inietov/fixes/bulkedit_does_not_show_in_history
Fixes Bulk edit doesn't show in Asset's history nor Activity report [sc-16550]
2022-01-31 23:07:02 -08:00
Ivan Nieto Vivanco
2fec40d7df Adds actionlog for bulk edits 2022-02-01 00:00:12 -06:00
Brady Wetherington
72e9360228 Merge remote-tracking branch 'upstream/develop' into develop 2022-01-31 10:13:30 -08:00
snipe
215beb9d8a Merge pull request #10580 from misilot/fix-10176-webui-master
Replace .my.cnf with column-statistics.cnf at the system level for mysqldump (master)
2022-01-29 07:16:24 -08:00
Tom Misilo
b0c61ee044 Replace .my.cnf with column-statistics.cnf at the system level for mysqldump
Fixes #10176

The `column-statistics.cnf` file is copied to `/etc/mysql/conf.d/column-statistics.cnf` for each Dockerfile that exists.

This puts it as a system level mysql client change, so the web ui interface also works.
2022-01-29 07:28:12 -06:00
Tom Misilo
fb585955b4 Replace .my.cnf with column-statistics.cnf at the system level for mysqldump
Fixes #10176

The `column-statistics.cnf` file is copied to `/etc/mysql/conf.d/column-statistics.cnf` for each Dockerfile that exists.

This puts it as a system level mysql client change, so the web ui interface also works.
2022-01-29 07:24:50 -06:00
snipe
16fb2213b5 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2022-01-28 12:40:03 -08:00
snipe
a0d0645453 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-01-28 12:38:42 -08:00
snipe
1ef336a08b Merge pull request #10576 from snipe/features/add_custom_fields_search
Added #9576 - Lookup Asset by Custom Field via API [sc-18632]
2022-01-28 09:51:28 -08:00
snipe
aa3aa78204 Adds Lookup Asset by Custom Field via API [sc-18632]
Signed-off-by: snipe <snipe@snipe.net>
2022-01-28 09:08:48 -08:00
snipe
db0a078c0b Merge pull request #10573 from uberbrady/fix_force_root_url
Add some guardrails around very-badly formatted APP_URL settings
2022-01-27 11:29:29 -08:00
Brady Wetherington
44719e3dcc Fix whitespace issues 2022-01-27 11:29:20 -08:00
Brady Wetherington
1cf1278b3b Fix whitespace issues 2022-01-27 11:28:51 -08:00
Brady Wetherington
476075235a Add some guardrails around very-badly formatted APP_URL settings 2022-01-27 11:24:21 -08:00
Brady Wetherington
70648dedd3 Add some guardrails around very-badly formatted APP_URL settings 2022-01-27 11:21:46 -08:00
snipe
a65fb63b6b Merge pull request #10511 from inietov/features/audit_date_in_importer
Adds audit dates in the asset importer
2022-01-27 10:58:53 -08:00
snipe
9634dde0dd Merge pull request #10567 from inietov/fixes/importing_and_checking_out_licenses_master
Fixes Importing licenses without product key duplicates the license
2022-01-27 10:58:06 -08:00
snipe
0eab249819 Merge pull request #10569 from inietov/fixes/donked_layout_required_field_error_depreciation_develop
Fixes donked layout required field error depreciation in develop[sc-17111]
2022-01-27 10:57:33 -08:00
snipe
077caa29f8 Merge pull request #10570 from inietov/fixes/donked_layout_required_field_error_depreciation
Fixes donked layout required field error depreciation [sc-17111]
2022-01-26 21:23:51 -08:00
Ivan Nieto Vivanco
a87478d3ac Set the actual field we are evaluating as required (months) 2022-01-26 23:02:27 -06:00
Ivan Nieto Vivanco
34819ec5cf Fixes the appearance of some error messages 2022-01-26 23:00:52 -06:00
Ivan Nieto Vivanco
44349db597 Fixes the appearance of some error messages 2022-01-26 22:58:02 -06:00
snipe
c70ae19c28 Merge pull request #10529 from uberbrady/fix_insecure_host_headers
Force UrlGenerator's Root URL to be the base of APP_URL unless overriden (v5)
2022-01-26 16:59:55 -08:00
snipe
b153138d1e Merge pull request #10534 from inietov/feature/add_remaining_address_field_to_user_import_develop
Add Zip field in the User Importer for develop [sc-18556]
2022-01-26 16:58:37 -08:00
snipe
d0b90bdff9 Merge pull request #10568 from inietov/fixes/importing_and_checking_out_licenses
Fixes Importing licenses without product key duplicates the license for develop branch
2022-01-26 16:30:00 -08:00
Ivan Nieto Vivanco
55fdc86e02 Tweak query in the License Importer to not require a Product Key 2022-01-26 17:51:04 -06:00
Ivan Nieto Vivanco
450cb8f92f Tweak query in the License Importer to not require a Product Key 2022-01-26 17:49:34 -06:00
snipe
8ebade7892 Merge pull request #10566 from inietov/fixes/cant_add_customfield_to_fieldset
Fix #10564: Edit the route to associate custom fields with fieldsets
2022-01-26 13:02:26 -08:00
Ivan Nieto Vivanco
fcd203f4dc Fix the route to associate custom fields with fieldsets 2022-01-26 14:43:20 -06:00
Brady Wetherington
48f1380f6e Merge pull request #10528 from uberbrady/fix_insecure_host_headers_v6
Force UrlGenerator's Root URL to be the base of APP_URL unless overriden
2022-01-24 18:26:30 -08:00
snipe
eade041b6e Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2022-01-21 12:33:53 -08:00
snipe
ee47a02792 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2022-01-21 12:33:49 -08:00
snipe
8813f55770 Merge pull request #10545 from inietov/fixes/unable_to_add_asset_model
Fixes #10536 Unable to add asset model (v6.0.0-RC-1)
2022-01-21 10:13:10 -08:00
Ivan Nieto Vivanco
7383ec7f1e Add an early return if the model id is not set (for new Asset Models) 2022-01-21 11:45:45 -06:00
snipe
0721ab8bbf Regenerated production assets
Signed-off-by: snipe <snipe@snipe.net>
2022-01-20 11:01:04 -08:00
snipe
00c8a1ee21 Merge pull request #10533 from inietov/feature/add_remaining_address_field_to_user_import
Add Zip field in the User Importer [sc-18556]
2022-01-19 12:07:18 -08:00
Ivan Nieto Vivanco
c86ed892ab Add Zip field in the User Importer 2022-01-19 13:52:15 -06:00
Ivan Nieto Vivanco
1fc71a4111 Add Zip field in the User Importer 2022-01-19 13:35:54 -06:00
Brady Wetherington
0c4768fd2a Force UrlGenerator's Root URL to be the base of APP_URL unless overriden
(For v5)
2022-01-18 15:52:59 -08:00
Brady Wetherington
455bc736be Force UrlGenerator's Root URL to be the base of APP_URL unless overriden 2022-01-18 15:31:30 -08:00
snipe
a26119c262 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2022-01-18 14:50:35 -08:00
snipe
e7541f29d2 Use php artisan serve url
Signed-off-by: snipe <snipe@snipe.net>
2022-01-18 14:50:24 -08:00
snipe
f9647614ab Merge pull request #10527 from inietov/fixes/pdo_exception_syntax_error_when_sendexpirationalers_is_called
Fixes PDO exeception syntax error when Expiring Alerts Threshold is not set
2022-01-18 12:43:08 -08:00
Ivan Nieto Vivanco
a05795420a Respect the default value of 60 days in expiring licenses 2022-01-18 14:34:14 -06:00
Ivan Nieto Vivanco
42d86bf57b Adds default values if the expiring alerts threshold is null 2022-01-18 14:21:49 -06:00
snipe
201b52baf8 Merge pull request #10523 from inietov/fixes/depreciation_report_shows_assets_that_not_deprecate_master
Fixes bug where the depreciation report shows assets that not deprecate for master
2022-01-18 10:37:21 -08:00
snipe
c8c559784d Merge pull request #10522 from inietov/fixes/depreciation_report_shows_assets_that_not_deprecate
Fixes bug where the depreciation report shows assets that not depreciate
2022-01-15 12:23:58 -08:00
Ivan Nieto Vivanco
f510b9c2a9 Add query to filter non-deprecable assets when the Depreciation Report is called 2022-01-15 14:21:31 -06:00
Ivan Nieto Vivanco
8334ed6f7e Add query to filter non-deprecable assets when the Depreciation Report is called 2022-01-15 14:01:19 -06:00
Ivan Nieto Vivanco
9ae03f21dc Adds condition to only charge custom field's livewire when the model is updated 2022-01-15 12:14:34 -06:00
Ivan Nieto Vivanco
92b3576395 Fixes a route definition to correctly populate the deprecation report 2022-01-15 12:02:43 -06:00
snipe
6d96f96615 Merge pull request #10520 from inietov/fixes/sc-14356/importer_creating_duplicate_asset_models
Fixes an issue where importer is creating duplicate asset models
2022-01-15 07:47:36 -08:00
snipe
75bd365ca1 Merge pull request #10521 from inietov/fixes/sc-14356/importer_creating_duplicate_asset_models_master
Fixes an issue where importer is creating duplicate asset models for Master Branch
2022-01-15 07:46:39 -08:00
Ivan Nieto Vivanco
153c30eda8 Add to Importer the capacity to search Models only with Model Name since Model Number is not required 2022-01-15 04:32:47 -06:00
Ivan Nieto Vivanco
58b1db29e2 Adds condition to only update the Asset's Model Number if is provided by import file 2022-01-15 04:15:38 -06:00
Ivan Nieto Vivanco
8bd280b416 Add to Importer the capacity to search Models only with Model Name since Model Number is not required 2022-01-15 04:12:30 -06:00
Ivan Nieto Vivanco
d5f6f6cafe Fixes duplicate API endpoint that returns fieldsets instead of customfields 2022-01-15 03:46:28 -06:00
snipe
b9cc0c9d4c Merge pull request #10519 from uberbrady/request_pending_assets
Make 'pending' assets properly requestable; use requestable scope
2022-01-14 13:07:16 -08:00
Brady Wetherington
ef463a37d8 Make 'pending' assets properly requestable; use requestable scope 2022-01-14 12:48:33 -08:00
snipe
cfb64be9a4 More specific RC version number
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 21:41:04 -08:00
snipe
91017aed52 Bumped to RC-1
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 21:38:10 -08:00
snipe
af2e407543 Normalize array format in en language to the new shitty way
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 21:30:35 -08:00
snipe
ddfa5776c5 Updated language strings
This absolutely sucks. Something changed in CrowdIn or something else, which results in this push being *thousands* of files because someone somewhere decided that `return [];` was vastly inferior to `return array();`

I'll try to fix it. :(

FML

Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 21:27:29 -08:00
snipe
da47f62d17 Added strings
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 21:20:38 -08:00
snipe
207ff014b1 Merge pull request #10514 from uberbrady/fix_double_wildcard_query_requestable
Fixed extraneous wildcard query in requestable asset search
2022-01-13 19:39:08 -08:00
Brady Wetherington
65e584c2bd Revert the unnecessary optimization for asset->count() 2022-01-13 19:37:08 -08:00
snipe
591e1c6a9d Merge pull request #10512 from uberbrady/fix_asset_acceptance_routing_bug
Duplicate route meant overwrite of route-name
2022-01-13 17:08:26 -08:00
snipe
24a234ede3 Merge pull request #10503 from uberbrady/develop_fix_dont_req_preauth_uac
Permit DONT_REQ_PREAUTH AD users to log in
2022-01-13 17:01:59 -08:00
snipe
be7e6ed847 Merge pull request #10502 from uberbrady/ldap_useraccountcontrol_dont_req_preauth
Add new UserAccountControl to permitted UAC's for AD.
2022-01-13 17:01:47 -08:00
Brady Wetherington
4e8ae8a162 Fix extraneous wildcard query in requestable asset search 2022-01-13 16:32:40 -08:00
Brady Wetherington
c527a5c6e7 Duplicate route meant overwrite of route-name 2022-01-13 16:03:32 -08:00
snipe
115109f612 Merge pull request #10510 from misilot/fix-10176-master
Looks great, thanks!
2022-01-13 13:22:22 -08:00
Thomas Misilo
037a912e21 Adding .my.cnf to disable column-statistics backup
Fixes #10176

The ```.my.cnf``` file is copied to ```/root/.my.cnf``` for each
Dockerfile that exists
2022-01-13 15:16:59 -06:00
Ivan Nieto Vivanco
949fe2a14a Adds last_audit_date and next_audit_date in the asset importer 2022-01-13 15:14:20 -06:00
snipe
4e3fd6bfaf Merge pull request #10509 from misilot/fix-10176
Adding .my.cnf to disable column-statistics backup
2022-01-13 13:13:54 -08:00
Thomas Misilo
930666ffa0 Adding .my.cnf to disable column-statistics backup
Fixes #10176

The ```.my.cnf``` file is copied to ```/root/.my.cnf``` for each
Dockerfile that exists
2022-01-13 14:36:00 -06:00
snipe
984db1ef44 Apply personal API token fix to master
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 01:39:56 -08:00
snipe
0e5ef53c35 Merge pull request #10504 from snipe/fixes/auth_controls_on_api_key_creation
Fixes auth controls on api key creation
2022-01-13 01:36:52 -08:00
snipe
512dbfee7a Added gate to check that the user is allowed to view API keys
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 01:33:27 -08:00
snipe
eb8f23a888 Removed commented code
Signed-off-by: snipe <snipe@snipe.net>
2022-01-13 01:32:28 -08:00
snipe
8f4ec95fbb Remove assets query, since we handle that via API call now and just need the count()
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 23:23:00 -08:00
snipe
67ba8a6281 Removed extra spaces
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 23:18:39 -08:00
snipe
9368ddeaf0 Added badge count on requestable assets
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 23:17:54 -08:00
snipe
f206d4ed4e Fixed double div in current purchase value
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 22:26:56 -08:00
snipe
224d0b2fd2 Small language file additions
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 22:21:00 -08:00
snipe
ae50f86c39 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 20:52:30 -08:00
snipe
43c57c8461 Merge master into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	README.md
#	app/Http/Controllers/BulkAssetModelsController.php
#	app/Http/Controllers/CustomFieldsController.php
#	app/Http/Controllers/CustomFieldsetsController.php
#	app/Http/Controllers/ModalController.php
#	app/Http/Transformers/GroupsTransformer.php
#	config/version.php
#	package-lock.json
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
#	resources/assets/less/overrides.less
#	resources/lang/en/admin/hardware/message.php
#	resources/lang/en/admin/settings/general.php
#	resources/views/partials/bootstrap-table.blade.php
#	routes/web.php
2022-01-12 20:51:33 -08:00
snipe
ba5b835933 Lock seeder to english
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 13:10:29 -08:00
Brady Wetherington
a063806bcc Permit DONT_REQ_PREAUTH AD users to log in 2022-01-12 12:50:39 -08:00
Brady Wetherington
c8fe929e09 Add new UserAccountControl to permitted UAC's for AD. 2022-01-12 12:07:51 -08:00
snipe
df0da0f3bc Fixed escaped string
Signed-off-by: snipe <snipe@snipe.net>
2022-01-12 11:20:31 -08:00
snipe
181dc5127f Add @UniversalSuperBox as a contributor 2022-01-11 15:03:08 -08:00
snipe
303fc39966 Regenerated assets to pikc up #10089 changes
Signed-off-by: snipe <snipe@snipe.net>
2022-01-11 14:38:17 -08:00
snipe
730c2a6821 Merge pull request #10496 from UniversalSuperBox/fix/improve-asset-card-view
Fixed #10089 (partially): Back to master: Added some BS tables style overrides for mobile
2022-01-11 14:10:18 -08:00
Alex Janes
d2bb3e6377 Merge branch 'develop' into features/quickscan_checkin 2022-01-11 16:40:20 -05:00
snipe
bc10761b49 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2022-01-11 12:44:16 -08:00
snipe
2262176a60 Merge pull request #10449 from adagioajanes/features/lock_logins_to_saml
Added #10436: Restricted Logins to SAML controlled via environment variable
2022-01-11 12:37:54 -08:00
Alex Janes
edef640d35 Merge branch 'develop' into features/lock_logins_to_saml 2022-01-11 09:05:14 -05:00
snipe
cf14a0222c Merge pull request #10498 from Haxatron/master
Fix access control
2022-01-10 19:24:31 -08:00
snipe
23a2700178 Merge pull request #10491 from snipe/fixes/migration_licenses_table_issue
Fixed - v6 migration licenses table issue
2022-01-10 15:51:18 -08:00
snipe
ea83567e7d Merge pull request #10494 from exula/fix/increase_max_licenses
Fixed #7824
2022-01-10 15:04:47 -08:00
snipe
dcc199835b Add @nuraeil as a contributor 2022-01-10 14:56:22 -08:00
snipe
d9624b59b4 Merge pull request #10264 from nuraeil/added-localized-strings
Added #10242: Improved localized strings
2022-01-10 14:48:52 -08:00
snipe
b98c97b00e Merge pull request #10265 from uberbrady/remove_old_ldap
Remove old ldap
2022-01-10 14:34:34 -08:00
snipe
b18b3812df Back to master: Added some BS tables style overrides for mobile
This repeats 06e8e826, which alone improves the mobile view immensely,
on master.
2022-01-10 15:23:43 -06:00
Brad
6b6a83a525 Removing something stupid PHPStorm put in the use area 2022-01-10 14:21:19 -05:00
Brad
81084fa717 Fixed #7824
Previously there was a 999 max seats on Licenses as anything above that seemed to cause slowdowns and failure.

This commit allievates those pain points

- removed freeSeats as a hydrated Eloquent model on JSON requests for the licenses index
- removed 'licenseSeats.user', 'licenseSeats.asset' from the 'with' clause as it's not needed in the view (Datatabales takes care of that)
- removed the 999 max seats limit from the License Model,
- reworked how new license seats are created when increasing seats or creating licenses
- Added an index the license_seats table to help speed up lookups
2022-01-10 14:03:28 -05:00
Wächtler, Yannick
f906dbd81e Added missed translation strings, fixed the column width for the date selector (too small in certain languages) 2022-01-10 09:21:23 +01:00
Nuraeil
5bb2f6fa0f Merge branch 'develop' into added-localized-strings 2022-01-09 17:40:54 +01:00
Wächtler, Yannick
b77e7f88d4 fix(bootstrap-table): adds locale env to table init, adds bootstrap-table-locale-all to webpack-mix 2022-01-09 17:35:28 +01:00
snipe
66976d9359 Merge pull request #10492 from snipe/fixes/finish_localizing_backup_restore
Finished localizing backup restore strings
2022-01-07 16:51:43 -08:00
snipe
0f5bb0e65d Localize bakcup restore strings
Signed-off-by: snipe <snipe@snipe.net>
2022-01-07 16:50:19 -08:00
snipe
8719b3d3e9 Only try to create the licenses table if it doesn't exist
Signed-off-by: snipe <snipe@snipe.net>
2022-01-07 15:43:34 -08:00
Wächtler, Yannick
c3ab4c7512 Fixed the tables not displaying the correct language 2022-01-06 14:29:10 +01:00
Wächtler, Yannick
04d649122b Fixed duplication for a couple of items, removed TODO markers, added lots of translation strings where there was a TODO 2022-01-06 12:35:37 +01:00
Haxatron
bb095641c2 Update BulkAssetModelsController.php
https://huntr.dev/bounties/efdf2ead-f9d1-4767-9f02-d11f762d15e7
2022-01-06 09:50:11 +08:00
Nuraeil
271c364ef8 Merge pull request #9 from snipe/develop
Merge snipe/snipe-it:develop into nuraeil/snipe-it:added-localized-strings
2022-01-04 10:48:51 +01:00
snipe
b78e610ce3 Merge pull request #10480 from snipe/fixes/check_for_valid_custom_field
Fixed format property on invalid custom field object when trying to edit a field that doesn't exist
2022-01-03 19:28:25 -08:00
snipe
884b6b0270 Fixes format property on invalid custom field object
Signed-off-by: snipe <snipe@snipe.net>
2022-01-03 19:14:50 -08:00
Brady Wetherington
95c30cae8d Some duplicate imports at the top of the Settings file 2022-01-03 13:53:53 -08:00
Brady Wetherington
3c7f2e89ec Merge branch 'develop' into remove_old_ldap
Had to re-do the composer install because the conflicts were too complicated.
2022-01-03 12:56:58 -08:00
snipe
7a1ab1292c Merge pull request #10479 from adagioajanes/fixes/auto_asset_tag_phrasing
Fixed auto asset tag phrasing
2021-12-31 15:17:59 -08:00
Alex Janes
87bb741013 Merge branch 'snipe:master' into fixes/auto_asset_tag_phrasing 2021-12-31 16:34:57 -05:00
Alex Janes
5fe2083688 Adjusted the phrasing around auto-incrementing asset tags. 2021-12-31 16:33:30 -05:00
snipe
2ee84c2675 Added a few more comments
Signed-off-by: snipe <snipe@snipe.net>
2021-12-30 18:33:28 -08:00
snipe
39a5b6b426 Merge pull request #10478 from snipe/fixes/whitelist_modal_views
Added allow list to modal view options
2021-12-30 18:29:30 -08:00
snipe
c6ce928567 Added allow list to modal view options
Signed-off-by: snipe <snipe@snipe.net>
2021-12-30 18:16:49 -08:00
snipe
950a23b0f4 Merge pull request #10476 from snipe/fixes/custom_fieldsets_index
Fixed missing index for fieldsets
2021-12-30 13:18:13 -08:00
snipe
b4fac3e4ae Fixed missing index for fieldsets
Signed-off-by: snipe <snipe@snipe.net>
2021-12-30 13:16:44 -08:00
snipe
548e483ef8 Merge pull request #10475 from snipe/fixes/wrong_default_sort_on_kits
Fixed assets_count doesnt exist as a column on kits
2021-12-30 13:02:12 -08:00
snipe
bad6b862ca assets_count doesnt exist as a column
Signed-off-by: snipe <snipe@snipe.net>
2021-12-30 12:59:16 -08:00
snipe
359b22e17a Applies #10470 to develop
Signed-off-by: snipe <snipe@snipe.net>
2021-12-27 13:22:47 -08:00
snipe
4e336e11ee Merge pull request #10470 from snipe/increase_address_length_for_supplier
Fixed #10469 - increased size of supplier address field
2021-12-27 12:29:13 -08:00
snipe
8588e9ebf1 Fixed #10469 - increased size of supplier address field
Signed-off-by: snipe <snipe@snipe.net>
2021-12-27 12:28:02 -08:00
snipe
aaeda5bf76 Merge pull request #10468 from snipe/fixes/10467_safari_font_awesome_content_code_headers
Fixed #10467 - Safari only font-awesome bug
2021-12-24 12:34:36 -08:00
snipe
8be6d10dbe Fixed #10467 - Safari only font-awesome bug
Signed-off-by: snipe <snipe@snipe.net>
2021-12-24 12:30:34 -08:00
snipe
fde5c6c226 Add @adagioajanes as a contributor 2021-12-24 11:21:46 -08:00
snipe
f4ef828332 Fixex js table export
Signed-off-by: snipe <snipe@snipe.net>
2021-12-24 11:17:36 -08:00
snipe
87f52cbfec Seeder fixes
Signed-off-by: snipe <snipe@snipe.net>
2021-12-24 10:47:06 -08:00
snipe
11524d0f7d Merge pull request #10463 from adagioajanes/fixes/pass_total_to_GroupsTransformer
Fixed #10461: Groups management page did not paginate correctly
2021-12-24 10:39:22 -08:00
Alex Janes
d0bfd8dfd2 Fixed the collection of the groups total to GroupsTransformer.php. Groups page should now paginate correctly. 2021-12-23 20:54:34 -05:00
Alex Janes
ea93f82bde added the notes field to allow users to quickly add notes to multiple checkins at once 2021-12-23 17:37:48 -05:00
snipe
312200bf44 Removed duplicate "department" entry in importer, pulls #10460 to master
Signed-off-by: snipe <snipe@snipe.net>
2021-12-21 13:37:20 -08:00
snipe
69bc02727b Merge pull request #10460 from inietov/fixes/duplicate_department_in_user_import
Fixes Duplicate department in user import
2021-12-21 13:30:24 -08:00
Ivan Nieto Vivanco
e03a8cc721 Delete an extra entry for Departments when importing Users via GUI 2021-12-21 14:42:51 -06:00
Alex Janes
2e5820e29d small phrase change 2021-12-20 23:31:10 -05:00
Alex Janes
b01a4468c7 refactored from bulkcheckin to quickscancheckin 2021-12-20 23:27:36 -05:00
snipe
48d3bfef03 Merge pull request #10421 from Robert-Azelis/patch-5
Create new user account from asset form - additional fields
2021-12-20 17:05:38 -08:00
Alex Janes
7acb559069 corrected issue with asset not found errors 2021-12-20 19:55:00 -05:00
Alex Janes
55b8d080b9 more lang changes 2021-12-20 19:39:06 -05:00
Alex Janes
fcc9815c6e Revert "Added phrase to all language files to prevent errors (translation still needs to happen)"
This reverts commit 87ef37b0b4.
2021-12-20 18:05:21 -05:00
Alex Janes
cb14abfc54 Revert "fixed zh-CN file format"
This reverts commit 20f66a1b55.
2021-12-20 18:05:09 -05:00
Alex Janes
3841c3560b changed a page title 2021-12-20 16:52:00 -05:00
Alex Janes
20f66a1b55 fixed zh-CN file format 2021-12-20 14:05:13 -05:00
Alex Janes
2b5aca183c removed unnecessary additional data call from api method 2021-12-19 19:21:58 -05:00
Alex Janes
14b21a6e95 removed some whitespace 2021-12-19 19:17:32 -05:00
Alex Janes
08cb8c354b more cleanup to fit formatting convention 2021-12-19 19:11:24 -05:00
Alex Janes
87ef37b0b4 Added phrase to all language files to prevent errors (translation still needs to happen) 2021-12-19 18:50:55 -05:00
Alex Janes
29da4f4325 Removed a bunch of redundant code I created from the API 2021-12-19 18:39:57 -05:00
Alex Janes
bc4fe88ac0 First version of bulk checkin 2021-12-19 16:53:31 -05:00
Alex Janes
ead142cdf7 Corrected a tiny HTML typo in the SAML view. (Unrelated to this PR) 2021-12-18 12:00:07 -05:00
Alex Janes
9d4a6b85ed Merge remote-tracking branch 'origin/features/lock_logins_to_saml' into features/lock_logins_to_saml 2021-12-18 11:56:57 -05:00
Alex Janes
227ca61301 Changed phrasing of "SAML Force Login" to "SAML Default Login" (English only at this point) 2021-12-18 11:56:36 -05:00
Alex Janes
a68ec8bb57 Update LoginController.php
Updated if statements to match convention exactly.
2021-12-17 18:52:42 -05:00
Alex Janes
74de91c31a Merge pull request #1 from snipe/develop
Develop
2021-12-17 14:51:03 -05:00
snipe
04f4bb83e9 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-12-16 20:37:22 -08:00
snipe
9b2dd6522f Switch GET to POST for asset request
Signed-off-by: snipe <snipe@snipe.net>
2021-12-16 20:36:08 -08:00
snipe
4ca2252e3b Switches GET to POST for request assset
Signed-off-by: snipe <snipe@snipe.net>
2021-12-16 20:32:29 -08:00
Alex Janes
d99db5c63b bug fix and formatting fix 2021-12-16 19:04:37 -05:00
Wächtler, Yannick
2901525194 Merge branch 'snipe-develop' into added-localized-strings 2021-12-17 00:22:08 +01:00
Wächtler, Yannick
279fced877 merge 2021-12-17 00:14:36 +01:00
snipe
8c5dce5dcf Merge pull request #10450 from snipe/master_into_develop
Master into develop
2021-12-16 14:45:53 -08:00
snipe
398180dc59 Small merge unmagling
Signed-off-by: snipe <snipe@snipe.net>
2021-12-16 14:38:04 -08:00
snipe
6be98638ed Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2021-12-16 14:29:38 -08:00
snipe
c3d55ee27e Merge master down into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	README.md
#	app/Exceptions/Handler.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/Api/SettingsController.php
#	app/Http/Controllers/CustomFieldsController.php
#	app/Http/Controllers/SettingsController.php
#	app/Http/Transformers/AssetsTransformer.php
#	app/Models/Setting.php
#	config/version.php
#	resources/lang/af/button.php
#	resources/lang/ar/button.php
#	resources/lang/bg/button.php
#	resources/lang/cs/button.php
#	resources/lang/cy/button.php
#	resources/lang/da/button.php
#	resources/lang/de/button.php
#	resources/lang/el/button.php
#	resources/lang/en-GB/button.php
#	resources/lang/en-ID/button.php
#	resources/lang/es-CO/admin/groups/message.php
#	resources/lang/es-MX/button.php
#	resources/lang/et/admin/custom_fields/general.php
#	resources/lang/et/admin/hardware/table.php
#	resources/lang/et/admin/kits/general.php
#	resources/lang/et/admin/manufacturers/message.php
#	resources/lang/et/admin/models/general.php
#	resources/lang/et/admin/settings/general.php
#	resources/lang/et/button.php
#	resources/lang/et/mail.php
#	resources/lang/fa/button.php
#	resources/lang/fa/help.php
#	resources/lang/fi/button.php
#	resources/lang/fil/button.php
#	resources/lang/fr/button.php
#	resources/lang/ga-IE/button.php
#	resources/lang/he/button.php
#	resources/lang/hr/button.php
#	resources/lang/hu/admin/settings/general.php
#	resources/lang/hu/auth/message.php
#	resources/lang/hu/button.php
#	resources/lang/hu/mail.php
#	resources/lang/id/admin/hardware/table.php
#	resources/lang/id/button.php
#	resources/lang/it/button.php
#	resources/lang/iu/button.php
#	resources/lang/ja/button.php
#	resources/lang/ko/button.php
#	resources/lang/lt/button.php
#	resources/lang/lv/button.php
#	resources/lang/mi/button.php
#	resources/lang/mk/button.php
#	resources/lang/ml-IN/button.php
#	resources/lang/mn/button.php
#	resources/lang/ms/admin/hardware/table.php
#	resources/lang/ms/admin/kits/general.php
#	resources/lang/ms/admin/models/general.php
#	resources/lang/ms/admin/models/message.php
#	resources/lang/ms/admin/settings/general.php
#	resources/lang/ms/button.php
#	resources/lang/nl/button.php
#	resources/lang/no/admin/hardware/table.php
#	resources/lang/no/admin/kits/general.php
#	resources/lang/no/admin/settings/general.php
#	resources/lang/no/auth/message.php
#	resources/lang/no/button.php
#	resources/lang/no/help.php
#	resources/lang/no/mail.php
#	resources/lang/pl/button.php
#	resources/lang/pt-BR/button.php
#	resources/lang/pt-PT/auth/message.php
#	resources/lang/pt-PT/button.php
#	resources/lang/pt-PT/mail.php
#	resources/lang/ro/button.php
#	resources/lang/ru/admin/settings/general.php
#	resources/lang/ru/button.php
#	resources/lang/ru/help.php
#	resources/lang/sl/admin/custom_fields/general.php
#	resources/lang/sl/admin/hardware/table.php
#	resources/lang/sl/admin/kits/general.php
#	resources/lang/sl/admin/manufacturers/message.php
#	resources/lang/sl/admin/models/general.php
#	resources/lang/sl/admin/settings/general.php
#	resources/lang/sl/admin/users/general.php
#	resources/lang/sl/auth/message.php
#	resources/lang/sl/button.php
#	resources/lang/sl/help.php
#	resources/lang/sr-CS/button.php
#	resources/lang/ta/button.php
#	resources/lang/th/button.php
#	resources/lang/th/mail.php
#	resources/lang/tl/button.php
#	resources/lang/tr/admin/settings/general.php
#	resources/lang/tr/auth/message.php
#	resources/lang/tr/button.php
#	resources/lang/uk/button.php
#	resources/lang/ur-PK/button.php
#	resources/lang/vi/button.php
#	resources/lang/zh-CN/button.php
#	resources/lang/zh-HK/button.php
#	resources/lang/zh-TW/admin/hardware/table.php
#	resources/lang/zh-TW/button.php
#	resources/lang/zu/button.php
#	resources/views/models/custom_fields_form.blade.php
#	resources/views/reports/custom.blade.php
#	resources/views/settings/slack.blade.php
2021-12-16 14:26:24 -08:00
Alex Janes
6898119891 Replaced env() with config() to check environment variables
Made the app.php description for 'REQUIRE_SAML' a bit more... descriptive.
2021-12-16 16:56:39 -05:00
Alex Janes
a6116a1b15 If SAML required, don't accept login form post. 2021-12-16 14:33:25 -05:00
Alex Janes
696943b04b Add option to environment to require SAML for a more secure installation. 2021-12-16 11:44:34 -05:00
Alex Janes
3c8d70c5fb Add option to environment to require SAML for a more secure installation. 2021-12-16 11:44:07 -05:00
snipe
a05fe9c1f7 Add @exula as a contributor 2021-12-15 09:30:36 -08:00
snipe
395401e9db Merge pull request #10439 from exula/exula-fix-slack-settings
Update SettingsController.php to save Slack Settings
2021-12-15 08:36:18 -08:00
Bradley Coudriet
dbdc1c7f3f Update SettingsController.php to save Slack Settings
This goes with #10438 that I just submitted about Slack Settings not saving.

This adds the necessary code to actually save the Slack Settings,
As they are already validated by the SlackSettingsRequest, this seems like an easy and low-impact fix.
2021-12-15 10:38:51 -05:00
Nuraeil
c3b7576d99 Merge pull request #7 from snipe/develop
Develop
2021-12-14 19:51:40 +01:00
Wächtler, Yannick
484b996879 fixed merge conflicts 2021-12-14 19:48:59 +01:00
snipe
52322806fa Merge pull request #10434 from inietov/fixes/v6_components_error
Fix route to checkout components from the details page
2021-12-14 10:41:24 -08:00
Wächtler, Yannick
4397a12efc Merge branch 'develop' of https://github.com/snipe/snipe-it into snipe-develop 2021-12-14 19:37:27 +01:00
Ivan Nieto Vivanco
d083f89f30 Delete extra character remaining from previous tests :( 2021-12-14 12:32:30 -06:00
snipe
ace4a00e29 Merge pull request #10433 from inietov/features/adding_title_to_custom_report_master
Add title column to custom reports on master branch
2021-12-14 10:28:18 -08:00
snipe
59555483f3 Merge pull request #10432 from inietov/features/adding_title_to_custom_report
Add title column to custom reports
2021-12-14 10:28:02 -08:00
Ivan Nieto Vivanco
2402f00a2e Fix route to checkout components from the details page 2021-12-14 12:26:46 -06:00
Ivan Nieto Vivanco
c80aa2a289 Add title column to custom reports 2021-12-14 12:05:33 -06:00
Ivan Nieto Vivanco
0037cdb00c Add title column to custom reports 2021-12-13 20:27:23 -06:00
snipe
25e2e7ecc6 Merge pull request #10418 from inietov/fixes/bulk_edit_count_more_users_than_selected
Fixes bulk edit message counts more users than the actual selected users number
2021-12-13 14:13:14 -08:00
snipe
02be4773de Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 12:07:34 -08:00
snipe
c988d84271 Merge pull request #10426 from snipe/fixes/added_escape_to_asset_api_assigned_to
Added escape to assigned_to API response
2021-12-13 12:06:08 -08:00
snipe
9d5d1a9f9a Added escape to assigned_to API response
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 12:03:03 -08:00
snipe
3a7cef15bd Merge pull request #10423 from misilot/automated-image-build-github-actions
Automatic Building of Docker Images and Pushing to DockerHub
2021-12-13 11:32:57 -08:00
snipe
44d3a425cb Merge pull request #10422 from misilot/docker-alpine-build-automatic
Adds an automatic build for Alpine Linux based Image
2021-12-13 11:32:42 -08:00
snipe
1854d7d668 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 11:28:01 -08:00
snipe
e5f4048e9e Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 11:01:02 -08:00
Thomas Misilo
5e58f60845 Adds an automatic build for Alpine Linux based Image
This Fixes #10339, and allows for automatic building of the Alpine Linux
image, and push to docker-hub.

This will push a "latest-alpine" based on the master branch, a
"develop-alpine" based on the develop branch, and a v##.##.##-alpine
image based on any released version.

`DOCKER_USERNAME` and `DOCKER_ACCESS_TOKEN` do both need
to be added to the repository as secrets.
2021-12-13 10:39:55 -06:00
Thomas Misilo
a7760b331b Automatic Building of Docker Images and Pushing to DockerHub
This allows for building and pushing of the Snipe-IT docker images
directly from GitHub to DockerHub.

This will push a "latest" based on the master branch, a
"develop" based on the develop branch, and a v##.##.##
image based on any released version.

`DOCKER_USERNAME` and `DOCKER_ACCESS_TOKEN` do both need
to be added to the repository as secrets.
2021-12-13 10:39:04 -06:00
Robert-Azelis
01608d81ab Update user.blade.php
Create new user account from asset form - additional fields #10420
2021-12-13 09:22:25 +01:00
Ivan Nieto Vivanco
5bda4b79d2 Fixes the Asset Factory to assign example Suppliers and Locations to Assets 2021-12-11 21:36:54 -06:00
Ivan Nieto Vivanco
a419a690d4 Add a variable to better control the selected user's ids 2021-12-11 18:01:38 -06:00
Ivan Nieto Vivanco
b43a0569b1 Fixes trying to get property 'id' of non-object in develop seeders 2021-12-11 17:26:41 -06:00
snipe
39b0dc136c Added LDAP strings back
Signed-off-by: snipe <snipe@snipe.net>
2021-12-11 10:14:35 -08:00
snipe
d0e7879c89 Merge pull request #10415 from uberbrady/fix_actionlog_memory_exhaustion
Remove 'actionlog' from the ::with() clause in the asset query API
2021-12-10 19:10:40 -08:00
snipe
503c802d70 Merge pull request #10416 from uberbrady/yank_assetlogs_from_asset_api
Yank assetlog from eager-load clause in API query for develop
2021-12-10 19:09:55 -08:00
Brady Wetherington
ea71086dfc Yank assetlog from eager-load clause in API query for develop 2021-12-10 18:50:34 -08:00
Brady Wetherington
acfb41f129 Remove 'actionlog' from the ::with() clause in the asset query API 2021-12-10 18:42:56 -08:00
snipe
5381aa3fbd Merge branch 'master' of https://github.com/snipe/snipe-it 2021-12-10 15:17:45 -08:00
snipe
e20a10a6a1 Add @Haxatron as a contributor 2021-12-10 15:17:26 -08:00
snipe
949141a8e7 Merge pull request #10414 from snipe/added_model_to_accessory_report
Added model number to accessory report
2021-12-10 15:10:02 -08:00
snipe
e1bf3b50f4 Added model number to accessory report
Signed-off-by: snipe <snipe@snipe.net>
2021-12-10 15:09:29 -08:00
snipe
cf5e3da3a5 Merge pull request #10406 from Haxatron/fix-access-control
security fix
2021-12-09 11:23:35 -08:00
Haxatron
1699c09758 Update AssetModelsController.php 2021-12-09 21:42:18 +08:00
Haxatron
918e7c8dae Fix access control - https://huntr.dev/bounties/19453ef1-4d77-4cff-b7e8-1bc8f3af0862/ 2021-12-09 12:57:04 +08:00
snipe
86afe6c4b1 Cleanup slack validation
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 18:03:56 -08:00
snipe
ff97b359ad Removed form request on ajax, cleaned up some other things
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:58:46 -08:00
snipe
81b66d0039 Change validation failure to 422 to make it consistent with Laravel's default
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:54:35 -08:00
snipe
8fa690b635 Reverting form request because it doesn't seem to work (????!!)
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:54:15 -08:00
snipe
8c1cd87831 Added slacksettingsrequest as use statement
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:56:22 -08:00
snipe
cde2bad297 Small mods to slack jquery
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:56:05 -08:00
snipe
80d36cd72b Added slack settings request
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:53:05 -08:00
snipe
713fbdc0a6 Merge pull request #10239 from Godmartinz/Adds-info-on-how-to-nullify-reorder-alerts
adds info on how to nullify reorder alerts for consumables, component…
2021-12-08 14:26:22 -08:00
snipe
6d84482104 Merge pull request #10388 from snipe/features/switch_to_dusk
WIP - Fixing unit tests, switching to dusk
2021-12-06 14:19:36 -08:00
snipe
0ba55e0eaf Merge pull request #10393 from aranar-pro/fix/#10365-Total-Purchase
Fixed #10365: Snipe-IT has a wrong total purchase cost when reaches m…
2021-12-06 14:08:24 -08:00
snipe
4612b9e711 Merge pull request #10394 from snipe/fixes/add_stricter_validation_for_slack_hooks
Adds stricter validation for slack hooks
2021-12-06 11:41:11 -08:00
snipe
ebdbc20740 Adds stricter validation for slack endpoints
Signed-off-by: snipe <snipe@snipe.net>
2021-12-06 11:40:24 -08:00
Andrew Roth
d1d3b84f77 Fixed #10365: Snipe-IT has a wrong total purchase cost when reaches million. Fixed to remove multiple commas in +1M per item. 2021-12-06 13:06:23 -05:00
snipe
66ed311914 Fixed asset maintenances test
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 20:14:39 -08:00
snipe
f334bf1058 Fixed notification tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 20:01:03 -08:00
snipe
0104f35f31 Fixed Component Test, commented Consumables
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 19:43:15 -08:00
snipe
222ee8e0bf Slight refactor on depreciation test
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 19:36:07 -08:00
snipe
0e3bafd5b4 Fixed depreciation tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 19:19:42 -08:00
snipe
17bc562ac4 Commented out broken permissions and importer tests for now
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 19:19:35 -08:00
snipe
1e46fde5e2 Fixed status labels tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 19:01:57 -08:00
snipe
872bd29cb3 Removed repetitive tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 18:27:52 -08:00
snipe
21e2504f79 Trying unsuccessfully to get nested factories working
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 17:38:28 -08:00
snipe
3a1e2a56d6 Use the proper ID for status ID factory
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 17:38:06 -08:00
snipe
5a01fff79c Use the Setting model for basetest
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 17:37:51 -08:00
snipe
390e8a6cc3 Fixed company unit test
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 16:43:03 -08:00
snipe
b0d2fc787a Fixed accessory test
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 16:33:16 -08:00
snipe
35ba28bff9 Continuing to refactor tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 16:14:45 -08:00
snipe
c2709be4a1 Removed pointless tests
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 16:14:23 -08:00
snipe
00d2235610 Lowercase tests in composer.json per previous revert
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 15:12:47 -08:00
snipe
21575cf674 Lowercase tests dir
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 15:09:52 -08:00
snipe
c949a1f5f2 renamed Tests to tests 2021-12-02 15:08:26 -08:00
snipe
9536f836f0 Beginning of CompanyTest fixes (not done yet)
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 15:02:46 -08:00
snipe
064e0b7a1c Removed dd for debugging
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 15:02:25 -08:00
snipe
37033fb2f7 Removed some defaul values to handle validation
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 15:02:11 -08:00
snipe
77d6649e38 One more case change because I have NOTHING else to do
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 14:26:31 -08:00
snipe
f61f386f31 Fixed again because I suck
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 14:07:48 -08:00
snipe
d20a0f7c6d Update composer autoload for test case case
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 14:05:35 -08:00
snipe
406aed6b07 Case sensitive dir stuff
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 14:03:32 -08:00
snipe
5555553307 renamed again for git to accept case 2021-12-02 14:02:16 -08:00
snipe
00b63fe7c7 Fixed category factory methods
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 13:40:16 -08:00
snipe
cae62fd4c7 Merge pull request #9902 from SidingsMedia/sum_cost_by_quantity
Fixed #5676: Sum cost by quantity
2021-12-02 12:13:04 -08:00
snipe
44b6907919 Updated phpunit.xml
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 11:44:32 -08:00
snipe
406211d2fe Move mockery to require-dev
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 11:22:46 -08:00
snipe
fb06c136b9 Added mockery (because reasons?)
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 11:11:14 -08:00
snipe
957d092844 Upgraded phpunit to v9
Signed-off-by: snipe <snipe@snipe.net>
2021-12-02 11:04:04 -08:00
snipe
ed2797afdd Small fixes
Signed-off-by: snipe <snipe@snipe.net>
2021-12-01 23:33:20 -08:00
snipe
ad6d70b86f Removed unused Str
Signed-off-by: snipe <snipe@snipe.net>
2021-12-01 23:30:48 -08:00
snipe
17bd6d71e7 Fixed location unit test
Signed-off-by: snipe <snipe@snipe.net>
2021-12-01 22:45:39 -08:00
snipe
d96e95abd6 Small mods to configs, removed old faker, added new
Signed-off-by: snipe <snipe@snipe.net>
2021-12-01 13:46:21 -08:00
snipe
bc355e1f26 Remve unused use Hash statements
Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:47:02 -08:00
snipe
d8234d5a0b Trying to unfuck the TestCase
A lot has changed between versions

Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:46:44 -08:00
snipe
f3f6a04c43 Use hash::
Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:46:20 -08:00
snipe
fe2cd8b708 Switched back to sqlite for unit
Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:45:54 -08:00
snipe
e73373a75a Removed empty tests
Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:45:42 -08:00
snipe
d08c1787a1 First steps at getting dusk working
Signed-off-by: snipe <snipe@snipe.net>
2021-11-30 20:09:29 -08:00
Nuraeil
d3972888dc Merge pull request #6 from snipe/develop
Develop
2021-11-30 06:37:17 +01:00
snipe
a579353198 Add @bestlong as a contributor 2021-11-24 20:04:26 -08:00
snipe
7360e15d4e Add @sneak-it as a contributor 2021-11-24 20:04:05 -08:00
snipe
9dc2fa61b8 Add @adamboutcher as a contributor 2021-11-24 20:03:52 -08:00
snipe
80fd49a59e Add @leitwerk-ag as a contributor 2021-11-24 20:03:40 -08:00
snipe
d30fa9199c Merge branch 'master' of https://github.com/snipe/snipe-it 2021-11-24 19:58:52 -08:00
snipe
8028b39b43 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:58:43 -08:00
snipe
ff81e6d536 Merge pull request #10361 from snipe/fixes/xss_in_accessories_checkout_notes
Escape notes in transformCheckedOutAccessory
2021-11-24 19:56:36 -08:00
snipe
00fad35c2a Escape notes in transformCheckedOutAccessory
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:54:45 -08:00
snipe
3b68a6f1be Merge pull request #10345 from leitwerk-ag/master
Fixed #10344 and #9135: don't prepand fields with a whitespace in text based export formats
2021-11-24 19:43:21 -08:00
snipe
bc91aef47d Merge pull request #10352 from adamboutcher/install_rocky
Improved Installer: Added Rocky Linux Support
2021-11-24 19:42:37 -08:00
snipe
3debe78574 Merge pull request #10350 from inietov/fixes/trim_custom_fields_names
Apply trim() function when storing Custom Fields names
2021-11-24 19:42:04 -08:00
snipe
4c2d47e7c6 Merge pull request #10354 from inietov/fixes/customfields_with_date_format_doesnt_display_default_value
Fixes Default Values - Date not applying
2021-11-24 19:41:51 -08:00
snipe
fc1b3b31b5 Merge pull request #10358 from sneak-it/bullseye
Improved Installer: Add Debian 11 (Bullseye) install script support
2021-11-24 19:41:37 -08:00
snipe
4afd598df7 Merge pull request #10356 from bestlong/fix_modal_dialog_html_typo
fix modal-title html tag unpaired.
2021-11-24 19:39:58 -08:00
snipe
29bbfad693 Applied escaping fix from master to develop
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:38:27 -08:00
snipe
d1d3f893ac Merge pull request #10360 from snipe/fixes/escaped_characters_on_asset_create_checkout
Removed escaping on input save for asset checkout on creation
2021-11-24 19:20:54 -08:00
snipe
830d07f84f Removed escaping on input save for asset checkout on creation
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:19:32 -08:00
snipe
0e30b9aef7 Merge pull request #10355 from inietov/fixes/customfields_with_date_format_doesnt_display_default_value_master
Fixes Default Values - Date not applying for master branch
2021-11-24 18:22:02 -08:00
sneaK
b937aedc30 Add Debian 11 (Bullseye) install script support 2021-11-24 10:24:05 -05:00
Shao Yu-Lung
55d05eeae3 fix modal-title html tag unpaired. 2021-11-24 10:28:10 +08:00
Ivan Nieto Vivanco
d95d3dc282 Add the call to defaultValue() function in custom fields with date format 2021-11-23 17:21:46 -06:00
Ivan Nieto Vivanco
741eb28622 Add the call to defaultValue() function in custom fields with date format 2021-11-23 17:11:21 -06:00
Adam
ab06c26527 Rocky Linux Support
Addition to enable Rocky Linux installation.
2021-11-23 16:13:38 +00:00
Ivan Nieto Vivanco
1ca770895a Apply trim() function when storing Custom Fields names 2021-11-22 18:43:21 -06:00
snipe
ef8f646ab2 Merge pull request #10349 from snipe/chore/sc-17719/add-sodium-as-a-requirement-in-upgrade-php
Update upgrade.php with newer requires
2021-11-22 15:32:51 -08:00
snipe
686e58806f Update upgrade.php with newer requires
Signed-off-by: snipe <snipe@snipe.net>
2021-11-22 15:31:23 -08:00
Klaus J. Mueller
a85fa14f9c fix #10344 and #9135 2021-11-22 17:58:26 +01:00
Matthew Nickson
9381ba2404 Merge branch 'develop' into sum_cost_by_quantity 2021-11-21 18:59:34 +00:00
Brady Wetherington
e8f5dc85a6 Downgraded a FIXME to a TODO 2021-11-19 16:38:46 -08:00
Wächtler, Yannick
1b76185798 Added TODO: comments to pages, where there are non-localized strings, in order to keep track of them 2021-11-19 15:32:13 +01:00
Wächtler, Yannick
9164daf5bc Added localized strings for admin/settings 2021-11-19 15:23:48 +01:00
Wächtler, Yannick
6917d59185 Added localized strings for reports 2021-11-19 12:39:19 +01:00
Wächtler, Yannick
04fec144a0 Added localization strings for partials, added file structure 2021-11-19 12:12:11 +01:00
Nuraeil
6eb120d101 Merge pull request #5 from snipe/develop
Develop
2021-11-19 11:51:16 +01:00
snipe
df0b240a05 Merge pull request #10288 from uberbrady/composer_install_under_phpv8
[sc-17645] Composer install under phpv8
2021-11-18 15:28:54 -08:00
snipe
3e83b2ff2f Merge pull request #10334 from snipe/feature/sc-17704/make-all-currency-values-right-aligned
Added text-right to presenters for money values
2021-11-18 15:10:19 -08:00
snipe
c49c5f4164 Added text-right to presenters for money values
Signed-off-by: snipe <snipe@snipe.net>
2021-11-18 15:09:17 -08:00
snipe
6d545ff11b Merge pull request #10333 from snipe/bug/sc-17711/v6-bug-500-server-error-when-trying-to-checkin
Fixed v6 bug 500 server error when trying to checkin
2021-11-18 14:38:17 -08:00
snipe
250f6b6fb8 Fixed v6 bug 500 server error when trying to checkin [sc-17711]
Signed-off-by: snipe <snipe@snipe.net>
2021-11-18 14:37:12 -08:00
Nuraeil
7084703b5a Merge pull request #4 from snipe/develop
Merge current develop into branch
2021-11-18 21:30:45 +01:00
snipe
f6d5d6cc09 Merge pull request #10316 from snipe/bug/sc-17684/v6-bug-error-when-editing-model-with-no-custom
v6 bug - Error when editing model with no custom
2021-11-17 18:38:48 -08:00
snipe
b058d84f2c Merge pull request #10322 from snipe/uberbrady-patch-2
Change the `[END]` directive in `.htaccess` to `[L]`
2021-11-17 18:01:52 -08:00
Brady Wetherington
5fb05d8b1c Change the [END] directive in .htaccess to [L]
This allows backwards-compatibility with older Apache versions (which we _used_ to have), and should do the exact same thing.
2021-11-17 15:29:51 -08:00
Wächtler, Yannick
5a2f8788a9 Fixed merge issue in view.blade.php and added translatable string 2021-11-16 19:34:20 +01:00
Wächtler, Yannick
f2c3e51a83 Catching up to snipe-it/develop branch 2021-11-16 19:25:23 +01:00
Wächtler, Yannick
74ed790d20 Merge branch 'snipe-develop' into added-localized-strings 2021-11-16 08:51:06 +01:00
Wächtler, Yannick
6feb39f6b9 Merge branch 'develop' of https://github.com/snipe/snipe-it into snipe-develop 2021-11-16 08:50:45 +01:00
snipe
bbb0d1be17 Possible fix for asset model editing when no custom fieldset is associated
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 21:09:35 -08:00
snipe
476e17055b Escape custom fields in API response
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 20:31:01 -08:00
snipe
db45de5da2 Fixed old style user routes
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 20:26:07 -08:00
snipe
207c785b1d Added missing use statements for Laravel 8 routes
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 20:20:10 -08:00
snipe
8a747be3a0 Fixed routes for newer format (l8)
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 20:16:40 -08:00
snipe
65d1855b38 Display app_locked message on front-end
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 19:50:55 -08:00
snipe
46d2f8a81d Disallow file upload to backups on demo
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 19:42:02 -08:00
snipe
92b7aaf44b Log the user out upon successful restore
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 19:40:01 -08:00
snipe
8bf11e9417 Bummped hash fpr v6-pre-alpha
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 19:31:20 -08:00
snipe
174d23a42a Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 19:29:57 -08:00
snipe
f2f8f96991 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Transformers/AssetsTransformer.php
#	app/Importer/ConsumableImporter.php
#	app/Models/Consumable.php
#	config/version.php
#	package-lock.json
#	package.json
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
#	resources/views/custom_fields/fieldsets/view.blade.php
#	resources/views/layouts/default.blade.php
#	routes/web.php
#	routes/web/fields.php
2021-11-15 19:24:38 -08:00
snipe
ce69e54202 Merge pull request #10297 from snipe/features/backup_importer_ui
v6 Feature - Added backup restore from GUI
2021-11-15 19:09:37 -08:00
snipe
cc5b8f3d6d Merge pull request #10302 from SBrown2021/patch-1
Typo in upgrade.php
2021-11-11 10:32:42 -08:00
SBrown2021
c668cc3103 Typo in upgrade.php
Fixed typo on line 181. bootsrap/cache/services.php -> bootstrap/cache/services.php
2021-11-11 17:05:24 +00:00
snipe
bc21875324 More refinements to the UI
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 18:15:38 -08:00
snipe
1a703bf78b Added logout clarification
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 17:59:52 -08:00
snipe
494c72d92b Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 17:58:04 -08:00
snipe
69fe3c0299 Added some comments on the JS
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 17:57:15 -08:00
snipe
0c58fa1b1e Merge branch 'features/backup_importer_ui' of https://github.com/snipe/snipe-it into features/backup_importer_ui 2021-11-10 17:49:04 -08:00
snipe
e2702186a9 Slightly reworked UI
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 17:48:59 -08:00
snipe
595c3bfd57 Merge pull request #10298 from uberbrady/features/backup_importer_ui
Cleaned up the output and added some better checks for errors
2021-11-10 17:21:23 -08:00
Brady Wetherington
c2b5f9b372 Cleaned up the output and added some better checks for errors 2021-11-10 17:08:04 -08:00
snipe
b069eec43a Fixed upload disabled button
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 16:01:22 -08:00
snipe
040bdd2f32 Merge branch 'features/backup_importer_ui' of https://github.com/snipe/snipe-it into features/backup_importer_ui 2021-11-10 13:01:05 -08:00
snipe
f8cf65bbb3 Small layout fixes
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 13:01:02 -08:00
snipe
c1a844cce6 Merge pull request #10296 from uberbrady/features/backup_importer_ui
Tweak Restore command to _also_ run via webserver via Artisan::call()
2021-11-10 13:00:40 -08:00
Brady Wetherington
2b6614e2dd Tweak Restore command to _also_ run via webserver via Artisan::call() 2021-11-10 12:44:19 -08:00
Brady Wetherington
864cc4f8d5 Fix FIXME's by downgrading them to TODO's :) 2021-11-10 11:37:10 -08:00
snipe
ec2a3b0f35 Updated label names
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 01:44:34 -08:00
snipe
230a568145 Added help text and more info in the modal
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 01:44:11 -08:00
snipe
457c6080cc Better handling if there was no file uploaded
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 01:43:45 -08:00
snipe
856b9294f8 Improved BS tables on backups
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 00:08:43 -08:00
snipe
8590e5d67e UNRELATED: fixed wrong html tag for license view badge count
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 00:08:15 -08:00
snipe
cf070866f0 INCOMPLETE: Added more generic language strings
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 00:07:47 -08:00
snipe
76685d7fd3 Clearer text in restore artisan command
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 00:07:32 -08:00
snipe
96f76e1f6b INCOMPLETE: Added restore and upload methods for backups
Signed-off-by: snipe <snipe@snipe.net>
2021-11-10 00:07:17 -08:00
snipe
05c6254fdc Updated snipeit.js with "restore" modal code
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 22:39:33 -08:00
snipe
3b25093aeb Removed noisy debugging
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 22:38:27 -08:00
snipe
76506dabbf Made helpers call full namespace (tho I have no idea why this was necessary)
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 22:38:14 -08:00
snipe
1b1b54fbf4 Add modified_value and modified_display so we can use the formatted date but still sort correctly
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 22:37:49 -08:00
snipe
542ab75d89 Added new backup routes
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 19:39:50 -08:00
snipe
0e21a95817 Escape error message in asset autdit apI (same as in v5)
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 19:39:32 -08:00
snipe
fb21712a68 Added restore modal HTML
Signed-off-by: snipe <snipe@snipe.net>
2021-11-09 19:38:40 -08:00
Brady Wetherington
91f087258b Merge branch 'develop' into remove_old_ldap 2021-11-09 18:33:41 -08:00
Brady Wetherington
25d72d2978 Make composer install work on 7.4 as well as 8.0 2021-11-09 13:06:24 -08:00
Brady Wetherington
ec030e9e1f Tweak some version requirements to make composer install run under phpv8 2021-11-08 21:19:23 -08:00
Brady Wetherington
a58c5ce27f Better documentation, disable AdLdap2-based "Add domain" setting 2021-11-08 17:11:47 -08:00
Wächtler, Yannick
6b2801867d Renamed account/api to account/general to match naming schema, changed the associated account/api trans() to account/general 2021-11-04 20:15:23 +01:00
Wächtler, Yannick
97030866e4 Adding newly added template files 2021-11-04 20:12:47 +01:00
Nuraeil
3f2749d5d6 Merge pull request #2 from snipe/develop
Develop
2021-11-04 19:16:00 +01:00
Brady Wetherington
b0417e5bd7 Finish pulling out the AdLdap2-based LDAP remnants that were still in the system 2021-11-03 15:22:06 -07:00
snipe
98de8526db Merge pull request #10258 from PlaneNuts/Fix_Advanced_Search/Checked_Out_To
Fixed #8828: Can't search by checked out user in advanced search
2021-11-02 14:53:08 -07:00
Wächtler, Yannick
63b30489df Added localized strings for notifications 2021-11-02 15:44:57 +01:00
Wächtler, Yannick
670b70c7e1 Added localized strings for models 2021-11-02 15:34:50 +01:00
Wächtler, Yannick
c0891e6827 Added localized strings for modals 2021-11-02 15:27:13 +01:00
Wächtler, Yannick
30d30490a3 Added localized strings for locations 2021-11-02 15:14:54 +01:00
Wächtler, Yannick
4af6412da6 Added localized strings for licenses 2021-11-02 14:55:49 +01:00
Wächtler, Yannick
4fcd4a930f Added localized strings for layouts 2021-11-02 14:45:58 +01:00
Wächtler, Yannick
8bad9c5140 Added localized strings for kits 2021-11-02 14:25:21 +01:00
Wächtler, Yannick
26e056fb3c Added localized strings for improter, added en structure 2021-11-02 14:09:22 +01:00
Wächtler, Yannick
c16ade2d87 Added localized strings for hardware 2021-11-02 14:02:48 +01:00
Wächtler, Yannick
167bf97d46 Added localized strings for groups 2021-11-02 12:03:41 +01:00
Wächtler, Yannick
e825fa81aa Added localized strings for depreciations 2021-11-02 11:50:56 +01:00
Wächtler, Yannick
a96c53784c Added localized strings for custom_fields 2021-11-02 11:27:53 +01:00
Wächtler, Yannick
c11af0e222 Added missing localized strings for account/accept/index.blade.php and view-assets.blade.php 2021-11-02 10:40:41 +01:00
Wächtler, Yannick
433d6fd3e0 Added localized strings for admin/companies 2021-11-02 10:23:15 +01:00
Wächtler, Yannick
b784e63aa8 Added localized strings for account 2021-11-02 10:13:22 +01:00
Terrell Eaton
2c7a71a2a1 Fixes not being able to search by checked out user in advanced search 2021-11-01 22:14:19 +01:00
Godfrey M
1683b04244 changed min_amt_help message 2021-11-01 11:05:44 -07:00
Matthew Nickson
90ca66834b Fixed sumFormatterQuantity if using 1.234,56 fomat
Previously sumFormatterQuantity used the parseFloat to convert the
string purchase_cost to a floating point number. parseFloat does not
return the correct value when using the comma format. To fix this
sumFormatterQuantity now used the cleanFloat function to convert
purchase_cost to a float.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2021-10-30 22:48:45 +01:00
snipe
eae9bf574f Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-10-29 14:11:58 -07:00
snipe
409600f29d Added S3 commented out settings in env example for clarity
Signed-off-by: snipe <snipe@snipe.net>
2021-10-29 14:11:54 -07:00
Brady Wetherington
4dda28de9e WIP: cleaning up LDAP 2021-10-28 18:19:50 -07:00
snipe
e932cdf106 Merge pull request #9799 from Toreg87/fixes/fmcs_departments
Fixed #9798: Scope departments for FullMultipleCompanySupport
2021-10-28 18:18:16 -07:00
Brady Wetherington
31933a56fa Trying to get the login screen working 2021-10-28 18:18:11 -07:00
snipe
ea0d92c439 Merge branch 'develop' into fixes/fmcs_departments 2021-10-28 18:18:08 -07:00
snipe
5458e44a40 Merge pull request #9508 from sh1hab/feature/remove_deleted_user_from_unaccepted_assets_report
Feature #9378 remove deleted user from unaccepted assets report
2021-10-28 18:11:19 -07:00
snipe
d36849bd41 Merge branch 'develop' into feature/remove_deleted_user_from_unaccepted_assets_report 2021-10-28 18:11:03 -07:00
snipe
84a3a85823 Fixed parse error for merge conflict
Signed-off-by: snipe <snipe@snipe.net>
2021-10-28 18:04:03 -07:00
snipe
798f6d65de Merge pull request #9847 from inietov/bug/ch15357/requested_assets_allow_to_cancel_if_checkedout_to_self
Adds a check to know if the asset is checked out to the logged in user to allow check the state in the view
2021-10-28 17:53:24 -07:00
snipe
d54434fdf7 Merge pull request #9541 from misilot/change-var-aws-public-url
Change from ENV to config value for PUBLIC_AWS_URL
2021-10-28 17:46:25 -07:00
snipe
bdf321ecc9 Merge branch 'develop' into change-var-aws-public-url 2021-10-28 17:46:16 -07:00
snipe
3ede7c7f18 Use icon and string for maintained value in license view
Signed-off-by: snipe <snipe@snipe.net>
2021-10-28 17:26:03 -07:00
snipe
2d782cd31f Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-10-28 17:20:27 -07:00
snipe
645529ba78 Merge pull request #9889 from ncareau/api-licenses
Add licenses api parameters and fix a missing variable in license view.
2021-10-28 17:20:09 -07:00
snipe
636dc6877b Merge pull request #10113 from Godmartinz/bug/sc-17129/v6-integration-pie-chart-disappears-if-you
Fixed #sc17129 - Pie chart disappears when window resizes
2021-10-28 17:14:14 -07:00
snipe
3951de1669 Merge branch 'develop' into bug/sc-17129/v6-integration-pie-chart-disappears-if-you 2021-10-28 17:13:37 -07:00
snipe
3088230236 Merge pull request #10209 from Godmartinz/feature/sc-1474/sync-parent-asset-location-with-children-assets
Fixes Bug: When parent asset is assigned to other location, children assets loca…
2021-10-28 16:49:44 -07:00
snipe
984bc501a5 Merge pull request #9906 from Toreg87/fixes/advanced_search_serial_v2
Fixed #9904: Advanced search with serial and another field produce incorrect results (v2)
2021-10-28 16:42:32 -07:00
snipe
371a39a118 Merge branch 'develop' into fixes/advanced_search_serial_v2 2021-10-28 16:42:10 -07:00
snipe
d3d199efc3 Add @PlaneNuts as a contributor 2021-10-28 16:39:28 -07:00
snipe
7821d38e60 Merge pull request #10238 from inietov/fixes/asset_components_must_return_relationship_instance
Fixes asset components must return relationship instance
2021-10-28 16:38:21 -07:00
snipe
1895dd326f Merge pull request #10245 from Sxderp/pr-support-appache-rewrite-redirect-headers-for-remote-user
support apache REDIRECT_* for remote user login
2021-10-28 16:34:57 -07:00
snipe
1975afaca6 Merge pull request #10248 from snipe/features/add_requestable_to_bulk_model_edit
Adds reqestable as model bulk edit field
2021-10-28 16:30:55 -07:00
snipe
52ef9280ba Adds reqestable as model bulk edit field
Signed-off-by: snipe <snipe@snipe.net>
2021-10-28 15:15:54 -07:00
snipe
30cfc34ecf Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-10-28 14:42:58 -07:00
snipe
668e8a357c Fixed labels in profile form
Signed-off-by: snipe <snipe@snipe.net>
2021-10-28 12:57:27 -07:00
Steven Daniele
efc644c960 support apache REDIRECT_* for remote user login 2021-10-28 14:23:38 -04:00
Godfrey M
b0da936c5c changed get to receive in the message 2021-10-27 16:41:38 -07:00
Godfrey M
8719667c44 adds info on how to nullify reorder alerts for consumables, components and accessories 2021-10-27 16:36:04 -07:00
Ivan Nieto Vivanco
ee9133f722 Return the proper Asset-Components relationship 2021-10-27 16:42:51 -05:00
snipe
8cfa8d97b4 Merge pull request #10215 from inietov/fixes/bulk_edit_counts_more_users_selected
Fixes bulk edit message counts more users than the actual selected users number
2021-10-21 13:02:03 -07:00
Ivan Nieto Vivanco
9eaf89aaa7 Add a variable to better control the selected user's ids 2021-10-21 13:28:58 -05:00
snipe
31d49b5c9b Fixed merge error parse error
Signed-off-by: snipe <snipe@snipe.net>
2021-10-20 18:11:34 -07:00
snipe
6e0f8068b2 Fixed duplicate use statement from merge fuckery
Signed-off-by: snipe <snipe@snipe.net>
2021-10-20 17:54:32 -07:00
snipe
9ee13f0d2a Fixed dupe use statement from merge fuckery
Signed-off-by: snipe <snipe@snipe.net>
2021-10-20 17:53:43 -07:00
snipe
ae1a4bb3c9 Fixed extra braces from merge fuckery
Signed-off-by: snipe <snipe@snipe.net>
2021-10-20 17:36:06 -07:00
snipe
aa8f1378c9 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	README.md
#	app/Http/Controllers/Accessories/AccessoriesController.php
#	app/Http/Controllers/Api/AssetMaintenancesController.php
#	app/Http/Controllers/Api/AssetModelsController.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/Api/UsersController.php
#	app/Http/Controllers/AssetMaintenancesController.php
#	app/Http/Controllers/Assets/AssetFilesController.php
#	app/Http/Controllers/Assets/AssetsController.php
#	app/Http/Controllers/Assets/BulkAssetsController.php
#	app/Http/Controllers/Components/ComponentsController.php
#	app/Http/Controllers/Consumables/ConsumablesController.php
#	app/Http/Controllers/Licenses/LicenseFilesController.php
#	app/Http/Controllers/Licenses/LicensesController.php
#	app/Http/Controllers/Users/UserFilesController.php
#	app/Http/Transformers/AssetsTransformer.php
#	app/Http/Transformers/LicensesTransformer.php
#	app/Importer/UserImporter.php
#	app/Models/Asset.php
#	config/app.php
#	config/version.php
#	package-lock.json
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
#	resources/lang/en/admin/users/message.php
#	resources/lang/is/button.php
#	resources/lang/ja/admin/kits/general.php
#	resources/lang/ro/admin/users/general.php
#	resources/lang/zh-HK/admin/depreciations/general.php
#	resources/lang/zh-HK/admin/models/general.php
#	resources/views/hardware/qr-view.blade.php
#	resources/views/hardware/view.blade.php
#	resources/views/partials/bootstrap-table.blade.php
#	resources/views/users/view.blade.php
#	routes/web.php
#	routes/web/hardware.php
#	routes/web/models.php
#	routes/web/users.php
2021-10-20 17:26:41 -07:00
Godfrey M
9ae7d0b23a when parent asset is assigned to other location, children assets location are updated as well. 2021-10-20 17:01:25 -07:00
snipe
365349fd91 Center custom fields email icon
Signed-off-by: snipe <snipe@snipe.net>
2021-10-18 18:39:46 -07:00
snipe
4095a3f8c4 Removed dupe bars
Signed-off-by: snipe <snipe@snipe.net>
2021-10-12 12:31:08 -07:00
snipe
94c4265524 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-10-12 12:30:39 -07:00
snipe
4a98519c1f Compiled assets
Signed-off-by: snipe <snipe@snipe.net>
2021-10-12 12:30:25 -07:00
snipe
d126b265ee Merge pull request #10192 from snipe/bug/sc-17471/font-awesome-hamburger-menu-is-showing-as
Fixed misisng hamburger menu
2021-10-12 12:10:53 -07:00
snipe
892fc0004a Fixed misisng hamburger menu
Signed-off-by: snipe <snipe@snipe.net>
2021-10-12 12:09:46 -07:00
snipe
2cbbf7efe2 Merge pull request #10186 from tanji/patch-2
Exclude web.config from Apache
2021-10-11 10:03:37 -07:00
Guillaume Lefranc
494ed3d17a Exclude web.config from Apache 2021-10-11 14:14:00 +02:00
Matthew Nickson
8996c24d1f Merge branch 'develop' into sum_cost_by_quantity 2021-10-10 13:01:44 +01:00
snipe
1f5c38ad7e Merge pull request #10179 from inietov/features/allow_same_category_name_for_different_types
Fixes #9365 #9800 Added a validation to use the same name in categories with different types [sc-17487]
2021-10-08 14:10:29 -07:00
Ivan Nieto Vivanco
23b770fac6 Added a validation to use the same name in categories with different types 2021-10-08 15:19:16 -05:00
snipe
5f52ee59b2 Merge pull request #9529 from dampfklon/Feature_#9514_Asset_Acceptance,_resend_mail/_send_remainder
Feature #9514, Feature #9378 Unaccepted Assets Report Actions, Fixed [ch16410]
2021-10-07 12:49:42 -07:00
Dampfklon
ab4a234e20 fix rebase errors 2021-10-07 21:32:57 +02:00
Dampfklon
7645f23f5c remove pending Acceptances on checkin 2021-10-07 21:03:46 +02:00
Dampfklon
4418ad2340 Enable display of deleted acceptances, strike deleted users, add date, enable sorting 2021-10-07 21:03:46 +02:00
Dampfklon
12ee06deb6 add Download All Button, change route analogue to activity report 2021-10-07 21:01:50 +02:00
Dampfklon
9a9ca59544 Fix decprecated implode usage 2021-10-07 20:55:47 +02:00
Dampfklon
ed99532c30 Unaccepted Assets Report Actions (send reminder, delete) added
Unaccepted Assets Export fixed
2021-10-07 20:53:02 +02:00
snipe
3980c80c70 Merge pull request #10166 from uberbrady/fix_default_values_for_custom_fields_for_models_rebased
Fix default values for custom fields for models rebased
2021-10-04 22:27:45 -07:00
Brady Wetherington
bbeedc026d A lot of cleanups to the Livewire stuff, and got it kinda-sorta basically working. 2021-10-04 22:07:29 -07:00
Brady Wetherington
d80604f2ac Most of the basics are working, but not done and lots of debug messages are about
I picked up the change that picked a point-release difference on the AWS library since that usually
works out for us (x.y.1 vs. x.y.2 - usually a good call)
2021-10-04 22:06:48 -07:00
snipe
1457fda508 Merge pull request #10159 from AL4AL/specify_docker_images_version
Fixed #10158 Specify docker images versions
2021-10-04 18:28:11 -07:00
Sajjad
f036e2b2a3 Specify docker images versions
Fix unquoted sentences
2021-10-03 11:12:53 +03:30
snipe
b919f5b1e9 Merge pull request #10150 from inietov/fixes/new_department_error_importing_users
Fixes New department error importing users.
2021-09-30 15:31:17 -07:00
Ivan Nieto Vivanco
11aa8971c8 Fix error if the Department is also empty 2021-09-30 17:20:44 -05:00
Ivan Nieto Vivanco
5c7aaaac22 Fix error when department is null 2021-09-30 16:46:23 -05:00
snipe
43a437000b Slightly better right-padding on row-new-striped
Signed-off-by: snipe <snipe@snipe.net>
2021-09-29 11:20:32 -07:00
snipe
228c8223a8 Merge pull request #10148 from uberbrady/snipe_it_v6_php_73
Try to generate a new composer lockfile under PHP 7.3
2021-09-29 10:57:56 -07:00
Brady Wetherington
3a73fa19f0 Try to generate a new composer lockfile under PHP 7.3 2021-09-29 10:53:44 -07:00
snipe
85b5f52cd8 Nicer mobile view for user view icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-28 23:04:30 -07:00
snipe
61f16f47a2 Use Helper alias
Signed-off-by: snipe <snipe@snipe.net>
2021-09-28 19:44:55 -07:00
snipe
9a83b90e44 Make row-new-striped 100% width
Signed-off-by: snipe <snipe@snipe.net>
2021-09-28 15:04:57 -07:00
snipe
9311f8694f Fixed incorrect icon for map marker
Signed-off-by: snipe <snipe@snipe.net>
2021-09-28 09:35:48 -07:00
NMC
c680977791 Merge branch 'develop' into api-licenses 2021-09-27 15:02:51 -04:00
snipe
c8ac19a5a0 Merge pull request #10135 from svpernova09/recreate-license-table-migration-issue
Rename license migration to resolve fatal error running migrations
2021-09-27 11:03:17 -07:00
Joe Ferguson
8c49f78218 Rename license migration to resolve fatal error running migrations during setup 2021-09-27 12:53:17 -05:00
snipe
2a6b59f0f8 Removed extra paramater from hasTable
Signed-off-by: snipe <snipe@snipe.net>
2021-09-27 09:48:03 -07:00
snipe
4c3f59c5fd Remove first migration for licenses
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 15:51:17 -07:00
snipe
6f96b25440 Attempt fix at Laravel "magic" class in migrations resulting in table already exists
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 15:48:43 -07:00
snipe
1657ba396f Added available license seat count to top tabs for licenses
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 15:03:56 -07:00
snipe
f0da1977fb Small visual improvements on consumables view
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 14:32:51 -07:00
snipe
d88c0ae5ec Merge pull request #10103 from snipe/fixes/make_boolean_fields_nullable
Fixed issue when creating a status label via API - default_label and show_in_nav being not nullable
2021-09-26 13:41:52 -07:00
snipe
450da5661d Add additional info on accessories view page
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 03:59:04 -07:00
snipe
a6632a7b9f Use new row striping on licenses detail page
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 03:58:53 -07:00
snipe
638e5a5bf6 Merge pull request #10132 from snipe/features/upgrade_the_rest_of_fa_icons
Upgraded FA icons to latest
2021-09-26 01:12:33 -07:00
snipe
7e41c74cc3 Updated more fa icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-26 01:11:08 -07:00
snipe
8738451685 Fixed font awesome caret
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 23:17:35 -07:00
snipe
65a6da5bd2 Added files tab back to assets
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 22:59:02 -07:00
snipe
a7b3f98e9f Updated angle icon with new font awesome
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 22:57:27 -07:00
snipe
8ee00d0f42 Changed paperflip to file icon
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 22:57:06 -07:00
snipe
667639b9fb Backed out the ribbon CSS for now
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 22:56:54 -07:00
snipe
749f364186 Removed gitter
Signed-off-by: snipe <snipe@snipe.net>
2021-09-25 22:56:32 -07:00
snipe
67d898e897 Updated map icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 14:30:36 -07:00
snipe
a9b306f2d2 Backing out the ribbon - too finicky on mobile :(
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 14:30:29 -07:00
snipe
e03d7b7016 More fa icon updates
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 13:07:02 -07:00
snipe
20e23c1248 Fixed 500 on wrong association
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 12:54:47 -07:00
snipe
5875cf1e9e Removed test code
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 12:33:34 -07:00
snipe
03e3c21d7e Merge pull request #10129 from snipe/features/improved_mobile_ux
Features/improved mobile ux
2021-09-24 12:30:56 -07:00
snipe
decc771459 Starting to refactor the hardware page
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 12:05:48 -07:00
snipe
78fa6452ee Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 12:05:18 -07:00
snipe
2c141813f1 Better formatting
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 11:51:52 -07:00
snipe
3317b5107a Added ribbon to show on user's photo that they are an admin
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 11:13:55 -07:00
snipe
0d1bd5b470 Updated more fa icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 11:13:34 -07:00
snipe
8d1c3106b5 Building assets again
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 11:13:15 -07:00
snipe
d480084c01 Merge pull request #10128 from inietov/fixes/route_not_defined_components_consumables
Fixes route not defined exception on components and consumables
2021-09-24 10:50:46 -07:00
Ivan Nieto Vivanco
efc9a8e2c9 Fixes route not defined exception on components and consumables 2021-09-24 11:38:07 -05:00
snipe
299ad681f7 More fa icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 07:21:30 -07:00
snipe
b2dc92b088 And a few more missed icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 06:44:38 -07:00
snipe
ad6f073c82 Few more icon updates
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 06:38:23 -07:00
snipe
8aba37522d More FA icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 06:18:22 -07:00
snipe
dbe93d91cd Updated fontawesome icons
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 06:07:46 -07:00
snipe
383c2c8466 New assets
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 04:12:55 -07:00
snipe
06e8e826bc Added some BS tables style overrides for mobile
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 04:12:41 -07:00
snipe
4a8f06b0f1 Added badge counters to tabs
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 04:12:22 -07:00
snipe
c69a883409 Fixed Groups route
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 04:12:07 -07:00
snipe
1574d24dde Fixed accessories route
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 04:11:58 -07:00
snipe
8937396a26 Added padding to the sidenav on mobile
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 03:02:57 -07:00
snipe
fd7c6179d5 Show the user's photo frst on mobile view
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 03:02:47 -07:00
snipe
9a299973ff Mobile CSS overrides
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 03:02:19 -07:00
snipe
7f41bdf0b0 Use new striping on hardware page
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 02:17:57 -07:00
snipe
90c22caa4b Rework user page to no longer use tables for data layout
This also fixes the weird display when lines break

Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 02:17:40 -07:00
snipe
12df310449 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2021-09-24 02:16:58 -07:00
snipe
7cbdf2c727 A few seeder fixes
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 22:16:19 -07:00
snipe
28a5838dfb Merge pull request #10125 from snipe/features/add_demo_user_images
Added userpics from thispersondoesnotexist.com
2021-09-23 22:08:39 -07:00
snipe
932c1364ee Added userpics from thispersondoesnotexist.com
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 22:05:42 -07:00
snipe
1ecd11dd2e More route fixes
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 21:46:17 -07:00
snipe
d82490f4a6 Updated package-lock
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 19:05:41 -07:00
snipe
71644696d1 Removed duplicate migration
Signed-off-by: snipe <snipe@snipe.net>
2021-09-22 17:21:48 -07:00
snipe
61cf9ec009 Small conflict handling bits
Signed-off-by: snipe <snipe@snipe.net>
2021-09-22 00:00:44 -07:00
snipe
e27065fe16 Merge branch 'develop-v6-integration' into develop-v6-rc1
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	README.md
#	app/Console/Commands/ResetDemoSettings.php
#	app/Helpers/Helper.php
#	app/Http/Controllers/Api/AccessoriesController.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/Api/CategoriesController.php
#	app/Http/Controllers/Api/ComponentsController.php
#	app/Http/Controllers/Api/ConsumablesController.php
#	app/Http/Controllers/Api/LocationsController.php
#	app/Http/Controllers/Api/StatuslabelsController.php
#	app/Http/Controllers/Api/SuppliersController.php
#	app/Http/Controllers/AssetMaintenancesController.php
#	app/Http/Controllers/Auth/ForgotPasswordController.php
#	app/Http/Controllers/DepreciationsController.php
#	app/Http/Controllers/ReportsController.php
#	app/Http/Controllers/SettingsController.php
#	app/Http/Requests/ImageUploadRequest.php
#	app/Http/Transformers/ActionlogsTransformer.php
#	app/Http/Transformers/DepreciationsTransformer.php
#	app/Listeners/CheckoutableListener.php
#	app/Models/Accessory.php
#	app/Models/Asset.php
#	app/Models/Company.php
#	app/Models/Ldap.php
#	app/Models/User.php
#	app/Presenters/AssetPresenter.php
#	app/Presenters/CategoryPresenter.php
#	composer.json
#	composer.lock
#	config/version.php
#	database/factories/AssetModelFactory.php
#	database/migrations/2020_10_22_233743_move_accessory_checkout_note_to_join_table.php
#	database/seeds/AssetModelSeeder.php
#	package-lock.json
#	public/css/build/AdminLTE.css
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/css/dist/skins/skin-black-dark.css
#	public/css/dist/skins/skin-black-dark.min.css
#	public/css/dist/skins/skin-black.css
#	public/css/dist/skins/skin-black.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-blue.css
#	public/css/dist/skins/skin-blue.min.css
#	public/css/dist/skins/skin-contrast.css
#	public/css/dist/skins/skin-contrast.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-green.css
#	public/css/dist/skins/skin-green.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-orange.css
#	public/css/dist/skins/skin-orange.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-purple.css
#	public/css/dist/skins/skin-purple.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/css/dist/skins/skin-red.css
#	public/css/dist/skins/skin-red.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/css/dist/skins/skin-yellow.css
#	public/css/dist/skins/skin-yellow.min.css
#	public/js/build/app.js
#	public/js/build/vendor.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
#	resources/assets/js/vue.js
#	resources/lang/af/validation.php
#	resources/lang/ar/admin/settings/general.php
#	resources/lang/ar/validation.php
#	resources/lang/bg/admin/settings/general.php
#	resources/lang/bg/validation.php
#	resources/lang/cs/admin/settings/general.php
#	resources/lang/cs/validation.php
#	resources/lang/cy/help.php
#	resources/lang/cy/validation.php
#	resources/lang/da/admin/settings/general.php
#	resources/lang/da/validation.php
#	resources/lang/de/admin/settings/general.php
#	resources/lang/de/validation.php
#	resources/lang/el/validation.php
#	resources/lang/en-GB/admin/settings/general.php
#	resources/lang/en-GB/validation.php
#	resources/lang/en-ID/admin/hardware/table.php
#	resources/lang/en-ID/admin/settings/general.php
#	resources/lang/en-ID/validation.php
#	resources/lang/es-CO/admin/settings/general.php
#	resources/lang/es-CO/auth/message.php
#	resources/lang/es-CO/button.php
#	resources/lang/es-CO/help.php
#	resources/lang/es-CO/validation.php
#	resources/lang/es-ES/admin/settings/general.php
#	resources/lang/es-ES/auth/message.php
#	resources/lang/es-ES/button.php
#	resources/lang/es-ES/help.php
#	resources/lang/es-ES/validation.php
#	resources/lang/es-MX/admin/settings/general.php
#	resources/lang/es-MX/validation.php
#	resources/lang/es-VE/admin/settings/general.php
#	resources/lang/es-VE/auth/message.php
#	resources/lang/es-VE/button.php
#	resources/lang/es-VE/help.php
#	resources/lang/es-VE/validation.php
#	resources/lang/et/validation.php
#	resources/lang/fa/validation.php
#	resources/lang/fi/admin/settings/general.php
#	resources/lang/fi/validation.php
#	resources/lang/fil/validation.php
#	resources/lang/fr/admin/settings/general.php
#	resources/lang/fr/validation.php
#	resources/lang/ga-IE/validation.php
#	resources/lang/he/admin/settings/general.php
#	resources/lang/he/general.php
#	resources/lang/he/validation.php
#	resources/lang/hr/validation.php
#	resources/lang/hu/validation.php
#	resources/lang/id/validation.php
#	resources/lang/is/admin/categories/general.php
#	resources/lang/is/admin/companies/message.php
#	resources/lang/is/admin/companies/table.php
#	resources/lang/is/admin/components/general.php
#	resources/lang/is/admin/components/table.php
#	resources/lang/is/admin/consumables/table.php
#	resources/lang/is/admin/depreciations/general.php
#	resources/lang/is/admin/depreciations/message.php
#	resources/lang/is/admin/hardware/form.php
#	resources/lang/is/admin/hardware/general.php
#	resources/lang/is/admin/hardware/message.php
#	resources/lang/is/admin/hardware/table.php
#	resources/lang/is/admin/kits/general.php
#	resources/lang/is/admin/licenses/form.php
#	resources/lang/is/admin/licenses/general.php
#	resources/lang/is/admin/locations/table.php
#	resources/lang/is/admin/manufacturers/table.php
#	resources/lang/is/admin/reports/message.php
#	resources/lang/is/admin/settings/general.php
#	resources/lang/is/admin/settings/message.php
#	resources/lang/is/admin/statuslabels/message.php
#	resources/lang/is/admin/suppliers/message.php
#	resources/lang/is/admin/suppliers/table.php
#	resources/lang/is/admin/users/table.php
#	resources/lang/is/mail.php
#	resources/lang/is/validation.php
#	resources/lang/it/admin/settings/general.php
#	resources/lang/it/validation.php
#	resources/lang/iu/validation.php
#	resources/lang/ja/mail.php
#	resources/lang/ja/validation.php
#	resources/lang/ko/validation.php
#	resources/lang/lt/validation.php
#	resources/lang/lv/validation.php
#	resources/lang/mi/validation.php
#	resources/lang/mk/validation.php
#	resources/lang/ml-IN/validation.php
#	resources/lang/mn/validation.php
#	resources/lang/ms/validation.php
#	resources/lang/nl/admin/settings/general.php
#	resources/lang/nl/validation.php
#	resources/lang/no/validation.php
#	resources/lang/pl/admin/settings/general.php
#	resources/lang/pl/validation.php
#	resources/lang/pt-BR/admin/settings/general.php
#	resources/lang/pt-BR/mail.php
#	resources/lang/pt-BR/validation.php
#	resources/lang/pt-PT/validation.php
#	resources/lang/ro/validation.php
#	resources/lang/ru/validation.php
#	resources/lang/sl/validation.php
#	resources/lang/sr-CS/admin/settings/general.php
#	resources/lang/sr-CS/validation.php
#	resources/lang/sv-SE/admin/settings/general.php
#	resources/lang/sv-SE/auth/message.php
#	resources/lang/sv-SE/button.php
#	resources/lang/sv-SE/mail.php
#	resources/lang/sv-SE/validation.php
#	resources/lang/ta/validation.php
#	resources/lang/th/validation.php
#	resources/lang/tl/validation.php
#	resources/lang/tr/mail.php
#	resources/lang/tr/validation.php
#	resources/lang/uk/admin/accessories/table.php
#	resources/lang/uk/admin/asset_maintenances/message.php
#	resources/lang/uk/admin/asset_maintenances/table.php
#	resources/lang/uk/validation.php
#	resources/lang/ur-PK/validation.php
#	resources/lang/vi/admin/settings/general.php
#	resources/lang/vi/validation.php
#	resources/lang/zh-CN/admin/settings/general.php
#	resources/lang/zh-CN/validation.php
#	resources/lang/zh-HK/validation.php
#	resources/lang/zh-TW/validation.php
#	resources/lang/zu/validation.php
#	resources/views/partials/bootstrap-table.blade.php
#	resources/views/partials/forms/edit/company-select.blade.php
#	routes/api.php
2021-09-21 23:46:50 -07:00
snipe
b7f0e76e4c Merge branch 'develop-v6-integration' of https://github.com/snipe/snipe-it into develop-v6-integration 2021-09-21 20:07:07 -07:00
snipe
6d3c8a9189 Add @Delta5 as a contributor 2021-09-21 20:06:45 -07:00
snipe
df1b1bc972 Merge pull request #10111 from Delta5/add-restore-user-api-endpoint
Added restore functionality to user API
2021-09-21 20:05:52 -07:00
Godfrey M
160017c720 more deadspace 2021-09-21 19:28:39 -07:00
Godfrey M
941cba73b9 removed deadspace and unnecessary css changes 2021-09-21 19:27:17 -07:00
Godfrey M
4a0c8de82a adds jquery eventlistner to monitor chart.js width and refresh accordingly 2021-09-21 19:13:09 -07:00
Delta5
c8c3c7fbbd Fixed issue with incorrect error message 2021-09-21 19:45:18 +00:00
Delta5
615f7e3c69 Fix author name and remove additional line spacing 2021-09-21 19:18:19 +00:00
Delta5
59302e1d19 Add restore to users api endpoint 2021-09-21 17:42:26 +00:00
Delta5
20f7fe1ecc Add restore to users api endpoint 2021-09-21 17:36:11 +00:00
snipe
d24822e342 Retroactively fix any existing settings for that table
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 15:47:29 -07:00
snipe
c59c7337a5 Forgot the ->change() method
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 15:42:25 -07:00
snipe
b331bb33d9 Code fixes and a new migration
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 15:37:24 -07:00
snipe
9f3b63387a Merge pull request #9987 from Godmartinz/bug/ch17111/donked-layout-on-required-field-error-in
Bug/ch17111/donked layout on required field error in
2021-08-24 15:11:22 -07:00
Godfrey M
a407fe9312 removed more dead space 2021-08-24 15:07:56 -07:00
Godfrey M
53ddf5ae04 removed dead space 2021-08-24 15:07:18 -07:00
Godfrey M
a197b730a1 fixed a layout issue with the month field in depreciations [ch17111] 2021-08-24 15:02:42 -07:00
snipe
193a52876e Fix incorrect resource route name
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 15:01:10 -07:00
snipe
d3844811b5 Updated composer lock
Signed-off-by: snipe <snipe@snipe.net>
2021-08-17 20:28:26 -07:00
snipe
211e0c6bd4 Dropped down to PHP 7.3 compat packages
Signed-off-by: snipe <snipe@snipe.net>
2021-08-17 20:21:43 -07:00
snipe
4c13ddd0c5 Merge pull request #9937 from Godmartinz/depreciation_min_feature
adds a Floor value for depreciation models
2021-08-16 18:29:48 -07:00
Godfrey M
9480709ea3 changed value to current value 2021-08-16 18:22:24 -07:00
Godfrey M
cef0e424e1 adds a Floor value for depreciation models 2021-08-16 18:14:10 -07:00
snipe
29008545bc Merge pull request #9924 from snipe/chore/ch16531/update-demo-photos-of-iphones-to-be-more
Update demo photos of iPhones to be more [ch16531]
2021-08-11 13:16:09 -07:00
Godfrey M
4c2257b67d Update demo photos of iPhones to be more [ch16531] 2021-08-11 13:13:12 -07:00
Tobias Regnery
eced1ab77f Fix advanced search with serial and another field
The advanced search in /hardware produces incorrect results if the serial is combined with another field like category.
There is a typo as the fieldname 'product_key' doesn't exist. Change this to 'serial'.

Also change the last If-Statement from ->orWhere() to ->where(). Now additional fields like custom fields can be combined with other searches in an And-Clause.
I think this function could be simplified further, but this is the minimal bugfix.
2021-08-05 15:07:28 +02:00
Computroniks
8121d904e7 Licence cost calculation
Licences use diffrent key to track quantity. sumFormatterQuantity has
been modified to detect which key to use.

Signed-off-by: Computroniks <mnickson@sidingsmedia.com>
2021-08-04 22:33:39 +01:00
Computroniks
f994af16da Added function to calculate cost based on quantity
sumFormatterQuantity takes the same input as sumFormatter but instead
of calculating the specified columns total it calculates the total
purchase cost of an item based upon its quantity. Also updated affected
pressenters to use this formatter.

Signed-off-by: Computroniks <mnickson@sidingsmedia.com>
2021-08-04 22:09:50 +01:00
NMC
4cfc4aec1d fix false search in api. 2021-08-01 15:10:22 -04:00
NMC
976957ddd4 Add Maintained filed in licenses view and api. + Expires in API 2021-08-01 14:30:16 -04:00
snipe
071325f368 Merge pull request #9824 from PetriAsi/feature/api-image-uploads-v6
Added #9594:  Feature/api image uploads for v6
2021-07-27 14:35:16 -07:00
snipe
476ab2888c Merge pull request #9852 from Godmartinz/develop-v6-integration
adds newer versions of devices for demo
2021-07-27 14:34:15 -07:00
snipe
5f077cc33a Merge pull request #9858 from dampfklon/fix-dockerfile-v6
Add new php extension dependencies for v6
2021-07-27 14:32:23 -07:00
Dampfklon
20df7be2f4 add new php extensions dependencies for v6 2021-07-24 23:15:17 +02:00
Godfrey M
013e168883 adds newer versions of devices for demo 2021-07-21 15:12:27 -07:00
Ivan Nieto Vivanco
35ffe8b902 Adds a check to know if the asset is checked out to the logged in user to allow check the state int the view 2021-07-20 18:56:22 -05:00
Petri Asikainen
f753404197 missed this when rebasing 2021-07-15 12:26:14 +03:00
Petri Asikainen
5d999d2572 legacy image_source support for store 2021-07-15 12:26:14 +03:00
Petri Asikainen
d50294e8e2 Just mention source of idea as code rewriten 2021-07-15 12:26:14 +03:00
Petri Asikainen
2fc3ff671e hand legacy image_source field 2021-07-15 12:26:14 +03:00
Petri Asikainen
89cc84f1d9 convert image_source field
This reverts commit b2d3ba7410.
2021-07-15 12:26:14 +03:00
Petri Asikainen
f24138da44 Revert "Handle image_source with ConvertBase64ToFiles"
This reverts commit 168d7f7004.
2021-07-15 12:26:14 +03:00
Petri Asikainen
a76b36cad9 Handle image_source with ConvertBase64ToFiles 2021-07-15 12:26:14 +03:00
Petri Asikainen
1936fc2ea9 Better debug comment 2021-07-15 12:26:14 +03:00
Petri Asikainen
23f77b2894 Fixed case again 2021-07-15 12:26:14 +03:00
Petri Asikainen
15dd7061ed removed unused Bag-functions 2021-07-15 12:26:14 +03:00
Petri Asikainen
5f81488679 fix debug placement 2021-07-15 12:26:14 +03:00
Petri Asikainen
c894e8ceb3 handle files via standard field 2021-07-15 12:26:14 +03:00
Petri Asikainen
bbe964c6b2 debug trait 2021-07-15 12:26:14 +03:00
Petri Asikainen
2325b1d8c2 Try without trait 2021-07-15 12:26:14 +03:00
Petri Asikainen
948a741935 case case again.. 2021-07-15 12:26:14 +03:00
Petri Asikainen
d7d3681d71 trait base64 encoded files 2021-07-15 12:26:13 +03:00
Petri Asikainen
e6d432423d trait base64 encoded files 2021-07-15 12:26:13 +03:00
Petri Asikainen
6173aaa25c fixed capitalization 2021-07-15 12:26:13 +03:00
Petri Asikainen
91af3f2661 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
4191dd39ea Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
2f3501bdc2 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
f1b8ce0a1b Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
6a21660c14 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
64c8767e81 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
0e7af80806 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
e95b15d553 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
bb269e0e5f Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
60f13c8d79 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
5081ca3512 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
b4380c8012 Support images and multipart requests 2021-07-15 12:26:13 +03:00
Petri Asikainen
f6766c5f23 Support images and multipart requests 2021-07-15 12:26:07 +03:00
Petri Asikainen
8bbbb06c5e testing image upload via api 2021-07-15 12:24:25 +03:00
snipe
06806341c7 Nicer tab names for permissions
Signed-off-by: snipe <snipe@snipe.net>
2021-07-08 15:57:41 -07:00
Tobias Regnery
9e1d7ffb5d Fix scope of departments for FullMultipleCompanySupport
If a user tries to view or edit a department from a different company
with FullMultipleCompanySupport enabled, there is a 403 error displayed.
Apply the correct company scope in order to only display the departments
from the own company in the departments view.

Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
2021-07-06 09:45:46 +02:00
snipe
533c3f1651 Fixed incorrect resource route
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 20:58:04 -07:00
snipe
a12ae19e32 Try deferring the load so it doesn’t query the server server 7 times for login
This doesn’t work?

Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 10:50:32 -07:00
snipe
50a644a2c0 Did I seriously spell my own goddamned name wrong in the docblock??
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 10:28:00 -07:00
snipe
3332bbe072 Removed unused properties on login
This may be dumb anyway - we probably don’t need to make so many round trips to the server just to see if things are required or not… But I’d really like to standardize the validation across the system

Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 10:27:44 -07:00
snipe
c517ec849d Small refactor for login Livewire
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 10:05:23 -07:00
snipe
ca41e2b7f3 Fixed typo in ansible playbook
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 07:59:12 -07:00
snipe
8780fa0a26 Use correct auth failure message
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 07:46:39 -07:00
snipe
d5881523d9 Removed unused translations
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 07:46:27 -07:00
snipe
704eb728bc Added livewire the login screen
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 02:16:57 -07:00
snipe
576e605f73 Make livewire less assy looking
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 22:40:18 -07:00
snipe
ebb0aa5532 Merge pull request #9766 from uberbrady/livewire_integration_v6
Livewire integration for Snipe-IT v6
2021-06-28 21:51:00 -07:00
Brady Wetherington
f3427ee670 Tweak to composer packages to get it to composer install correctly 2021-06-28 21:08:05 -07:00
Brady Wetherington
a6ac4f94f1 Breaking out field-listing into its own Livewire blade for use elsewhere 2021-06-28 21:00:20 -07:00
Brady Wetherington
ea1f1eb972 Get some basic Livewire going for 'edit model's default values. 2021-06-28 21:00:20 -07:00
Brady Wetherington
8e66abb926 Basic Laravel7 compatibility, starting getting Livewire going 2021-06-28 21:00:16 -07:00
snipe
dc125af029 Fixed locations link on homepage module
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 19:56:41 -07:00
snipe
2365634139 Added dashboard module for locations [ch9199]
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 19:46:56 -07:00
snipe
4af247f845 Added additional boxes to the dashboard
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 16:36:15 -07:00
snipe
d4e46ee41f Added comma in US currency format [ch16628]
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 16:14:32 -07:00
snipe
68c751fe63 Break out name into first name and last name [ch1382]
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 15:55:33 -07:00
snipe
a016f4ecd0 Applies PR #9761 to integration
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 13:11:22 -07:00
snipe
7af4c3a15f Fixed incorrect maintenances route
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 21:06:19 -07:00
snipe
d20c425a56 Un-donked assets
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 20:10:06 -07:00
snipe
1ea843248b Fixed #9729 - bulk edit order number capped at 20
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 20:04:45 -07:00
snipe
bdc285cebf Merge branch 'develop-v6-integration' of https://github.com/snipe/snipe-it into develop-v6-integration 2021-06-23 20:02:49 -07:00
snipe
71a53b3cbb Merge pull request #9741 from uberbrady/develop-v6-integration
Removed Ziggy.baseUrl references for meta references that already had baseUrl
2021-06-23 20:02:32 -07:00
Brady Wetherington
8268aca9fc Removed Ziggy.baseUrl references for meta references that had baseUrl 2021-06-23 19:57:45 -07:00
snipe
2e6bac7db5 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 18:36:43 -07:00
snipe
d037ec5b9c Dev assets
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 18:08:50 -07:00
snipe
2218155700 Remove phantomJS
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 18:04:00 -07:00
snipe
32a6fa5f0c Pushed less changes into integration branch
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 18:00:33 -07:00
snipe
b3ec4bb31b Porting PR #9720 to v6 integration
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 14:28:06 -07:00
snipe
6e7ef585e4 Merge branch 'develop-v6-integration' of https://github.com/snipe/snipe-it into develop-v6-integration 2021-06-23 14:27:26 -07:00
snipe
58d674cca8 Merge pull request #9737 from uberbrady/develop-v6-integration
Develop v6 integration
2021-06-23 11:25:40 -07:00
Brady Wetherington
17aab61987 Some fixes to some typos in other routes, commeting out parameters parameter which seems crashy 2021-06-22 18:58:25 -07:00
Brady Wetherington
9456a03a88 Almost finished with the routes which is...hopefully? The last thing? 2021-06-22 16:58:23 -07:00
snipe
dc157f8f78 Add components and users count to dashboard
Signed-off-by: snipe <snipe@snipe.net>
2021-06-19 16:16:18 -07:00
snipe
60538508d4 Added missing route
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 01:51:53 -07:00
snipe
17fb56d3b9 More updated routes
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 01:35:29 -07:00
snipe
346d879344 Updated routes
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 01:05:20 -07:00
snipe
14ac7a2181 Updated API routes
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 00:42:34 -07:00
snipe
aebb30cea8 Fixed Cors wildcard
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 00:23:51 -07:00
snipe
c407b52bbf Updated Cors
Signed-off-by: snipe <snipe@snipe.net>
2021-06-12 00:23:30 -07:00
snipe
b5ddc637b8 Merge branch 'develop-v6-integration' of https://github.com/snipe/snipe-it into develop-v6-integration 2021-06-11 22:20:02 -07:00
snipe
7f74b65834 Merge pull request #9704 from uberbrady/develop-v6-integration
Get it so that we can re-build assets.
2021-06-11 22:19:51 -07:00
snipe
226b208f7c Reset handler to stock for now
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 22:19:10 -07:00
Brady Wetherington
5b42481d8f Get it so that we can re-build assets. 2021-06-11 21:54:29 -07:00
snipe
c08f70b03c Restore exeption handler functionality
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 21:51:28 -07:00
snipe
9e0e952576 Updated composer
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 20:12:39 -07:00
snipe
1b70b533aa Merge branch 'develop-v6-integration' of https://github.com/snipe/snipe-it into develop-v6-integration 2021-06-11 19:41:57 -07:00
snipe
b30bbe1740 Fixed more factories
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 19:41:20 -07:00
snipe
b3e9c51584 Merge pull request #9703 from uberbrady/develop-v6-integration
Remove barryvdh's laravel-cors for fruitcake's laravel-cors
2021-06-11 19:25:11 -07:00
Brady Wetherington
0118ff8a78 Remove barryvdh's laravel-cors for fruitcake's laravel-cors 2021-06-11 19:12:43 -07:00
snipe
b7f45d2ae2 Re-emable auth routes
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 19:02:25 -07:00
snipe
fa786e615e Moved HasFactory
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 19:02:19 -07:00
snipe
2ed2007888 Merge pull request #9702 from uberbrady/develop-v6-integration
Finished fixing the web routes file
2021-06-11 17:15:35 -07:00
Brady Wetherington
42316f3ba7 Finished fixing the web routes file and put a gigantic warning in the api routes file 2021-06-11 17:12:06 -07:00
snipe
ebfb3ed5b7 Merge pull request #9699 from uberbrady/develop-v6-integration
Basic fixes to at least get the dashboard up
2021-06-11 15:56:59 -07:00
Brady Wetherington
fc5c0a0e95 Basic fixes to at least get the dashboard up 2021-06-11 15:23:44 -07:00
snipe
3095a78664 Small tweaks to Dashboard controller
Still gettiing a bizarre `Non-static method App\Http\Controllers\DashboardController::index() should not be called statically` error

Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 14:43:47 -07:00
snipe
2cddd7faf0 Fixed filesystem config
Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 14:26:10 -07:00
snipe
a5f144b4e0 Merge branch 'shift-46327' into develop-v6-integration
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2021-06-11 14:10:10 -07:00
snipe
a8123092af Misc fixes for shift
// TODO - re-fix the exception handler

Signed-off-by: snipe <snipe@snipe.net>
2021-06-11 14:07:50 -07:00
Laravel Shift
b62d1f49e4 Shift cleanup 2021-06-10 20:19:27 +00:00
Laravel Shift
9838c0c2ef Upgrade to Laravel Mix 6 2021-06-10 20:18:15 +00:00
Laravel Shift
8b82262777 Shift return type of base TestCase methods
From the [PHPUnit 8 release notes][1], the `TestCase` methods below now declare a `void` return type:

- `setUpBeforeClass()`
- `setUp()`
- `assertPreConditions()`
- `assertPostConditions()`
- `tearDown()`
- `tearDownAfterClass()`
- `onNotSuccessfulTest()`

[1]: https://phpunit.de/announcements/phpunit-8.html
2021-06-10 20:18:12 +00:00
Laravel Shift
30607ac268 Shift Laravel dependencies 2021-06-10 20:18:11 +00:00
Laravel Shift
7e93086dd4 Default config files
In an effort to make upgrading the constantly changing config files
easier, Shift defaulted them and merged your true customizations -
where ENV variables may not be used.
2021-06-10 20:18:10 +00:00
Laravel Shift
cc3c59bf97 Shift config files 2021-06-10 20:18:10 +00:00
Laravel Shift
c367fa7e40 Shift PSR-4 autoloading 2021-06-10 20:18:01 +00:00
Laravel Shift
c90b1c6a43 Namespace seeders 2021-06-10 20:18:00 +00:00
Laravel Shift
104b441e0d Shift to class based factories 2021-06-10 20:17:44 +00:00
Laravel Shift
c02a95e73f Ignore temporary framework files 2021-06-10 20:17:22 +00:00
Laravel Shift
3c40c6fe25 Shift console routes 2021-06-10 20:17:20 +00:00
Laravel Shift
9f43ce97e9 Convert deprecated $dates property to $casts 2021-06-10 20:17:18 +00:00
Laravel Shift
bdf23e472e Shift to class based routes 2021-06-10 20:17:14 +00:00
Laravel Shift
ddc8b8648b Shift service providers 2021-06-10 20:17:07 +00:00
Laravel Shift
4ed3d6afb8 Shift HTTP kernel and middleware 2021-06-10 20:17:04 +00:00
Laravel Shift
ec0dc681ba Shift core files 2021-06-10 20:16:59 +00:00
Laravel Shift
802dc9240d Shift bindings
PHP 5.5.9+ adds the new static `class` property which provides the fully qualified class name. This is preferred over using class name strings as these references are checked by the parser.
2021-06-10 20:16:56 +00:00
Laravel Shift
934afa036f Adopt Laravel coding style
Shift automatically applies the Laravel coding style - which uses the PSR-2 coding style as a base with some minor additions.

You may customize the adopted coding style by adding your own [PHP CS Fixer][1] `.php_cs` config file to your project root. Feel free to use [Shift's Laravel ruleset][2] to help you get started.

[1]: https://github.com/FriendsOfPHP/PHP-CS-Fixer
[2]: https://gist.github.com/laravel-shift/cab527923ed2a109dda047b97d53c200
2021-06-10 20:15:52 +00:00
sh1hab
f43413bdc3 Feature snipe#9378 update 2021-05-21 10:19:04 +06:00
sh1hab
cd4b1d8acb Merge branch 'develop' of https://github.com/snipe/snipe-it into feature/remove_deleted_user_from_unaccepted_assets_report 2021-05-21 10:09:05 +06:00
Thomas Misilo
18b1a155bf Change from ENV to config value for PUBLIC_AWS_URL
When running config:cache the env('PUBLIC_AWS'URL') value disappears and isn't available, so it doesn't get added to the CSP Policy.
2021-05-11 09:51:35 -05:00
sh1hab
6799ce9bfd merge develop with remove_deleted_user_from_unaccepted_assets_report 2021-05-05 16:19:14 +06:00
sh1hab
193a8d923b Feature #9378 update phpdoc comment 2021-04-29 16:32:37 +06:00
sh1hab
98a42afa78 Feature #9378 remove deleted user from unaccepted assets report 2021-04-29 15:34:05 +06:00
2938 changed files with 108680 additions and 66588 deletions

View File

@@ -2361,6 +2361,15 @@
"code"
]
},
{
"login": "Delta5",
"name": "Evan Taylor",
"avatar_url": "https://avatars.githubusercontent.com/u/1975640?v=4",
"profile": "https://github.com/Delta5",
"contributions": [
"code"
]
},
{
"login": "PetriAsi",
"name": "Petri Asikainen",
@@ -2468,6 +2477,114 @@
"contributions": [
"code"
]
},
{
"login": "leitwerk-ag",
"name": "LEITWERK AG",
"avatar_url": "https://avatars.githubusercontent.com/u/24418301?v=4",
"profile": "https://www.leitwerk.de/",
"contributions": [
"code"
]
},
{
"login": "adamboutcher",
"name": "Adam",
"avatar_url": "https://avatars.githubusercontent.com/u/1911435?v=4",
"profile": "http://www.aboutcher.co.uk",
"contributions": [
"code"
]
},
{
"login": "sneak-it",
"name": "Ian",
"avatar_url": "https://avatars.githubusercontent.com/u/16104273?v=4",
"profile": "https://snksrv.com",
"contributions": [
"code"
]
},
{
"login": "bestlong",
"name": "Shao Yu-Lung (Allen)",
"avatar_url": "https://avatars.githubusercontent.com/u/4023909?v=4",
"profile": "http://blog.bestlong.idv.tw/",
"contributions": [
"code"
]
},
{
"login": "Haxatron",
"name": "Haxatron",
"avatar_url": "https://avatars.githubusercontent.com/u/76475453?v=4",
"profile": "https://github.com/Haxatron",
"contributions": [
"code"
]
},
{
"login": "PlaneNuts",
"name": "PlaneNuts",
"avatar_url": "https://avatars.githubusercontent.com/u/88776392?v=4",
"profile": "https://github.com/PlaneNuts",
"contributions": [
"code"
]
},
{
"login": "exula",
"name": "Bradley Coudriet",
"avatar_url": "https://avatars.githubusercontent.com/u/3842948?v=4",
"profile": "http://bjcpgd.cias.rit.edu",
"contributions": [
"code"
]
},
{
"login": "UniversalSuperBox",
"name": "Dalton Durst",
"avatar_url": "https://avatars.githubusercontent.com/u/21966173?v=4",
"profile": "https://daltondur.st",
"contributions": [
"code"
]
},
{
"login": "adagioajanes",
"name": "Alex Janes",
"avatar_url": "https://avatars.githubusercontent.com/u/38761237?v=4",
"profile": "https://adagiohealth.org",
"contributions": [
"code"
]
},
{
"login": "nuraeil",
"name": "Nuraeil",
"avatar_url": "https://avatars.githubusercontent.com/u/32387849?v=4",
"profile": "https://github.com/nuraeil",
"contributions": [
"code"
]
},
{
"login": "TenOfTens",
"name": "TenOfTens",
"avatar_url": "https://avatars.githubusercontent.com/u/48162670?v=4",
"profile": "https://github.com/TenOfTens",
"contributions": [
"code"
]
},
{
"login": "insert-waffle",
"name": "waffle",
"avatar_url": "https://avatars.githubusercontent.com/u/9415391?v=4",
"profile": "https://ditisjens.be/",
"contributions": [
"code"
]
}
]
}

105
.env.dusk.local Normal file
View File

@@ -0,0 +1,105 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=local
APP_DEBUG=false
APP_KEY=base64:hTUIUh9CP6dQx+6EjSlfWTgbaMaaRvlpEwk45vp+xmk=
APP_URL=http://127.0.0.1:8000
APP_TIMEZONE='US/Eastern'
APP_LOCALE=en
APP_LOCKED=false
MAX_RESULTS=200
# --------------------------------------------
# REQUIRED: UPLOADED FILE STORAGE SETTINGS
# --------------------------------------------
PRIVATE_FILESYSTEM_DISK=local
PUBLIC_FILESYSTEM_DISK=local_public
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=snipeit-local
DB_USERNAME=snipeit-local
DB_PASSWORD=snipeit-local
DB_PREFIX=null
DB_DUMP_PATH='/Applications/MAMP/Library/bin'
# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS
# --------------------------------------------
DB_SSL=false
DB_SSL_KEY_PATH=null
DB_SSL_CERT_PATH=null
DB_SSL_CA_PATH=null
DB_SSL_CIPHER=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER="log"
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
# This should be gd or imagick
# --------------------------------------------
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=true
COOKIE_NAME=snipeit_v5_local
SECURE_COOKIES=true
# --------------------------------------------
# OPTIONAL: SECURITY HEADER SETTINGS
# --------------------------------------------
REFERRER_POLICY=same-origin
ENABLE_CSP=true
CORS_ALLOWED_ORIGINS="*"
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: LOGIN THROTTLING
# --------------------------------------------
LOGIN_MAX_ATTEMPTS=50000
LOGIN_LOCKOUT_DURATION=1000
RESET_PASSWORD_LINK_EXPIRES=15
# --------------------------------------------
# OPTIONAL: API
# --------------------------------------------
API_MAX_REQUESTS_PER_HOUR=200
# --------------------------------------------
# OPTIONAL: SAML SETTINGS
# --------------------------------------------
DISABLE_NOSAML_LOCAL_LOGIN=true
# --------------------------------------------
# OPTIONAL: MISC
# --------------------------------------------
APP_LOG=single
LOG_LEVEL=debug
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=null
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
ALLOW_IFRAMING=true
ENABLE_HSTS=false
WARN_DEBUG=false
APP_CIPHER=AES-256-CBC

View File

@@ -15,6 +15,10 @@ MAX_RESULTS=500
PRIVATE_FILESYSTEM_DISK=local
PUBLIC_FILESYSTEM_DISK=local_public
#PRIVATE_FILESYSTEM_DISK=s3_private
#PUBLIC_FILESYSTEM_DISK=s3_public
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
@@ -145,10 +149,12 @@ APP_LOG_MAX_FILES=10
APP_LOCKED=false
APP_CIPHER=AES-256-CBC
APP_FORCE_TLS=false
APP_ALLOW_INSECURE_HOSTS=false
GOOGLE_MAPS_API=
LDAP_MEM_LIM=500M
LDAP_TIME_LIM=600
IMPORT_TIME_LIMIT=600
IMPORT_MEMORY_LIMIT=500M
REPORT_TIME_LIMIT=12000
REQUIRE_SAML=false
API_THROTTLE_PER_MINUTE=120

View File

@@ -1,10 +1,10 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing-ci
APP_ENV='testing-ci'
APP_DEBUG=false
APP_KEY=ChangeMe
APP_URL=http://localhost:8000
APP_KEY='base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU='
APP_URL='http://localhost:8000'
APP_TIMEZONE='US/Pacific'
APP_LOCALE=en
FILESYSTEM_DISK=local
@@ -12,9 +12,9 @@ FILESYSTEM_DISK=local
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_CONNECTION=sqlite
DB_HOST=localhost
DB_DATABASE=snipeit_unit
DB_DATABASE='sqlite_testing'
DB_USERNAME=root
DB_PASSWORD=null
@@ -22,13 +22,7 @@ DB_PASSWORD=null
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER=log
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=YOURUSERNAME
MAIL_PASSWORD=YOURPASSWORD
MAIL_ENCRYPTION=null
MAIL_FROM_ADDR=you@example.com
MAIL_FROM_NAME=Snipe-IT
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
@@ -37,37 +31,7 @@ MAIL_FROM_NAME=Snipe-IT
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET_ACCESS_KEY=null
AWS_ACCESS_KEY_ID=null
AWS_DEFAULT_REGION=null
AWS_BUCKET=null
AWS_BUCKET_ROOT=null
AWS_URL=null
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=false
COOKIE_NAME=snipeittest_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: APP LOG FORMAT
# --------------------------------------------
APP_LOG=single
APP_LOG=single

82
.github/workflows/docker-alpine.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
# Snipe-IT (Alpine) Docker image build for hub.docker.com
name: Docker images (Alpine)
# Run this Build for all pushes to 'master' or develop branch, or tagged releases.
# Also run for PRs to ensure PR doesn't break Docker build process
on:
push:
branches:
- master
- develop
tags:
- 'v**'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
pull_request:
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
if: github.repository == 'snipe/snipe-it'
runs-on: ubuntu-latest
env:
# Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
# For a new commit on default branch (master), use the literal tag 'latest' on Docker image.
# For a new commit on other branches, use the branch name as the tag for Docker image.
# For a new tag, copy that tag name as the tag for Docker image.
IMAGE_TAGS: |
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
type=ref,event=tag,suffix=-alpine
# Define default tag "flavor" for docker/metadata-action per
# https://github.com/docker/metadata-action#flavor-input
# We turn off 'latest' tag by default.
TAGS_FLAVOR: |
latest=false
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v2
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
###############################################
# Build/Push the 'snipe/snipe-it' image
###############################################
# https://github.com/docker/metadata-action
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v3
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
flavor: ${{ env.TAGS_FLAVOR }}
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.alpine
platforms: linux/amd64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build.outputs.tags }}
labels: ${{ steps.meta_build.outputs.labels }}

82
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
# Snipe-IT Docker image build for hub.docker.com
name: Docker images
# Run this Build for all pushes to 'master' or develop branch, or tagged releases.
# Also run for PRs to ensure PR doesn't break Docker build process
on:
push:
branches:
- master
- develop
tags:
- 'v**'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
pull_request:
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
if: github.repository == 'snipe/snipe-it'
runs-on: ubuntu-latest
env:
# Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
# For a new commit on default branch (master), use the literal tag 'latest' on Docker image.
# For a new commit on other branches, use the branch name as the tag for Docker image.
# For a new tag, copy that tag name as the tag for Docker image.
IMAGE_TAGS: |
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=tag
# Define default tag "flavor" for docker/metadata-action per
# https://github.com/docker/metadata-action#flavor-input
# We turn off 'latest' tag by default.
TAGS_FLAVOR: |
latest=false
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v2
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
###############################################
# Build/Push the 'snipe/snipe-it' image
###############################################
# https://github.com/docker/metadata-action
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v3
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
flavor: ${{ env.TAGS_FLAVOR }}
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build.outputs.tags }}
labels: ${{ steps.meta_build.outputs.labels }}

2
.nvmrc
View File

@@ -1 +1 @@
v10.15.1
v12.22.1

View File

@@ -1,5 +1,5 @@
FROM ubuntu:focal
LABEL maintainer Brady Wetherington <bwetherington@grokability.com>
FROM ubuntu:20.04
LABEL maintainer="Brady Wetherington <bwetherington@grokability.com>"
# No need to add `apt-get clean` here, reference:
# - https://github.com/snipe/snipe-it/pull/9201
@@ -41,6 +41,7 @@ libmcrypt-dev \
php7.4-dev \
ca-certificates \
unzip \
dnsutils \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -77,6 +78,8 @@ COPY . /var/www/html
RUN a2enmod rewrite
COPY docker/column-statistics.cnf /etc/mysql/conf.d/column-statistics.cnf
############ INITIAL APPLICATION SETUP #####################
WORKDIR /var/www/html
@@ -135,4 +138,4 @@ RUN chmod +x /startup.sh /usr/bin/supervisor-exit-event-listener
CMD ["/startup.sh"]
EXPOSE 80
EXPOSE 443
EXPOSE 443

View File

@@ -1,4 +1,4 @@
FROM alpine:3
FROM alpine:3.14.2
# Apache + PHP
RUN apk add --no-cache \
apache2 \
@@ -25,6 +25,8 @@ RUN apk add --no-cache \
php7-session \
php7-dom \
php7-xmlwriter \
php7-xmlreader \
php7-sodium \
curl \
wget \
vim \
@@ -32,6 +34,8 @@ RUN apk add --no-cache \
mysql-client \
tini
COPY docker/column-statistics.cnf /etc/mysql/conf.d/column-statistics.cnf
# Where apache's PID lives
RUN mkdir -p /run/apache2 && chown apache:apache /run/apache2
@@ -80,4 +84,4 @@ ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]
EXPOSE 80
EXPOSE 80

View File

@@ -98,5 +98,6 @@ VOLUME [ "/var/lib/snipeit" ]
COPY --chown=www-data:www-data docker/docker-secrets.env /var/www/html/.env
COPY --chmod=655 docker/docker-entrypoint.sh /usr/local/bin/docker-snipeit-entrypoint
COPY docker/column-statistics.cnf /etc/mysql/conf.d/column-statistics.cnf
ENTRYPOINT [ "/usr/local/bin/docker-snipeit-entrypoint" ]
CMD [ "/usr/local/bin/docker-php-entrypoint", "php-fpm" ]

View File

@@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-271-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-284-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@@ -128,8 +128,10 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") |
| [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") |
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [<img src="https://avatars.githubusercontent.com/u/11973217?v=4" width="110px;"/><br /><sub>tbrconnect</sub>](https://github.com/tbrconnect)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") | [<img src="https://avatars.githubusercontent.com/u/12447225?v=4" width="110px;"/><br /><sub>kcoyo</sub>](https://github.com/kcoyo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kcoyo "Code") | [<img src="https://avatars.githubusercontent.com/u/494017?v=4" width="110px;"/><br /><sub>Travis Miller</sub>](https://travismiller.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=travismiller "Code") |
| [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") | [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -2,10 +2,10 @@
namespace App\Console\Commands;
use App\Models\LicenseSeat;
use Illuminate\Console\Command;
use App\Models\User;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
class CheckinLicensesFromAllUsers extends Command
@@ -41,55 +41,48 @@ class CheckinLicensesFromAllUsers extends Command
*/
public function handle()
{
$license_id = $this->option('license_id');
$notify = $this->option('notify');
if (!$license_id) {
if (! $license_id) {
$this->error('ERROR: License ID is required.');
return false;
}
if (!$license = License::where('id','=',$license_id)->first()) {
if (! $license = License::where('id', '=', $license_id)->first()) {
$this->error('Invalid license ID');
return false;
}
$this->info('Checking in ALL seats for '.$license->name);
$licenseSeats = LicenseSeat::where('license_id', '=', $license_id)
->whereNotNull('assigned_to')
->with('user')
->get();
$this->info(' There are ' .$licenseSeats->count(). ' seats checked out: ');
$this->info(' There are '.$licenseSeats->count().' seats checked out: ');
if (!$notify) {
if (! $notify) {
$this->info('No mail will be sent.');
}
foreach ($licenseSeats as $seat) {
$this->info($seat->user->username .' has a license seat for '.$license->name);
$this->info($seat->user->username.' has a license seat for '.$license->name);
$seat->assigned_to = null;
if ($seat->save()) {
// Override the email address so we don't notify on checkin
if (!$notify) {
if (! $notify) {
$seat->user->email = null;
}
// Log the checkin
$seat->logCheckin($seat->user, 'Checked in via cli tool');
}
}
}
}

View File

@@ -2,10 +2,10 @@
namespace App\Console\Commands;
use App\Models\LicenseSeat;
use Illuminate\Console\Command;
use App\Models\User;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
class CheckoutLicenseToAllUsers extends Command
@@ -41,18 +41,18 @@ class CheckoutLicenseToAllUsers extends Command
*/
public function handle()
{
$license_id = $this->option('license_id');
$notify = $this->option('notify');
if (!$license_id) {
$this->error('ERROR: License ID is required.');
return false;
if (! $license_id) {
$this->error('ERROR: License ID is required.');
return false;
}
if (!$license = License::where('id','=',$license_id)->with('assignedusers')->first()) {
if (! $license = License::where('id', '=', $license_id)->with('assignedusers')->first()) {
$this->error('Invalid license ID');
return false;
}
@@ -64,7 +64,7 @@ class CheckoutLicenseToAllUsers extends Command
$this->info('Checking out '.$users->count().' of '.$license->getAvailSeatsCountAttribute().' seats for '.$license->name);
if (!$notify) {
if (! $notify) {
$this->info('No mail will be sent.');
}
@@ -74,14 +74,14 @@ class CheckoutLicenseToAllUsers extends Command
// to them
if ($user->licenses->where('id', '=', $license_id)->count()) {
$this->info($user->username .' already has this license checked out to them. Skipping... ');
$this->info($user->username.' already has this license checked out to them. Skipping... ');
continue;
}
// If the license is valid, check that there is an available seat
if ($license->availCount()->count() < 1) {
$this->error('ERROR: No available seats');
return false;
}
@@ -89,13 +89,12 @@ class CheckoutLicenseToAllUsers extends Command
// Get the seat ID
$licenseSeat = $license->freeSeat();
// Update the seat with checkout info,
$licenseSeat->assigned_to = $user->id;
$licenseSeat->assigned_to = $user->id;
if ($licenseSeat->save()) {
// Temporarily null the user's email address so we don't send mail if we're not supposed to
if (!$notify) {
if (! $notify) {
$user->email = null;
}
@@ -103,10 +102,6 @@ class CheckoutLicenseToAllUsers extends Command
$licenseSeat->logCheckout('Checked out via cli tool', $user);
$this->info('License '.$license_id.' seat '.$licenseSeat->id.' checked out to '.$user->username);
}
}
}
}

View File

@@ -37,7 +37,6 @@ class CreateAdmin extends Command
*/
public function handle()
{
$first_name = $this->option('first_name');
$last_name = $this->option('last_name');
$username = $this->option('username');
@@ -45,7 +44,7 @@ class CreateAdmin extends Command
$password = $this->option('password');
$show_in_list = $this->argument('show_in_list');
if (($first_name=='') || ($last_name=='') || ($username=='') || ($email=='') || ($password=='')) {
if (($first_name == '') || ($last_name == '') || ($username == '') || ($email == '') || ($password == '')) {
$this->info('ERROR: All fields are required.');
} else {
$user = new \App\Models\User;
@@ -68,12 +67,9 @@ class CreateAdmin extends Command
$errors = $user->getErrors();
foreach ($errors->all() as $error) {
$this->info('ERROR:'. $error);
$this->info('ERROR:'.$error);
}
}
}
}
}

View File

@@ -38,9 +38,7 @@ class DisableLDAP extends Command
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nThis will disable LDAP support. You will not be able \nto login with an account that does not exist \nlocally in the Snipe-IT local database. \n****************************************************\n\nDo you wish to continue? [y|N]")) {
$setting = Setting::getSettings();
$setting->ldap_enabled = 0;
if ($setting->save()) {
@@ -51,6 +49,5 @@ class DisableLDAP extends Command
} else {
$this->info('Canceled. No actions taken.');
}
}
}

View File

@@ -37,49 +37,43 @@ class FixDoubleEscape extends Command
*/
public function handle()
{
$tables = [
'\App\Models\Asset' => ['name'],
'\App\Models\License' => ['name'],
'\App\Models\Consumable' => ['name'],
'\App\Models\Accessory' => ['name'],
'\App\Models\Component' => ['name'],
'\App\Models\Company' => ['name'],
'\App\Models\Manufacturer' => ['name'],
'\App\Models\Supplier' => ['name'],
'\App\Models\Statuslabel' => ['name'],
'\App\Models\Depreciation' => ['name'],
'\App\Models\AssetModel' => ['name'],
'\App\Models\Group' => ['name'],
'\App\Models\Department' => ['name'],
'\App\Models\Location' => ['name'],
'\App\Models\User' => ['first_name', 'last_name'],
\App\Models\Asset::class => ['name'],
\App\Models\License::class => ['name'],
\App\Models\Consumable::class => ['name'],
\App\Models\Accessory::class => ['name'],
\App\Models\Component::class => ['name'],
\App\Models\Company::class => ['name'],
\App\Models\Manufacturer::class => ['name'],
\App\Models\Supplier::class => ['name'],
\App\Models\Statuslabel::class => ['name'],
\App\Models\Depreciation::class => ['name'],
\App\Models\AssetModel::class => ['name'],
\App\Models\Group::class => ['name'],
\App\Models\Department::class => ['name'],
\App\Models\Location::class => ['name'],
\App\Models\User::class => ['first_name', 'last_name'],
];
$count = array();
$count = [];
foreach ($tables as $classname => $fields) {
$count[$classname] = [];
$count[$classname]['classname'] = 0;
foreach ($fields as $field) {
$count[$classname]['classname']++;
$count[$classname][$field] = 0;
foreach ($tables as $classname => $fields) {
$count[$classname] = array();
$count[$classname]['classname'] = 0;
foreach($fields as $field) {
$count[$classname]['classname']++;
$count[$classname][$field] = 0;
foreach($classname::where("$field",'LIKE','%&%')->get() as $row) {
$this->info('Updating '.$field.' for '.$classname);
$row->{$field} = html_entity_decode($row->{$field},ENT_QUOTES);
$row->save();
$count[$classname][$field]++;
}
foreach ($classname::where("$field", 'LIKE', '%&%')->get() as $row) {
$this->info('Updating '.$field.' for '.$classname);
$row->{$field} = html_entity_decode($row->{$field}, ENT_QUOTES);
$row->save();
$count[$classname][$field]++;
}
}
}
$this->info('Update complete');
}
}

View File

@@ -29,7 +29,6 @@ class FixMismatchedAssetsAndLogs extends Command
*/
private $dryrun = false;
/**
* Create a new command instance.
*
@@ -47,30 +46,29 @@ class FixMismatchedAssetsAndLogs extends Command
*/
public function handle()
{
if ($this->option('dryrun')) {
$this->dryrun = true;
}
if ($this->dryrun) {
$this->info('This is a DRY RUN - no changes will be saved.' );
$this->info('This is a DRY RUN - no changes will be saved.');
}
$mismatch_count = 0;
$assets = Asset::whereNotNull('assigned_to')
->where('assigned_type', '=', 'App\\Models\\User')
->where('assigned_type', '=', \App\Models\User::class)
->orderBy('id', 'ASC')->get();
foreach ($assets as $asset) {
// get the last checkout of the asset
if ($checkout_log = Actionlog::where('target_type', '=', 'App\\Models\\User')
if ($checkout_log = Actionlog::where('target_type', '=', \App\Models\User::class)
->where('action_type', '=', 'checkout')
->where('item_id', '=', $asset->id)
->orderBy('created_at', 'DESC')
->first()) {
// Now check for a subsequent checkin log - we want to ignore those
if (!$checkin_log = Actionlog::where('target_type', '=', 'App\\Models\\User')
if (! $checkin_log = Actionlog::where('target_type', '=', \App\Models\User::class)
->where('action_type', '=', 'checkin from')
->where('item_id', '=', $asset->id)
->whereDate('created_at', '>', $checkout_log->created_at)
@@ -78,28 +76,24 @@ class FixMismatchedAssetsAndLogs extends Command
->first()) {
//print_r($asset);
if ($checkout_log->target_id != $asset->assigned_to) {
$this->error('Log ID: '.$checkout_log->id.' -- Asset ID '. $checkout_log->item_id.' SHOULD BE checked out to User '.$checkout_log->target_id.' but its assigned_to is '.$asset->assigned_to );
if ($checkout_log->target_id != $asset->assigned_to) {
$this->error('Log ID: '.$checkout_log->id.' -- Asset ID '.$checkout_log->item_id.' SHOULD BE checked out to User '.$checkout_log->target_id.' but its assigned_to is '.$asset->assigned_to);
if (!$this->dryrun) {
$asset->assigned_to = $checkout_log->target_id;
if ($asset->save()) {
$this->info('Asset record updated.');
} else {
$this->error('Error updating asset: '.$asset->getErrors());
}
if (! $this->dryrun) {
$asset->assigned_to = $checkout_log->target_id;
if ($asset->save()) {
$this->info('Asset record updated.');
} else {
$this->error('Error updating asset: '.$asset->getErrors());
}
$mismatch_count++;
}
} else {
//$this->info('Asset ID '.$asset->id.': There is a checkin '.$checkin_log->created_at.' after this checkout '.$checkout_log->created_at);
$mismatch_count++;
}
} else {
//$this->info('Asset ID '.$asset->id.': There is a checkin '.$checkin_log->created_at.' after this checkout '.$checkout_log->created_at);
}
}
}
$this->info($mismatch_count.' mismatched assets.');
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Console\Commands;
use App\Models\Location;
use Illuminate\Console\Command;
use League\Csv\Reader;
use App\Models\Location;
class ImportLocations extends Command
{
@@ -39,10 +39,8 @@ class ImportLocations extends Command
*/
public function handle()
{
if (!ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
if (! ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
$filename = $this->argument('filename');
@@ -53,18 +51,17 @@ class ImportLocations extends Command
// Import parent location names first if they don't exist
foreach ($results as $parent_index => $parent_row) {
if (array_key_exists('Parent Name', $parent_row)) {
$parent_name = trim($parent_row['Parent Name']);
if (array_key_exists('Name', $parent_row)) {
$this->info('- Parent: ' . $parent_name . ' in row as: ' . trim($parent_row['Parent Name']));
$this->info('- Parent: '.$parent_name.' in row as: '.trim($parent_row['Parent Name']));
}
// Save parent location name
// This creates a sort of name-stub that we'll update later on in this script
$parent_location = Location::firstOrCreate(array('name' => $parent_name));
$parent_location = Location::firstOrCreate(['name' => $parent_name]);
if (array_key_exists('Name', $parent_row)) {
$this->info('Parent for ' . $parent_row['Name'] . ' is ' . $parent_name . '. Attempting to save ' . $parent_name . '.');
$this->info('Parent for '.$parent_row['Name'].' is '.$parent_name.'. Attempting to save '.$parent_name.'.');
}
// Check if the record was updated or created.
@@ -74,18 +71,15 @@ class ImportLocations extends Command
} else {
$this->info('- Parent location '.$parent_name.' was created.');
}
} else {
$this->info('- No Parent Name provided, so no parent location will be created.');
}
}
$this->info('----- Parents Created.... backfilling additional details... --------');
// Loop through ALL records and add/update them if there are additional fields
// besides name
foreach ($results as $index => $row) {
if (array_key_exists('Parent Name', $row)) {
$parent_name = trim($row['Parent Name']);
} else {
@@ -94,11 +88,12 @@ class ImportLocations extends Command
// Set the location attributes to save
if (array_key_exists('Name', $row)) {
$location = Location::firstOrCreate(array('name' => trim($row['Name'])));
$location = Location::firstOrCreate(['name' => trim($row['Name'])]);
$location->name = trim($row['Name']);
$this->info('Checking location: '.$location->name);
} else {
$this->error('Location name is required and is missing from at least one row in this dataset. Check your CSV for extra trailing rows and try again.');
return false;
}
if (array_key_exists('Currency', $row)) {
@@ -126,7 +121,6 @@ class ImportLocations extends Command
$location->ldap_ou = trim($row['OU']);
}
// If a parent name is provided, we created it earlier in the script,
// so let's grab that ID
if ($parent_name) {
@@ -142,21 +136,15 @@ class ImportLocations extends Command
// Check if the record was updated or created.
// This is mostly for clearer debugging.
if ($location->exists) {
$this->info('Location ' . $location->name . ' already exists. Updating...');
$this->info('Location '.$location->name.' already exists. Updating...');
} else {
$this->info('- Location '.$location->name.' was created. ');
}
// If there's a validation error, display that
// If there's a validation error, display that
} else {
$this->error('- Non-parent Location '.$location->name.' could not be created: '.$location->getErrors() );
$this->error('- Non-parent Location '.$location->name.' could not be created: '.$location->getErrors());
}
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class KillAllSessions extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:global-logout {--force : Skip the danger prompt; assuming you enter "y"} ';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will destroy all web sessions on disk and will force a re-login for all users.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (!$this->option('force') && !$this->confirm("****************************************************\nTHIS WILL FORCE A LOGIN FOR ALL LOGGED IN USERS.\n\nAre you SURE you wish to continue? ")) {
return $this->error("Session loss not confirmed");
}
$session_files = glob(storage_path("framework/sessions/*"));
$count = 0;
foreach ($session_files as $file) {
if (is_file($file))
unlink($file);
$count++;
}
\DB::table('users')->update(['remember_token' => null]);
$this->info($count. ' sessions cleared!');
}
}

View File

@@ -54,7 +54,7 @@ class LdapSync extends Command
$ldap_result_email = Setting::getSettings()->ldap_email;
$ldap_result_phone = Setting::getSettings()->ldap_phone_field;
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
$ldap_result_country = Setting::getSettings()->ldap_country;
$ldap_result_country = Setting::getSettings()->ldap_country;
$ldap_result_dept = Setting::getSettings()->ldap_dept;
try {
@@ -62,14 +62,15 @@ class LdapSync extends Command
Ldap::bindAdminToLdap($ldapconn);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
return [];
}
$summary = array();
$summary = [];
try {
if ($this->option('base_dn') != '') {
@@ -81,78 +82,78 @@ class LdapSync extends Command
$results = Ldap::findLdapUsers($search_base);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
return [];
}
/* Determine which location to assign users to by default. */
$location = NULL; // FIXME - this would be better called "$default_location", which is more explicit about its purpose
$location = null; // TODO - this would be better called "$default_location", which is more explicit about its purpose
if ($this->option('location')!='') {
if ($this->option('location') != '') {
$location = Location::where('name', '=', $this->option('location'))->first();
LOG::debug('Location name '.$this->option('location').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
} elseif ($this->option('location_id')!='') {
} elseif ($this->option('location_id') != '') {
$location = Location::where('id', '=', $this->option('location_id'))->first();
LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
}
if (!isset($location)) {
if (! isset($location)) {
LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
}
/* Process locations with explicitly defined OUs, if doing a full import. */
if ($this->option('base_dn')=='') {
if ($this->option('base_dn') == '') {
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
$ldap_ou_lengths = array();
$ldap_ou_lengths = [];
foreach ($ldap_ou_locations as $ou_loc) {
$ldap_ou_lengths[] = strlen($ou_loc["ldap_ou"]);
$ldap_ou_lengths[] = strlen($ou_loc['ldap_ou']);
}
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (sizeof($ldap_ou_locations) > 0) {
if (count($ldap_ou_locations) > 0) {
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
for ($i = 0; $i < $results['count']; $i++) {
$results[$i]['ldap_location_override'] = false;
$results[$i]['location_id'] = 0;
}
// Grab subsets based on location-specific DNs, and overwrite location for these users.
foreach ($ldap_ou_locations as $ldap_loc) {
try {
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
} catch (\Exception $e) { // FIXME: this is stolen from line 77 or so above
$location_users = Ldap::findLdapUsers($ldap_loc['ldap_ou']);
} catch (\Exception $e) { // TODO: this is stolen from line 77 or so above
if ($this->option('json_summary')) {
$json_summary = [ "error" => true, "error_message" => trans('admin/users/message.error.ldap_could_not_search')." Location: ".$ldap_loc['name']." (ID: ".$ldap_loc['id'].") cannot connect to \"".$ldap_loc["ldap_ou"]."\" - ".$e->getMessage(), "summary" => [] ];
$json_summary = ['error' => true, 'error_message' => trans('admin/users/message.error.ldap_could_not_search').' Location: '.$ldap_loc['name'].' (ID: '.$ldap_loc['id'].') cannot connect to "'.$ldap_loc['ldap_ou'].'" - '.$e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
return [];
}
$usernames = array();
for ($i = 0; $i < $location_users["count"]; $i++) {
$usernames = [];
for ($i = 0; $i < $location_users['count']; $i++) {
if (array_key_exists($ldap_result_username, $location_users[$i])) {
$location_users[$i]["ldap_location_override"] = true;
$location_users[$i]["location_id"] = $ldap_loc["id"];
$location_users[$i]['ldap_location_override'] = true;
$location_users[$i]['location_id'] = $ldap_loc['id'];
$usernames[] = $location_users[$i][$ldap_result_username][0];
}
}
// Delete located users from the general group.
foreach ($results as $key => $generic_entry) {
if ((is_array($generic_entry)) && (array_key_exists($ldap_result_username, $generic_entry))) {
if ((is_array($generic_entry)) && (array_key_exists($ldap_result_username, $generic_entry))) {
if (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
unset($results[$key]);
}
@@ -166,55 +167,53 @@ class LdapSync extends Command
}
/* Create user account entries in Snipe-IT */
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
$pass = bcrypt($tmp_pass);
for ($i = 0; $i < $results["count"]; $i++) {
if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == "TRUE") {
$item = array();
$item["username"] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : "";
$item["employee_number"] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : "";
$item["lastname"] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : "";
$item["firstname"] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : "";
$item["email"] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : "" ;
$item["ldap_location_override"] = isset($results[$i]["ldap_location_override"]) ? $results[$i]["ldap_location_override"]:"";
$item["location_id"] = isset($results[$i]["location_id"]) ? $results[$i]["location_id"]:"";
$item["telephone"] = isset($results[$i][$ldap_result_phone][0]) ? $results[$i][$ldap_result_phone][0] : "";
$item["jobtitle"] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : "";
$item["country"] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : "";
$item["department"] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : "";
for ($i = 0; $i < $results['count']; $i++) {
if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == 'TRUE') {
$item = [];
$item['username'] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : '';
$item['employee_number'] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : '';
$item['lastname'] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : '';
$item['firstname'] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : '';
$item['email'] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : '';
$item['ldap_location_override'] = isset($results[$i]['ldap_location_override']) ? $results[$i]['ldap_location_override'] : '';
$item['location_id'] = isset($results[$i]['location_id']) ? $results[$i]['location_id'] : '';
$item['telephone'] = isset($results[$i][$ldap_result_phone][0]) ? $results[$i][$ldap_result_phone][0] : '';
$item['jobtitle'] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : '';
$item['country'] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : '';
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
$department = Department::firstOrCreate([
'name' => $item["department"],
'name' => $item['department'],
]);
$user = User::where('username', $item["username"])->first();
$user = User::where('username', $item['username'])->first();
if ($user) {
// Updating an existing user.
$item["createorupdate"] = 'updated';
$item['createorupdate'] = 'updated';
} else {
// Creating a new user.
$user = new User;
$user->password = $pass;
$user->activated = 0;
$item["createorupdate"] = 'created';
$item['createorupdate'] = 'created';
}
$user->first_name = $item["firstname"];
$user->last_name = $item["lastname"];
$user->username = $item["username"];
$user->email = $item["email"];
$user->employee_num = e($item["employee_number"]);
$user->phone = $item["telephone"];
$user->jobtitle = $item["jobtitle"];
$user->country = $item["country"];
$user->first_name = $item['firstname'];
$user->last_name = $item['lastname'];
$user->username = $item['username'];
$user->email = $item['email'];
$user->employee_num = e($item['employee_number']);
$user->phone = $item['telephone'];
$user->jobtitle = $item['jobtitle'];
$user->country = $item['country'];
$user->department_id = $department->id;
// Sync activated state for Active Directory.
if ( array_key_exists('useraccountcontrol', $results[$i]) ) {
if (array_key_exists('useraccountcontrol', $results[$i])) {
/* The following is _probably_ the correct logic, but we can't use it because
some users may have been dependent upon the previous behavior, and this
could cause additional access to be available to users they don't want
@@ -231,7 +230,7 @@ class LdapSync extends Command
} else {
$user->activated = 0;
} */
$enabled_accounts = [
$enabled_accounts = [
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
@@ -240,27 +239,26 @@ class LdapSync extends Command
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'4260352',// 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
'1049088',// 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
'4194816',// 0x400200 NORMAL_ACCOUNT, DONT_REQ_PREAUTH
'4260352', // 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
'1049088', // 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
];
$user->activated = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
$user->activated = (in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts)) ? 1 : 0;
}
// If we're not using AD, and there isn't an activated flag set, activate all users
elseif (empty($ldap_result_active_flag)) {
$user->activated = 1;
$user->activated = 1;
}
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
} elseif ((isset($location)) && (!empty($location))) {
} elseif ((isset($location)) && (! empty($location))) {
if ((is_array($location)) && (array_key_exists('id', $location))) {
$user->location_id = $location['id'];
} elseif (is_object($location)) {
$user->location_id = $location->id;
}
}
$user->ldap_import = 1;
@@ -268,31 +266,30 @@ class LdapSync extends Command
$errors = '';
if ($user->save()) {
$item["note"] = $item["createorupdate"];
$item["status"]='success';
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
} else {
foreach ($user->getErrors()->getMessages() as $key => $err) {
$errors .= $err[0];
}
$item["note"] = $errors;
$item["status"]='error';
$item['note'] = $errors;
$item['status'] = 'error';
}
array_push($summary, $item);
}
}
if ($this->option('summary')) {
for ($x = 0; $x < count($summary); $x++) {
if ($summary[$x]['status']=='error') {
if ($summary[$x]['status'] == 'error') {
$this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was not imported: '.$summary[$x]['note']);
} else {
$this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was '.strtoupper($summary[$x]['createorupdate']).'.');
}
}
} else if ($this->option('json_summary')) {
$json_summary = [ "error" => false, "error_message" => "", "summary" => $summary ]; // hardcoding the error to false and the error_message to blank seems a bit weird
} elseif ($this->option('json_summary')) {
$json_summary = ['error' => false, 'error_message' => '', 'summary' => $summary]; // hardcoding the error to false and the error_message to blank seems a bit weird
$this->info(json_encode($json_summary));
} else {
return $summary;

View File

@@ -1,399 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use Log;
use Exception;
use App\Models\User;
use App\Services\LdapAd;
use App\Models\Location;
use Illuminate\Console\Command;
use Adldap\Models\User as AdldapUser;
/**
* LDAP / AD sync command.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
class LdapSyncNg extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:ldap-sync-ng
{--location= : A location name }
{--location_id= : A location id}
{--base_dn= : A diffrent base DN to use }
{--summary : Print summary }
{--json_summary : Print summary in json format }
{--dryrun : Run the sync process but don\'t update the database}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command line LDAP/AD sync';
/**
* An LdapAd instance.
*
* @var \App\Models\LdapAd
*/
private $ldap;
/**
* LDAP settings collection.
*
* @var \Illuminate\Support\Collection
*/
private $settings = null;
/**
* A default location collection.
*
* @var \Illuminate\Support\Collection
*/
private $defaultLocation = null;
/**
* Mapped locations collection.
*
* @var \Illuminate\Support\Collection
*/
private $mappedLocations = null;
/**
* The summary collection.
*
* @var \Illuminate\Support\Collection
*/
private $summary;
/**
* Is dry-run?
*
* @var bool
*/
private $dryrun = false;
/**
* Show users to be imported.
*
* @var array
*/
private $userlist = [];
/**
* Create a new command instance.
*/
public function __construct(LdapAd $ldap)
{
parent::__construct();
$this->ldap = $ldap;
$this->settings = $this->ldap->ldapSettings;
$this->summary = collect();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$dispatcher = \Adldap\Adldap::getEventDispatcher();
// Listen for all model events.
$dispatcher->listen('Adldap\Models\Events\*', function ($eventName, array $data) {
echo $eventName; // Returns 'Adldap\Models\Events\Updating'
var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating;
\Log::debug("Event: ".$eventName." data - ".print_r($data, true));
});
$dispatcher->listen('Adldap\Auth\Events\*', function ($eventName, array $data) {
echo $eventName; // Returns 'Adldap\Models\Events\Updating'
var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating;
\Log::debug("Event: ".$eventName." data - ".print_r($data, true));
});
ini_set('max_execution_time', env('LDAP_TIME_LIM', "600")); //600 seconds = 10 minutes
ini_set('memory_limit', '500M');
$old_error_reporting = error_reporting(); // grab old error_reporting .ini setting, for later re-enablement
error_reporting($old_error_reporting & ~E_DEPRECATED); // disable deprecation warnings, for LDAP in PHP 7.4 (and greater)
if ($this->option('dryrun')) {
$this->dryrun = true;
}
$this->checkIfLdapIsEnabled();
$this->checkLdapConnection();
$this->setBaseDn();
$this->getUserDefaultLocation();
/*
* Use the default location if set, this is needed for the LDAP users sync page
*/
if (!$this->option('base_dn') && null == $this->defaultLocation) {
$this->getMappedLocations();
}
$this->processLdapUsers();
// Print table of users
if ($this->dryrun) {
$this->info('The following users will be synced!');
$headers = ['First Name', 'Last Name', 'Username', 'Email', 'Employee #', 'Location Id', 'Status'];
$this->table($headers, $this->summary->toArray());
}
error_reporting($old_error_reporting); // re-enable deprecation warnings.
return $this->getSummary();
}
/**
* Generate the LDAP sync summary.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @return string
*/
private function getSummary(): string
{
if ($this->option('summary') && null === $this->dryrun) {
$this->summary->each(function ($item) {
$this->info('USER: '.$item['note']);
if ('ERROR' === $item['status']) {
$this->error('ERROR: '.$item['note']);
}
});
} elseif ($this->option('json_summary')) {
$json_summary = [
'error' => false,
'error_message' => '',
'summary' => $this->summary->toArray(),
];
$this->info(json_encode($json_summary));
}
return '';
}
/**
* Create a new user or update an existing user.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @param \Adldap\Models\User $snipeUser
*/
private function updateCreateUser(AdldapUser $snipeUser): void
{
$user = $this->ldap->processUser($snipeUser, $this->defaultLocation, $this->mappedLocations);
$summary = [
'firstname' => $user->first_name,
'lastname' => $user->last_name,
'username' => $user->username,
'employee_number' => $user->employee_num,
'email' => $user->email,
'location_id' => $user->location_id,
];
// Only update the database if is not a dry run
if (!$this->dryrun) {
if ($user->isDirty()) { //if nothing on the user changed, don't bother trying to save anything nor put anything in the summary
if ($user->save()) {
$summary['note'] = ($user->wasRecentlyCreated ? 'CREATED' : 'UPDATED');
$summary['status'] = 'SUCCESS';
} else {
$errors = '';
foreach ($user->getErrors()->getMessages() as $error) {
$errors .= implode(", ",$error);
}
$summary['note'] = $snipeUser->getDN().' was not imported. REASON: '.$errors;
$summary['status'] = 'ERROR';
}
} else {
$summary = null;
}
}
// $summary['note'] = ($user->getOriginal('username') ? 'UPDATED' : 'CREATED'); // this seems, kinda, like, superfluous, relative to the $summary['note'] thing above, yeah?
if($summary) { //if the $user wasn't dirty, $summary was set to null so that we will skip the following push()
$this->summary->push($summary);
}
}
/**
* Process the users to update / create.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
*/
private function processLdapUsers(): void
{
try {
\Log::debug("CAL:LING GET LDAP SUSERS");
$ldapUsers = $this->ldap->getLdapUsers();
\Log::debug("END CALLING GET LDAP USERS");
} catch (Exception $e) {
$this->outputError($e);
exit($e->getMessage());
}
if (0 == $ldapUsers->count()) {
$msg = 'ERROR: No users found!';
Log::error($msg);
if ($this->dryrun) {
$this->error($msg);
}
exit($msg);
}
// Process each individual users
foreach ($ldapUsers->getResults() as $user) { // AdLdap2's paginate() method is weird, it gets *everything* and ->getResults() returns *everything*
$this->updateCreateUser($user);
}
}
/**
* Get the mapped locations if a base_dn is provided.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
private function getMappedLocations()
{
$ldapOuLocation = Location::where('ldap_ou', '!=', '')->select(['id', 'ldap_ou'])->get();
$locations = $ldapOuLocation->sortBy(function ($ou, $key) {
return strlen($ou->ldap_ou);
});
if ($locations->count() > 0) {
$msg = 'Some locations have special OUs set. Locations will be automatically set for users in those OUs.';
LOG::debug($msg);
if ($this->dryrun) {
$this->info($msg);
}
$this->mappedLocations = $locations->pluck('ldap_ou', 'id'); // TODO: this seems ok-ish, but the key-> value is going location_id -> OU name, and the primary action here is the opposite of that - going from OU's to location ID's.
}
}
/**
* Set the base dn if supplied.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
private function setBaseDn(): void
{
if ($this->option('base_dn')) {
$this->ldap->baseDn = $this->option('base_dn');
$msg = sprintf('Importing users from specified base DN: "%s"', $this->ldap->baseDn);
LOG::debug($msg);
if ($this->dryrun) {
$this->info($msg);
}
}
}
/**
* Get a default location id for imported users.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
private function getUserDefaultLocation(): void
{
$location = $this->option('location_id') ?? $this->option('location');
if ($location) {
$userLocation = Location::where('name', '=', $location)
->orWhere('id', '=', intval($location))
->select(['name', 'id'])
->first();
if ($userLocation) {
$msg = 'Importing users with default location: '.$userLocation->name.' ('.$userLocation->id.')';
LOG::debug($msg);
if ($this->dryrun) {
$this->info($msg);
}
$this->defaultLocation = collect([
$userLocation->id => $userLocation->name,
]);
} else {
$msg = 'The supplied location is invalid!';
LOG::error($msg);
if ($this->dryrun) {
$this->error($msg);
}
exit(0);
}
}
}
/**
* Check if LDAP intergration is enabled.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
private function checkIfLdapIsEnabled(): void
{
if (false === $this->settings['ldap_enabled']) {
$msg = 'LDAP intergration is not enabled. Exiting sync process.';
$this->info($msg);
Log::info($msg);
exit(0);
}
}
/**
* Check to make sure we can access the server.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*/
private function checkLdapConnection(): void
{
try {
$this->ldap->testLdapAdUserConnection();
$this->ldap->testLdapAdBindConnection();
} catch (Exception $e) {
$this->outputError($e);
exit(0);
}
}
/**
* Output the json summary to the screen if enabled.
*
* @param Exception $error
*/
private function outputError($error): void
{
if ($this->option('json_summary')) {
$json_summary = [
'error' => true,
'error_message' => $error->getMessage(),
'summary' => [],
];
$this->info(json_encode($json_summary));
}
$this->error($error->getMessage());
LOG::error($error);
}
}

View File

@@ -0,0 +1,503 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Setting;
use Exception;
use Crypt;
/**
* Check if a given ip is in a network
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
* @return boolean true if the ip is in this range / false if not.
*/
function ip_in_range( $ip, $range ) {
if ( strpos( $range, '/' ) == false ) {
$range .= '/32';
}
// $range is in IP/CIDR format eg 127.0.0.1/24
list( $range, $netmask ) = explode( '/', $range, 2 );
$range_decimal = ip2long( $range );
$ip_decimal = ip2long( $ip );
$wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
}
// NOTE - this function was shamelessly stolen from this gist: https://gist.github.com/tott/7684443
class LdapTroubleshooter extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ldap:troubleshoot
{--ldap-search : Output an ldapsearch command-line for testing your LDAP config}
{--force : Skip the interactive yes/no prompt for confirmation}
{--debug : Include debugging output (verbose)}
{--trace : Include extremely verbose LDAP trace output}
{--timeout=15 : Timeout for LDAP Bind operations}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Runs a series of non-destructive LDAP commands to help try and determine correct LDAP settings for your environment.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Output something *only* if debug is enabled
*
* @return void
*/
public function debugout($string)
{
if($this->option('debug')) {
$this->line($string);
}
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if($this->option('trace')) {
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
}
$settings = Setting::getSettings();
$this->settings = $settings;
if($this->option('ldap-search')) {
if(!$this->option('force')) {
$confirmation = $this->confirm('WARNING: This command will display your LDAP password on your terminal. Are you sure this is ok?');
if(!$confirmation) {
$this->error('ABORTING');
exit(-1);
}
}
$output = [];
if($settings->ldap_server_cert_ignore) {
$this->line("# Ignoring server certificate validity");
$output[] = "LDAPTLS_REQCERT=never";
}
if($settings->ldap_client_tls_cert && $settings->ldap_client_tls_key) {
$this->line("# Adding LDAP Client Certificate and Key");
$output[] = "LDAPTLS_CERT=storage/ldap_client_tls.cert";
$output[] = "LDAPTLS_KEY=storage/ldap_client_tls.key";
}
$output[] = "ldapsearch";
$output[] = $settings->ldap_server;
$output[] = "-x";
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
if(substr($settings->ldap_filter,0,1) == "(" ) {
$output[] = escapeshellarg($settings->ldap_filter);
} else {
$output[] = escapeshellarg("(".$settings->ldap_filter.")");
}
if($settings->ldap_tls) {
$this->line("# adding STARTTLS option");
$output[] = "-Z";
}
$output[] = "-v";
$this->line("\n");
$this->line(implode(" \\\n",$output));
exit(0);
}
if(!$this->option('force')) {
$confirmation = $this->confirm('WARNING: This command will make several attempts to connect to your LDAP server. Are you sure this is ok?');
if(!$confirmation) {
$this->error('ABORTING');
exit(-1);
}
}
//$this->line(print_r($settings,true));
$this->info("STAGE 1: Checking settings");
if(!$settings->ldap_enabled) {
$this->error("WARNING: Snipe-IT's LDAP setting is not turned on. (That may be OK if you're still trying to figure out settings)");
}
$ldap_conn = false;
try {
$ldap_conn = ldap_connect($settings->ldap_server);
} catch (Exception $e) {
$this->error("WARNING: Exception caught when executing 'ldap_connect()' - ".$e->getMessage().". We will try to guess.");
}
if(!$ldap_conn) {
$this->error("WARNING: LDAP Server setting of: ".$settings->ldap_server." cannot be parsed. We will try to guess.");
//exit(-1);
}
//since we never use $ldap_conn again, we don't have to ldap_unbind() it (it's not even connected, tbh - that only happens at bind-time)
$parsed = parse_url($settings->ldap_server);
if(@$parsed['scheme'] != 'ldap' && @$parsed['scheme'] != 'ldaps') {
$this->error("WARNING: LDAP URL Scheme of '".@$parsed['scheme']."' is probably incorrect; should usually be ldap or ldaps");
}
if(!@$parsed['host']) {
$this->error("ERROR: Cannot determine hostname or IP from ldap URL: ".$settings->ldap_server.". ABORTING.");
exit(-1);
} else {
$this->info("Determined LDAP hostname to be: ".$parsed['host']);
}
$this->info("Performing DNS lookup of: ".$parsed['host']);
$ips = dns_get_record($parsed['host']);
$raw_ips = [];
//$this->info("Host IP is: ".print_r($ips,true));
if(!$ips || count($ips) == 0) {
$this->error("ERROR: DNS lookup of host: ".$parsed['host']." has failed. ABORTING.");
exit(-1);
}
$this->debugout("IP's? ".print_r($ips,true));
foreach($ips as $ip) {
if(!isset($ip['ip'])) {
continue;
}
$raw_ips[]=$ip['ip'];
if($ip['ip'] == "127.0.0.1") {
$this->error("WARNING: Using the localhost IP as the LDAP server. This is usually wrong");
}
if(ip_in_range($ip['ip'],'10.0.0.0/8') || ip_in_range($ip['ip'],'192.168.0.0/16') || ip_in_range($ip['ip'], '172.16.0.0/12')) {
$this->error("WARNING: Using an RFC1918 Private address for LDAP server. This may be correct, but it can be a problem if your Snipe-IT instance is not hosted on your private network");
}
}
$this->info("STAGE 2: Checking basic network connectivity");
$ports = [389,636];
if(@$parsed['port'] && !in_array($parsed['port'],$ports)) {
$ports[] = $parsed['port'];
}
$open_ports=[];
foreach($ports as $port ) {
$errno = 0;
$errstr = '';
$timeout = 30.0;
$result = '';
$this->info("Attempting to connect to port: ".$port." - may take up to $timeout seconds");
try {
$result = fsockopen($parsed['host'], $port, $errno, $errstr, 30.0);
} catch(Exception $e) {
$this->error("Exception: ".$e->getMessage());
}
if($result) {
$this->info("Success!");
$open_ports[] = $port;
} else {
$this->error("WARNING: Cannot connect to port: $port - $errstr ($errno)");
}
}
if(count($open_ports) == 0) {
$this->error("ERROR - no open ports. ABORTING.");
exit(-1);
}
$this->info("STAGE 3: Determine encryption algorithm, if any");
$ldap_urls = [];
$pretty_ldap_urls = [];
foreach($open_ports as $port) {
$this->line("Trying TLS first for port $port");
$ldap_url = "ldaps://".$parsed['host'].":$port";
if($this->test_anonymous_bind($ldap_url)) {
$this->info("Anonymous bind succesful to $ldap_url!");
$ldap_urls[] = [ $ldap_url, true, false ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
continue; // TODO - lots of copypasta in these if(test_anonymous_bind()) routines...
} else {
$this->error("WARNING: Failed to bind to $ldap_url - trying without certificate checks.");
}
if($this->test_anonymous_bind($ldap_url, false)) {
$this->info("Anonymous bind succesful to $ldap_url with certifcate-checks disabled");
$ldap_urls[] = [ $ldap_url, false, false ];
$pretty_ldap_urls[] = [ $ldap_url, "no", "no" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url with certificate checks disabled. Trying unencrypted with STARTTLS");
}
$ldap_url = "ldap://".$parsed['host'].":$port";
if($this->test_anonymous_bind($ldap_url, true, true)) {
$this->info("Plain connection to $ldap_url with STARTTLS succesful!");
$ldap_urls[] = [ $ldap_url, true, true ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "YES" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled. Trying without STARTTLS");
}
if($this->test_anonymous_bind($ldap_url)) {
$this->info("Plain connection to $ldap_url succesful!");
$ldap_urls[] = [ $ldap_url, true, false ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url. Giving up on port $port");
}
}
$this->debugout(print_r($ldap_urls,true));
if(count($ldap_urls) > 0 ) {
$this->info("Found working LDAP URL's: ");
foreach($ldap_urls as $ldap_url) { // TODO maybe do this as a $this->table() instead?
$this->info("LDAP URL: ".$ldap_url[0]);
$this->info($ldap_url[0]. ($ldap_url[1] ? " certificate checks enabled" : " certificate checks disabled"). ($ldap_url[2] ? " STARTTLS Enabled ": " STARTTLS Disabled"));
}
$this->table(["URL", "Cert Checks Enabled?", "STARTTLS Enabled?"],$pretty_ldap_urls);
} else {
$this->error("ERROR - no valid LDAP URL's available - ABORTING");
exit(1);
}
$this->info("STAGE 4: Test Administrative Bind for LDAP Sync");
foreach($ldap_urls AS $ldap_url) {
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, Crypt::decrypt($settings->ldap_pword));
}
$this->info("STAGE 5: Test BaseDN");
//grab all LDAP_ constants and fill up a reversed array mapping from weird LDAP dotted-strings to (Constant Name)
$all_defined_constants = get_defined_constants();
$ldap_constants = [];
foreach($all_defined_constants AS $key => $val) {
if(starts_with($key,"LDAP_") && is_string($val)) {
$ldap_constants[$val] = $key; // INVERT the meaning here!
}
}
$this->debugout("LDAP constants are: ".print_r($ldap_constants,true));
// recursive function that 'cleans' the returned array from ldap_get_entries which are formatted awfully
$cleaner = function ($array) {
$cleaned = [];
for($i = 0; $i < $array['count']; $i++) {
$row = $array[$i];
$clean_row = [];
foreach($row AS $key => $val ) {
$this->debugout("Key is: ".$key);
if($key == "count" || is_int($key) || $key == "dn") {
$this->debugout(" and we're gonna skip it\n");
continue;
}
$this->debugout(" And that seems fine.\n");
if(array_key_exists('count',$val)) {
if($val['count'] == 1) {
$clean_row[$key] = $val[0];
} else {
unset($val['count']); //these counts are annoying
$elements = [];
foreach($val as $entry) {
if(isset($ldap_constants[$entry])) {
$elements[] = $ldap_constants[$entry];
} else {
$elements[] = $entry;
}
}
$clean_row[$key] = $elements;
}
} else {
$clean_row[$key] = $val;
}
}
$cleaned[$i] = $clean_row;
}
return $cleaned;
};
foreach($ldap_urls AS $ldap_url) {
if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword))) {
$this->info("Success getting informational bind!");
} else {
$this->error("Unable to get information from bind.");
}
}
$this->info("STAGE 6: Test LDAP Login to Snipe-IT");
foreach($ldap_urls AS $ldap_url) {
$this->info("Starting auth to ".$ldap_url[0]);
while(true) {
$with_tls = $ldap_url[1] ? "with": "without";
$with_startssl = $ldap_url[2] ? "using": "not using";
if(!$this->confirm('Do you wish to try to authenticate to this directory: '.$ldap_url[0]." $with_tls TLS and $with_startssl STARTSSL?")) {
break;
}
$username = $this->ask("Username");
$password = $this->secret("Password");
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results?
}
}
$this->info("LDAP TROUBLESHOOTING COMPLETE!");
}
public function connect_to_ldap($ldap_url, $check_cert, $start_tls)
{
$lconn = ldap_connect($ldap_url);
ldap_set_option($lconn, LDAP_OPT_PROTOCOL_VERSION, 3); // should we 'test' different protocol versions here? Does anyone even use anything other than LDAPv3?
// no - it's formally deprecated: https://tools.ietf.org/html/rfc3494
if(!$check_cert) {
putenv('LDAPTLS_REQCERT=never'); // This is horrible; is this *really* the only way to do it?
} else {
putenv('LDAPTLS_REQCERT'); // have to very explicitly and manually *UN* set the env var here to ensure it works
}
if($this->settings->ldap_client_tls_cert && $this->settings->ldap_client_tls_key) {
// client-side TLS certificate support for LDAP (Google Secure LDAP)
putenv('LDAPTLS_CERT=storage/ldap_client_tls.cert');
putenv('LDAPTLS_KEY=storage/ldap_client_tls.key');
}
if($start_tls) {
if(!ldap_start_tls($lconn)) {
$this->error("WARNING: Unable to start TLS");
return false;
}
}
if(!$lconn) {
$this->error("WARNING: Failed to generate connection string - using: ".$ldap_url);
return false;
}
$net = ldap_set_option($lconn, LDAP_OPT_NETWORK_TIMEOUT, $this->option('timeout'));
$time = ldap_set_option($lconn, LDAP_OPT_TIMELIMIT, $this->option('timeout'));
if(!$net || !$time) {
$this->error("Unable to set timeouts!");
}
return $lconn;
}
public function test_anonymous_bind($ldap_url, $check_cert = true, $start_tls = false)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert , $start_tls) {
try {
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$this->info("gonna try to bind now, this can take a while if we mess it up");
$bind_results = ldap_bind($lconn);
$this->info("Bind results are: ".$bind_results." which translate into boolean: ".(bool)$bind_results);
return (bool)$bind_results;
} catch (Exception $e) {
$this->error("WARNING: Exception caught during bind - ".$e->getMessage());
return false;
}
});
}
public function test_authed_bind($ldap_url, $check_cert, $start_tls, $username, $password)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
try {
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$bind_results = ldap_bind($lconn, $username, $password);
if(!$bind_results) {
$this->error("WARNING: Failed to bind to $ldap_url as $username");
return false;
} else {
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
return (bool)$lconn;
}
} catch (Exception $e) {
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
return false;
}
});
}
public function test_informational_bind($ldap_url, $check_cert, $start_tls, $username, $password)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
try { // TODO - copypasta'ed from test_authed_bind
$conn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$bind_results = ldap_bind($conn, $username, $password);
if(!$bind_results) {
$this->error("WARNING: Failed to bind to $ldap_url as $username");
return false;
}
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
$result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/);
$results = ldap_get_entries($conn, $result);
$cleaned_results = $cleaner($results);
$this->line(print_r($cleaned_results,true));
//okay, great - now how do we display those results? I have no idea.
// I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it?
$this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?");
$search_results = ldap_search($conn, $settings->base_dn, $settings->filter);
$this->info("Printing first 10 results: ");
for($i=0;$i<10;$i++) {
$this->info($search_results[$i]);
}
} catch (\Exception $e) {
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
return false;
}
});
}
/***********************************************
*
* This function executes $function - which is expected to be some kind of executable function -
* with a timeout set. It respects the timeout by forking execution and setting a strict timer
* for which to get back a SIGUSR1 or SIGUSR2 signal from the forked process.
*
***********************************************/
private function timed_boolean_execute($function)
{
if(!(function_exists('pcntl_sigtimedwait') && function_exists('posix_getpid') && function_exists('pcntl_fork') && function_exists('posix_kill') && function_exists('pcntl_wifsignaled'))) {
// POSIX functions needed for forking aren't present, just run the function inline (ignoring timeout)
$this->info('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected');
return $function();
} else {
$parent_pid = posix_getpid();
$pid = pcntl_fork();
switch($pid) {
case 0:
//we're the 'child'
if($function()) {
//SUCCESS = SIGUSR1
posix_kill($parent_pid, SIGUSR1);
} else {
//FAILURE = SIGUSR2
posix_kill($parent_pid, SIGUSR2);
}
exit();
break; //yes I know we don't need it.
case -1:
//couldn't fork
$this->error("COULD NOT FORK - assuming failure");
return false;
break; //I still know that we don't need it
default:
//we remain the 'parent', $pid is the PID of the forked process.
$siginfo = [];
$exit_status = pcntl_sigtimedwait ([SIGUSR1, SIGUSR2], $siginfo, $this->option('timeout'));
if ($exit_status == SIGUSR1) {
return true;
} else {
posix_kill($pid, SIGKILL); //make sure we don't have processes hanging around that might try and send signals during later executions, confusing us
return false;
}
break; //Yeah I get it already, shush.
}
}
}
}

View File

@@ -2,10 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
class MergeUsersByUsername extends Command
{
@@ -44,7 +43,7 @@ class MergeUsersByUsername extends Command
$users = User::where('username', 'LIKE', '%@%')->whereNull('deleted_at')->get();
foreach ($users as $user) {
$parts = explode("@", $user->username);
$parts = explode('@', $user->username);
$bad_users = User::where('username', '=', $parts[0])->whereNull('deleted_at')->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')->get();
foreach ($bad_users as $bad_user) {
@@ -52,61 +51,55 @@ class MergeUsersByUsername extends Command
// Walk the list of assets
foreach ($bad_user->assets as $asset) {
$this->info( 'Updating asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
$this->info('Updating asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
$asset->assigned_to = $user->id;
if (!$asset->save()) {
$this->error( 'Could not update assigned_to field on asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
$this->error( 'Error saving: '.$asset->getErrors());
if (! $asset->save()) {
$this->error('Could not update assigned_to field on asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
$this->error('Error saving: '.$asset->getErrors());
}
}
// Walk the list of licenses
foreach ($bad_user->licenses as $license) {
$this->info( 'Updating license '.$license->name.' '.$license->id.' to user '.$user->id);
$this->info('Updating license '.$license->name.' '.$license->id.' to user '.$user->id);
$bad_user->licenses()->updateExistingPivot($license->id, ['assigned_to' => $user->id]);
}
// Walk the list of consumables
foreach ($bad_user->consumables as $consumable) {
$this->info( 'Updating consumable '.$consumable->id.' to user '.$user->id);
$this->info('Updating consumable '.$consumable->id.' to user '.$user->id);
$bad_user->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $user->id]);
}
// Walk the list of accessories
foreach ($bad_user->accessories as $accessory) {
$this->info( 'Updating accessory '.$accessory->id.' to user '.$user->id);
$this->info('Updating accessory '.$accessory->id.' to user '.$user->id);
$bad_user->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $user->id]);
}
// Walk the list of logs
foreach ($bad_user->userlog as $log) {
$this->info( 'Updating action log record '.$log->id.' to user '.$user->id);
$this->info('Updating action log record '.$log->id.' to user '.$user->id);
$log->target_id = $user->id;
$log->save();
}
// Update any manager IDs
$this->info( 'Updating managed user records to user '.$user->id);
$this->info('Updating managed user records to user '.$user->id);
User::where('manager_id', '=', $bad_user->id)->update(['manager_id' => $user->id]);
// Update location manager IDs
foreach ($bad_user->managedLocations as $managedLocation) {
$this->info( 'Updating managed location record '.$managedLocation->name.' to manager '.$user->id);
$this->info('Updating managed location record '.$managedLocation->name.' to manager '.$user->id);
$managedLocation->manager_id = $user->id;
$managedLocation->save();
}
// Mark the user as deleted
$this->info( 'Marking the user as deleted');
$this->info('Marking the user as deleted');
$bad_user->deleted_at = Carbon::now()->timestamp;
$bad_user->save();
}
}
}
}

View File

@@ -2,7 +2,6 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
@@ -39,39 +38,37 @@ class MoveUploadsToNewDisk extends Command
*/
public function handle()
{
if (config('filesystems.default')=='local') {
if (config('filesystems.default') == 'local') {
$this->error('Your current disk is set to local so we cannot proceed.');
$this->warn("Please configure your .env settings for S3. \nChange your PUBLIC_FILESYSTEM_DISK value to 's3_public' and your PRIVATE_FILESYSTEM_DISK to s3_private.");
return false;
}
$delete_local = $this->argument('delete_local');
$public_uploads['accessories'] = glob('public/accessories'."/*.*");
$public_uploads['assets'] = glob('public/assets'."/*.*");
$public_uploads['avatars'] = glob('public/avatars'."/*.*");
$public_uploads['categories'] = glob('public/categories'."/*.*");
$public_uploads['companies'] = glob('public/companies'."/*.*");
$public_uploads['components'] = glob('public/components'."/*.*");
$public_uploads['consumables'] = glob('public/consumables'."/*.*");
$public_uploads['departments'] = glob('public/departments'."/*.*");
$public_uploads['locations'] = glob('public/locations'."/*.*");
$public_uploads['manufacturers'] = glob('public/manufacturers'."/*.*");
$public_uploads['suppliers'] = glob('public/suppliers'."/*.*");
$public_uploads['assetmodels'] = glob('public/models'."/*.*");
$public_uploads['accessories'] = glob('public/accessories'.'/*.*');
$public_uploads['assets'] = glob('public/assets'.'/*.*');
$public_uploads['avatars'] = glob('public/avatars'.'/*.*');
$public_uploads['categories'] = glob('public/categories'.'/*.*');
$public_uploads['companies'] = glob('public/companies'.'/*.*');
$public_uploads['components'] = glob('public/components'.'/*.*');
$public_uploads['consumables'] = glob('public/consumables'.'/*.*');
$public_uploads['departments'] = glob('public/departments'.'/*.*');
$public_uploads['locations'] = glob('public/locations'.'/*.*');
$public_uploads['manufacturers'] = glob('public/manufacturers'.'/*.*');
$public_uploads['suppliers'] = glob('public/suppliers'.'/*.*');
$public_uploads['assetmodels'] = glob('public/models'.'/*.*');
// iterate files
foreach($public_uploads as $public_type => $public_upload)
{
foreach ($public_uploads as $public_type => $public_upload) {
$type_count = 0;
$this->info("- There are ".count($public_upload).' PUBLIC '.$public_type.' files.');
$this->info('- There are '.count($public_upload).' PUBLIC '.$public_type.' files.');
for ($i = 0; $i < count($public_upload); $i++) {
$type_count++;
$filename = basename($public_upload[$i]);
try {
try {
Storage::disk('public')->put('uploads/'.public_type.'/'.$filename, file_get_contents($public_upload[$i]));
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
@@ -79,13 +76,11 @@ class MoveUploadsToNewDisk extends Command
\Log::debug($e);
$this->error($e);
}
}
}
$logos = glob("public/uploads/setting*.*");
$this->info("- There are ".count($logos).' files that might be logos.');
$logos = glob('public/uploads/setting*.*');
$this->info('- There are '.count($logos).' files that might be logos.');
$type_count = 0;
foreach ($logos as $logo) {
@@ -96,41 +91,35 @@ class MoveUploadsToNewDisk extends Command
$this->info($type_count.'. LOGO: '.$filename.' was copied to '.env('PUBLIC_AWS_URL').'/uploads/'.$filename);
}
$private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*");
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*");
$private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*");
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*");
$private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*");
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*");
$private_uploads['users'] = glob('storage/private_uploads/users'."/*.*");
$private_uploads['backups'] = glob('storage/private_uploads/users'."/*.*");
$private_uploads['assets'] = glob('storage/private_uploads/assets'.'/*.*');
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'.'/*.*');
$private_uploads['audits'] = glob('storage/private_uploads/audits'.'/*.*');
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'.'/*.*');
$private_uploads['imports'] = glob('storage/private_uploads/imports'.'/*.*');
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'.'/*.*');
$private_uploads['users'] = glob('storage/private_uploads/users'.'/*.*');
$private_uploads['backups'] = glob('storage/private_uploads/users'.'/*.*');
foreach($private_uploads as $private_type => $private_upload)
{
$this->info("- There are ".count($private_upload).' PRIVATE '.$private_type.' files.');
foreach ($private_uploads as $private_type => $private_upload) {
$this->info('- There are '.count($private_upload).' PRIVATE '.$private_type.' files.');
$type_count = 0;
for ($x = 0; $x < count($private_upload); $x++) {
$type_count++;
$filename = basename($private_upload[$x]);
try {
try {
Storage::put($private_type.'/'.$filename, file_get_contents($private_upload[$i]));
$new_url = Storage::url($private_type.'/'.$filename, $filename);
$this->info($type_count.'. PRIVATE: '.$filename.' was copied to '.$new_url);
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
}
}
if ($delete_local=='true') {
if ($delete_local == 'true') {
$public_delete_count = 0;
$private_delete_count = 0;
@@ -139,10 +128,8 @@ class MoveUploadsToNewDisk extends Command
$this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n");
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
if ($this->confirm("Do you wish to continue?")) {
foreach($public_uploads as $public_type => $public_upload) {
if ($this->confirm('Do you wish to continue?')) {
foreach ($public_uploads as $public_type => $public_upload) {
for ($i = 0; $i < count($public_upload); $i++) {
$filename = $public_upload[$i];
try {
@@ -152,13 +139,10 @@ class MoveUploadsToNewDisk extends Command
\Log::debug($e);
$this->error($e);
}
}
}
foreach($private_uploads as $private_type => $private_upload)
{
foreach ($private_uploads as $private_type => $private_upload) {
for ($i = 0; $i < count($private_upload); $i++) {
$filename = $private_upload[$i];
try {
@@ -168,16 +152,11 @@ class MoveUploadsToNewDisk extends Command
\Log::debug($e);
$this->error($e);
}
}
}
$this->info($public_delete_count." PUBLIC local files and ".$private_delete_count." PRIVATE local files were deleted from your filesystem.");
$this->info($public_delete_count.' PUBLIC local files and '.$private_delete_count.' PRIVATE local files were deleted from your filesystem.');
}
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
@@ -13,7 +14,6 @@ ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
*/
class ObjectImportCommand extends Command
{
/**
* The console command name.
*
@@ -37,7 +37,9 @@ class ObjectImportCommand extends Command
{
parent::__construct();
}
private $bar;
/**
* Execute the console command.
*
@@ -55,7 +57,6 @@ class ObjectImportCommand extends Command
->setShouldNotify($this->option('send-welcome'))
->setUsernameFormat($this->option('username_format'));
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
// $logFile = $this->option('logfile');
// \Log::useFiles($logFile);
@@ -64,29 +65,28 @@ class ObjectImportCommand extends Command
$this->bar = null;
if (!empty($this->errors)) {
$this->comment("The following Errors were encountered.");
if (! empty($this->errors)) {
$this->comment('The following Errors were encountered.');
foreach ($this->errors as $asset => $error) {
$this->comment('Error: Item: ' . $asset . ' failed validation: ' . json_encode($error));
$this->comment('Error: Item: '.$asset.' failed validation: '.json_encode($error));
}
} else {
$this->comment("All Items imported successfully!");
$this->comment('All Items imported successfully!');
}
$this->comment("");
return;
$this->comment('');
}
public function errorCallback($item, $field, $errorString)
{
$this->errors[$item->name][$field] = $errorString;
}
public function progress($count)
{
if (!$this->bar) {
if (! $this->bar) {
$this->bar = $this->output->createProgressBar($count);
}
static $index =0;
static $index = 0;
$index++;
if ($index < $count) {
$this->bar->advance();
@@ -94,12 +94,12 @@ class ObjectImportCommand extends Command
$this->bar->finish();
}
}
// Tracks the current item for error messages
private $updating;
// An array of errors encountered while parsing
private $errors;
/**
* Log a message to file, configurable by the --log-file parameter.
* If a warning message is passed, we'll spit it to the console as well.
@@ -108,7 +108,7 @@ class ObjectImportCommand extends Command
* @since 3.0
* @param string $string
* @param string $level
*/
*/
public function log($string, $level = 'info')
{
if ($level === 'warning') {
@@ -121,6 +121,7 @@ class ObjectImportCommand extends Command
}
}
}
/**
* Get the console command arguments.
*
@@ -130,12 +131,11 @@ class ObjectImportCommand extends Command
*/
protected function getArguments()
{
return array(
array('filename', InputArgument::REQUIRED, 'File for the CSV import.'),
);
return [
['filename', InputArgument::REQUIRED, 'File for the CSV import.'],
];
}
/**
* Get the console command options.
*
@@ -145,16 +145,15 @@ class ObjectImportCommand extends Command
*/
protected function getOptions()
{
return array(
array('email_format', null, InputOption::VALUE_REQUIRED, 'The format of the email addresses that should be generated. Options are firstname.lastname, firstname, filastname', null),
array('username_format', null, InputOption::VALUE_REQUIRED, 'The format of the username that should be generated. Options are firstname.lastname, firstname, filastname, email', null),
array('logfile', null, InputOption::VALUE_REQUIRED, 'The path to log output to. storage/logs/importer.log by default', storage_path('logs/importer.log') ),
array('item-type', null, InputOption::VALUE_REQUIRED, 'Item Type To import. Valid Options are Asset, Consumable, Accessory, License, or User', 'Asset'),
array('web-importer', null, InputOption::VALUE_NONE, 'Internal: packages output for use with the web importer'),
array('user_id', null, InputOption::VALUE_REQUIRED, 'ID of user creating items', 1),
array('update', null, InputOption::VALUE_NONE, 'If a matching item is found, update item information'),
array('send-welcome', null, InputOption::VALUE_NONE, 'Whether to send a welcome email to any new users that are created.'),
);
return [
['email_format', null, InputOption::VALUE_REQUIRED, 'The format of the email addresses that should be generated. Options are firstname.lastname, firstname, filastname', null],
['username_format', null, InputOption::VALUE_REQUIRED, 'The format of the username that should be generated. Options are firstname.lastname, firstname, filastname, email', null],
['logfile', null, InputOption::VALUE_REQUIRED, 'The path to log output to. storage/logs/importer.log by default', storage_path('logs/importer.log')],
['item-type', null, InputOption::VALUE_REQUIRED, 'Item Type To import. Valid Options are Asset, Consumable, Accessory, License, or User', 'Asset'],
['web-importer', null, InputOption::VALUE_NONE, 'Internal: packages output for use with the web importer'],
['user_id', null, InputOption::VALUE_REQUIRED, 'ID of user creating items', 1],
['update', null, InputOption::VALUE_NONE, 'If a matching item is found, update item information'],
['send-welcome', null, InputOption::VALUE_NONE, 'Whether to send a welcome email to any new users that are created.'],
];
}
}

View File

@@ -50,7 +50,7 @@ class Purge extends Command
public function handle()
{
$force = $this->option('force');
if (($this->confirm("\n****************************************************\nTHIS WILL PURGE ALL SOFT-DELETED ITEMS IN YOUR SYSTEM. \nThere is NO undo. This WILL permanently destroy \nALL of your deleted data. \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) || $force == 'true') {
if (($this->confirm("\n****************************************************\nTHIS WILL PURGE ALL SOFT-DELETED ITEMS IN YOUR SYSTEM. \nThere is NO undo. This WILL permanently destroy \nALL of your deleted data. \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) || $force == 'true') {
/**
* Delete assets
@@ -80,9 +80,8 @@ class Purge extends Command
$location->forceDelete();
}
$accessories = Accessory::whereNotNull('deleted_at')->withTrashed()->get();
$accessory_assoc=0;
$accessory_assoc = 0;
$this->info($accessories->count().' accessories purged.');
foreach ($accessories as $accessory) {
$this->info('- Accessory "'.$accessory->name.'" deleted.');
@@ -92,7 +91,6 @@ class Purge extends Command
}
$this->info($accessory_assoc.' corresponding log records purged.');
$consumables = Consumable::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($consumables->count().' consumables purged.');
foreach ($consumables as $consumable) {
@@ -101,7 +99,6 @@ class Purge extends Command
$consumable->forceDelete();
}
$components = Component::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($components->count().' components purged.');
foreach ($components as $component) {
@@ -126,7 +123,6 @@ class Purge extends Command
$model->forceDelete();
}
$categories = Category::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($categories->count().' categories purged.');
foreach ($categories as $category) {
@@ -165,11 +161,8 @@ class Purge extends Command
$this->info('- Status Label "'.$status_label->name.'" deleted.');
$status_label->forceDelete();
}
} else {
$this->info('Action canceled. Nothing was purged.');
}
}
}

View File

@@ -38,7 +38,7 @@ class PurgeLoginAttempts extends Command
public function handle()
{
if ($this->confirm("\n****************************************************\nTHIS WILL DELETE ALL OF THE YOUR LOGIN ATTEMPT RECORDS. \nThere is NO undo! \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) {
\DB::statement('delete from login_attempts');
\DB::statement('delete from login_attempts');
}
}
}

View File

@@ -48,15 +48,13 @@ class ReEncodeCustomFieldNames extends Command
*/
public function handle()
{
if ($this->confirm('This will regenerate all of the custom field database fieldnames in your database. THIS WILL CHANGE YOUR SCHEMA AND SHOULD NOT BE DONE WITHOUT MAKING A BACKUP FIRST. Do you wish to continue?'))
{
if ($this->confirm('This will regenerate all of the custom field database fieldnames in your database. THIS WILL CHANGE YOUR SCHEMA AND SHOULD NOT BE DONE WITHOUT MAKING A BACKUP FIRST. Do you wish to continue?')) {
/** Get all of the custom fields */
$fields = CustomField::get();
$asset_columns = \DB::getSchemaBuilder()->getColumnListing('assets');
$custom_field_columns = array();
$custom_field_columns = [];
/** Loop through the columns on the assets table */
foreach ($asset_columns as $asset_column) {
@@ -71,18 +69,16 @@ class ReEncodeCustomFieldNames extends Command
* Then use that ID as the array key for use comparing the actual assets field name
* and the db_column value from the custom fields table.
*/
$last_part = substr(strrchr($asset_column, "_snipeit_"), 1);
$last_part = substr(strrchr($asset_column, '_snipeit_'), 1);
$custom_field_columns[$last_part] = $asset_column;
}
}
foreach ($fields as $field) {
$this->info($field->name .' ('.$field->id.') column should be '. $field->convertUnicodeDbSlug().'');
$this->info($field->name.' ('.$field->id.') column should be '.$field->convertUnicodeDbSlug().'');
/** The assets table has the column it should have, all is well */
if (\Schema::hasColumn('assets', $field->convertUnicodeDbSlug()))
{
if (\Schema::hasColumn('assets', $field->convertUnicodeDbSlug())) {
$this->info('-- ✓ This field exists - all good');
/**
@@ -90,24 +86,23 @@ class ReEncodeCustomFieldNames extends Command
* what $field->convertUnicodeDbSlug() is *now* expecting.
*/
} else {
$this->warn('-- X Field mismatch: updating... ');
$this->warn('-- X Field mismatch: updating... ');
/** Make sure the custom_field_columns array has the ID */
if (array_key_exists($field->id, $custom_field_columns)) {
/** Make sure the custom_field_columns array has the ID */
if (array_key_exists($field->id, $custom_field_columns)) {
/**
* Update the asset schema to the corrected fieldname that will be recognized by the
* system elsewhere that we use $field->convertUnicodeDbSlug()
*/
\Schema::table('assets', function($table) use ($custom_field_columns, $field) {
$table->renameColumn($custom_field_columns[$field->id], $field->convertUnicodeDbSlug());
});
/**
* Update the asset schema to the corrected fieldname that will be recognized by the
* system elsewhere that we use $field->convertUnicodeDbSlug()
*/
\Schema::table('assets', function ($table) use ($custom_field_columns, $field) {
$table->renameColumn($custom_field_columns[$field->id], $field->convertUnicodeDbSlug());
});
$this->warn('-- ✓ Field updated from '.$custom_field_columns[$field->id].' to '.$field->convertUnicodeDbSlug());
} else {
$this->warn('-- X WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
}
$this->warn('-- ✓ Field updated from '.$custom_field_columns[$field->id].' to '.$field->convertUnicodeDbSlug());
} else {
$this->warn('-- X WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
}
}
/** Update the db_column property in the custom fields table, just in case it doesn't match the other
@@ -115,12 +110,7 @@ class ReEncodeCustomFieldNames extends Command
*/
$field->db_column = $field->convertUnicodeDbSlug();
$field->save();
}
}
}
}

View File

@@ -44,37 +44,35 @@ class RecryptFromMcrypt extends Command
public function handle()
{
// Check and see if they have a legacy app key listed in their .env
// If not, we can try to use the current APP_KEY if looks like it's old
$legacy_key = env('LEGACY_APP_KEY');
$key_parts = explode(':', $legacy_key);
$legacy_cipher = env('LEGACY_CIPHER', 'rijndael-256');
$errors = array();
$errors = [];
if (!$legacy_key) {
if (! $legacy_key) {
$this->error('ERROR: You do not have a LEGACY_APP_KEY set in your .env file. Please locate your old APP_KEY and ADD a line to your .env file like: LEGACY_APP_KEY=YOUR_OLD_APP_KEY');
return false;
}
// Do some basic legacy app key length checks
if (strlen($legacy_key) == 32) {
$legacy_length_check = true;
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1])==44)) {
$legacy_key = base64_decode($key_parts[1],true);
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1]) == 44)) {
$legacy_key = base64_decode($key_parts[1], true);
$legacy_length_check = true;
} else {
$legacy_length_check = false;
}
// Check that the app key is 32 characters
if ($legacy_length_check === true) {
$this->comment('INFO: Your LEGACY_APP_KEY looks correct. Okay to continue.');
} else {
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters or base64 followed by 44 characters for later versions). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
return false;
}
@@ -84,8 +82,7 @@ class RecryptFromMcrypt extends Command
$force = ($this->option('force')) ? true : false;
if ($force || ($this->confirm("Are you SURE you wish to continue?"))) {
if ($force || ($this->confirm('Are you SURE you wish to continue?'))) {
$backup_file = 'backups/env-backups/'.'app_key-'.date('Y-m-d-gis');
try {
@@ -95,15 +92,14 @@ class RecryptFromMcrypt extends Command
$this->info('WARNING: Could not backup app keys');
}
if ($legacy_cipher){
$mcrypter = new McryptEncrypter($legacy_key,$legacy_cipher);
}else{
if ($legacy_cipher) {
$mcrypter = new McryptEncrypter($legacy_key, $legacy_cipher);
} else {
$mcrypter = new McryptEncrypter($legacy_key);
}
$settings = Setting::getSettings();
if ($settings->ldap_pword=='') {
if ($settings->ldap_pword == '') {
$this->comment('INFO: No LDAP password found. Skipping... ');
} else {
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
@@ -111,30 +107,28 @@ class RecryptFromMcrypt extends Command
$settings->save();
}
/** @var CustomField[] $custom_fields */
$custom_fields = CustomField::where('field_encrypted','=', 1)->get();
$custom_fields = CustomField::where('field_encrypted', '=', 1)->get();
$this->comment('INFO: Retrieving encrypted custom fields...');
$query = Asset::withTrashed();
foreach ($custom_fields as $custom_field) {
$this->comment('FIELD TO RECRYPT: '.$custom_field->name .' ('.$custom_field->db_column.')');
$this->comment('FIELD TO RECRYPT: '.$custom_field->name.' ('.$custom_field->db_column.')');
$query->orWhereNotNull($custom_field->db_column);
}
// Get all assets with a value in any of the fields that were encrypted
/** @var Asset[] $assets */
$assets = $query->get();
$bar = $this->output->createProgressBar(count($assets));
foreach ($assets as $asset) {
foreach ($custom_fields as $encrypted_field) {
$columnName = $encrypted_field->db_column;
// Make sure the value isn't null
if ($asset->{$columnName}!='') {
if ($asset->{$columnName} != '') {
// Try to decrypt the payload using the legacy app key
try {
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
@@ -144,14 +138,11 @@ class RecryptFromMcrypt extends Command
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
}
}
}
$asset->save();
$bar->advance();
}
$bar->finish();
if (count($errors) > 0) {
@@ -162,6 +153,5 @@ class RecryptFromMcrypt extends Command
}
}
}
}
}

View File

@@ -40,30 +40,26 @@ class RegenerateAssetTags extends Command
*/
public function handle()
{
if ($this->confirm('This will regenerate all of the asset tags within your system. This action is data-destructive and should be used with caution. Do you wish to continue?'))
{
if ($this->confirm('This will regenerate all of the asset tags within your system. This action is data-destructive and should be used with caution. Do you wish to continue?')) {
$output['info'] = [];
$output['warn'] = [];
$output['error'] = [];
$settings = Setting::getSettings();
$start_tag = ($this->option('start')) ? $this->option('start') : (($settings->next_auto_tag_base) ? Setting::getSettings()->next_auto_tag_base : 1) ;
$start_tag = ($this->option('start')) ? $this->option('start') : (($settings->next_auto_tag_base) ? Setting::getSettings()->next_auto_tag_base : 1);
$this->info('Starting at '.$start_tag);
$total_assets = Asset::orderBy('id','asc')->get();
$total_assets = Asset::orderBy('id', 'asc')->get();
$bar = $this->output->createProgressBar(count($total_assets));
try {
try {
Artisan::call('backup:run');
} catch (\Exception $e) {
$output['error'][] = $e;
}
foreach ($total_assets as $asset) {
$start_tag++;
$output['info'][] = 'Asset tag:'.$asset->asset_tag;
$asset->asset_tag = $settings->auto_increment_prefix.$settings->auto_increment_prefix.$start_tag;
@@ -81,24 +77,21 @@ class RegenerateAssetTags extends Command
$bar->finish();
$this->info("\n");
if (($this->option('output')=='all') || ($this->option('output')=='info')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'info')) {
foreach ($output['info'] as $key => $output_text) {
$this->info($output_text);
}
}
if (($this->option('output')=='all') || ($this->option('output')=='warn')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'warn')) {
foreach ($output['warn'] as $key => $output_text) {
$this->warn($output_text);
}
}
if (($this->option('output')=='all') || ($this->option('output')=='error')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'error')) {
foreach ($output['error'] as $key => $output_text) {
$this->error($output_text);
}
}
}
}
}

View File

@@ -43,16 +43,15 @@ class RestoreDeletedUsers extends Command
*/
public function handle()
{
$start_date = $this->option('start_date');
$end_date = $this->option('end_date');
$asset_totals = 0;
$license_totals = 0;
$user_count = 0;
if (($start_date=='') || ($end_date=='')) {
if (($start_date == '') || ($end_date == '')) {
$this->info('ERROR: All fields are required.');
return false;
}
@@ -63,15 +62,15 @@ class RestoreDeletedUsers extends Command
foreach ($users as $user) {
$user_count++;
$user_logs = Actionlog::where('target_id', $user->id)->where('target_type',User::class)
->where('action_type','checkout')->with('item')->get();
$user_logs = Actionlog::where('target_id', $user->id)->where('target_type', User::class)
->where('action_type', 'checkout')->with('item')->get();
$this->info($user_count.'. '.$user->username.' ('.$user->id.') was deleted at '.$user->deleted_at. ' and has '.$user_logs->count().' checkouts associated.');
$this->info($user_count.'. '.$user->username.' ('.$user->id.') was deleted at '.$user->deleted_at.' and has '.$user_logs->count().' checkouts associated.');
foreach ($user_logs as $user_log) {
$this->info(' * '.$user_log->item_type.': '.$user_log->item->name.' - item_id: '.$user_log->item_id);
if ($user_log->item_type==Asset::class) {
if ($user_log->item_type == Asset::class) {
$asset_totals++;
DB::table('assets')
@@ -79,11 +78,10 @@ class RestoreDeletedUsers extends Command
->update(['assigned_to' => $user->id, 'assigned_type'=> User::class]);
$this->info(' ** Asset '.$user_log->item->id.' ('.$user_log->item->asset_tag.') restored to user '.$user->id.'');
} elseif ($user_log->item_type==License::class) {
} elseif ($user_log->item_type == License::class) {
$license_totals++;
$avail_seat = DB::table('license_seats')->where('license_id','=',$user_log->item->id)
$avail_seat = DB::table('license_seats')->where('license_id', '=', $user_log->item->id)
->whereNull('assigned_to')->whereNull('asset_id')->whereBetween('updated_at', [$start_date, $end_date])->first();
if ($avail_seat) {
$this->info(' ** Allocating seat '.$avail_seat->id.' for this License');
@@ -91,27 +89,17 @@ class RestoreDeletedUsers extends Command
DB::table('license_seats')
->where('id', $avail_seat->id)
->update(['assigned_to' => $user->id]);
} else {
$this->warn('ERROR: No available seats for '.$user_log->item->name);
}
}
}
$this->warn('Restoring user '.$user->username.'!');
$user->restore();
}
$this->info($asset_totals.' assets affected');
$this->info($license_totals.' licenses affected');
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use ZipArchive;
class RestoreFromBackup extends Command
@@ -15,7 +14,7 @@ class RestoreFromBackup extends Command
*/
protected $signature = 'snipeit:restore
{--force : Skip the danger prompt; assuming you hit "y"}
{filename : The zip file to be migrated}
{filename : The full path of the .zip file to be migrated}
{--no-progress : Don\'t show a progress bar}';
/**
@@ -23,7 +22,7 @@ class RestoreFromBackup extends Command
*
* @var string
*/
protected $description = 'Restore from a previously created backup';
protected $description = 'Restore from a previously created Snipe-IT backup file';
/**
* Create a new command instance.
@@ -35,6 +34,8 @@ class RestoreFromBackup extends Command
parent::__construct();
}
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
/**
* Execute the console command.
*
@@ -43,20 +44,23 @@ class RestoreFromBackup extends Command
public function handle()
{
$dir = getcwd();
print "Current working directory is: $dir\n";
if( $dir != base_path() ) { // usually only the case when running via webserver, not via command-line
\Log::debug("Current working directory is: $dir, changing directory to: ".base_path());
chdir(base_path()); // TODO - is this *safe* to change on a running script?!
}
//
$filename = $this->argument('filename');
if (!$filename) {
return $this->error("Missing required filename");
if (! $filename) {
return $this->error('Missing required filename');
}
if (!$this->option('force') && !$this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
return $this->error("Data loss not confirmed");
if (! $this->option('force') && ! $this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
return $this->error('Data loss not confirmed');
}
if (config('database.default') != 'mysql') {
return $this->error("DB_CONNECTION must be MySQL in order to perform a restore. Detected: ".config('database.default'));
return $this->error('DB_CONNECTION must be MySQL in order to perform a restore. Detected: '.config('database.default'));
}
$za = new ZipArchive();
@@ -64,18 +68,18 @@ class RestoreFromBackup extends Command
$errcode = $za->open($filename/* , ZipArchive::RDONLY */); // that constant only exists in PHP 7.4 and higher
if ($errcode !== true) {
$errors = [
ZipArchive::ER_EXISTS => "File already exists.",
ZipArchive::ER_INCONS => "Zip archive inconsistent.",
ZipArchive::ER_INVAL => "Invalid argument.",
ZipArchive::ER_MEMORY => "Malloc failure.",
ZipArchive::ER_NOENT => "No such file.",
ZipArchive::ER_NOZIP => "Not a zip archive.",
ZipArchive::ER_EXISTS => 'File already exists.',
ZipArchive::ER_INCONS => 'Zip archive inconsistent.',
ZipArchive::ER_INVAL => 'Invalid argument.',
ZipArchive::ER_MEMORY => 'Malloc failure.',
ZipArchive::ER_NOENT => 'No such file ('.$filename.') in directory '.$dir.'.',
ZipArchive::ER_NOZIP => 'Not a zip archive.',
ZipArchive::ER_OPEN => "Can't open file.",
ZipArchive::ER_READ => "Read error.",
ZipArchive::ER_SEEK => "Seek error."
ZipArchive::ER_READ => 'Read error.',
ZipArchive::ER_SEEK => 'Seek error.',
];
return $this->error("Could not access file: ".$filename." - ".array_key_exists($errcode,$errors) ? $errors[$errcode] : " Unknown reason: $errcode");
return $this->error('Could not access file: '.$filename.' - '.array_key_exists($errcode, $errors) ? $errors[$errcode] : " Unknown reason: $errcode");
}
@@ -86,11 +90,11 @@ class RestoreFromBackup extends Command
'storage/private_uploads/assetmodels',
'storage/private_uploads/users',
'storage/private_uploads/licenses',
'storage/private_uploads/signatures'
'storage/private_uploads/signatures',
];
$private_files = [
'storage/oauth-private.key',
'storage/oauth-public.key'
'storage/oauth-public.key',
];
$public_dirs = [
'public/uploads/companies',
@@ -108,16 +112,16 @@ class RestoreFromBackup extends Command
'public/uploads/models',
'public/uploads/categories',
'public/uploads/avatars',
'public/uploads/manufacturers'
'public/uploads/manufacturers',
];
$public_files = [
'public/uploads/logo.*',
'public/uploads/setting-email_logo*',
'public/uploads/setting-label_logo*',
'public/uploads/setting-logo*',
'public/uploads/favicon.*',
'public/uploads/favicon-uploaded.*'
'public/uploads/favicon-uploaded.*',
];
$all_files = $private_dirs + $public_dirs;
@@ -127,64 +131,64 @@ class RestoreFromBackup extends Command
$interesting_files = [];
$boring_files = [];
for ($i=0; $i<$za->numFiles;$i++) {
for ($i = 0; $i < $za->numFiles; $i++) {
$stat_results = $za->statIndex($i);
// echo "index: $i\n";
// print_r($stat_results);
$raw_path = $stat_results['name'];
if(strpos($raw_path,'\\')!==false) { //found a backslash, swap it to forward-slash
$raw_path = strtr($raw_path,'\\','/');
if (strpos($raw_path, '\\') !== false) { //found a backslash, swap it to forward-slash
$raw_path = strtr($raw_path, '\\', '/');
//print "Translating file: ".$stat_results['name']." to: ".$raw_path."\n";
}
// skip macOS resource fork files (?!?!?!)
if(strpos($raw_path,"__MACOSX")!==false && strpos($raw_path,"._") !== false) {
if (strpos($raw_path, '__MACOSX') !== false && strpos($raw_path, '._') !== false) {
//print "SKIPPING macOS Resource fork file: $raw_path\n";
$boring_files[] = $raw_path;
continue;
}
if(@pathinfo($raw_path)['extension'] == "sql") {
print "Found a sql file!\n";
if (@pathinfo($raw_path)['extension'] == 'sql') {
\Log::debug("Found a sql file!");
$sqlfiles[] = $raw_path;
$sqlfile_indices[] = $i;
continue;
}
foreach(array_merge($private_dirs,$public_dirs) as $dir) {
$last_pos = strrpos($raw_path,$dir.'/');
if($last_pos !== false ) {
foreach (array_merge($private_dirs, $public_dirs) as $dir) {
$last_pos = strrpos($raw_path, $dir.'/');
if ($last_pos !== false) {
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
$interesting_files[$raw_path] = ['dest' =>$dir, 'index' => $i];
continue 2;
if($last_pos + strlen($dir) +1 == strlen($raw_path)) {
if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) {
// we don't care about that; we just want files with the appropriate prefix
//print("FOUND THE EXACT DIRECTORY: $dir AT: $raw_path!!!\n");
}
}
}
$good_extensions = ["png","gif","jpg","svg","jpeg","doc","docx","pdf","txt",
"zip","rar","xls","xlsx","lic","xml","rtf", "webp","key","ico"];
foreach(array_merge($private_files, $public_files) as $file) {
$has_wildcard = (strpos($file,"*") !== false);
if($has_wildcard) {
$file = substr($file,0,-1); //trim last character (which should be the wildcard)
$good_extensions = ['png', 'gif', 'jpg', 'svg', 'jpeg', 'doc', 'docx', 'pdf', 'txt',
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico', ];
foreach (array_merge($private_files, $public_files) as $file) {
$has_wildcard = (strpos($file, '*') !== false);
if ($has_wildcard) {
$file = substr($file, 0, -1); //trim last character (which should be the wildcard)
}
$last_pos = strrpos($raw_path,$file); // no trailing slash!
if($last_pos !== false ) {
$last_pos = strrpos($raw_path, $file); // no trailing slash!
if ($last_pos !== false) {
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
if(!in_array($extension, $good_extensions)) {
$this->warn("Potentially unsafe file ".$raw_path." is being skipped");
if (! in_array($extension, $good_extensions)) {
$this->warn('Potentially unsafe file '.$raw_path.' is being skipped');
$boring_files[] = $raw_path;
continue 2;
}
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//no wildcards found in $file, process 'normally'
if($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it.
if ($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it.
// print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though.
$interesting_files[$raw_path] = ['dest' => dirname($file),'index' => $i];
$interesting_files[$raw_path] = ['dest' => dirname($file), 'index' => $i];
continue 2;
}
}
@@ -194,11 +198,11 @@ class RestoreFromBackup extends Command
// print_r($interesting_files);exit(-1);
if( count($sqlfiles) != 1) {
return $this->error("There should be exactly *one* sql backup file found, found: ".( count($sqlfiles) == 0 ? "None" : implode(", ",$sqlfiles)));
if (count($sqlfiles) != 1) {
return $this->error('There should be exactly *one* sql backup file found, found: '.(count($sqlfiles) == 0 ? 'None' : implode(', ', $sqlfiles)));
}
if( strpos($sqlfiles[0], "db-dumps") === false ) {
if (strpos($sqlfiles[0], 'db-dumps') === false) {
//return $this->error("SQL backup file is missing 'db-dumps' component of full pathname: ".$sqlfiles[0]);
//older Snipe-IT installs don't have the db-dumps subdirectory component
}
@@ -207,14 +211,20 @@ class RestoreFromBackup extends Command
$pipes = [];
$env_vars = getenv();
$env_vars['MYSQL_PWD'] = config("database.connections.mysql.password");
$proc_results = proc_open("mysql -h ".escapeshellarg(config('database.connections.mysql.host'))." -u ".escapeshellarg(config('database.connections.mysql.username'))." ".escapeshellarg(config('database.connections.mysql.database')), // yanked -p since we pass via ENV
[0 => ['pipe','r'],1 => ['pipe','w'],2 => ['pipe','w']],
$env_vars['MYSQL_PWD'] = config('database.connections.mysql.password');
// TODO notes: we are stealing the dump_binary_path (which *probably* also has your copy of the mysql binary in it. But it might not, so we might need to extend this)
// we unilaterally prepend a slash to the `mysql` command. This might mean your path could look like /blah/blah/blah//mysql - which should be fine. But maybe in some environments it isn't?
$mysql_binary = config('database.connections.mysql.dump.dump_binary_path').'/mysql';
if( ! file_exists($mysql_binary) ) {
return $this->error("mysql tool at: '$mysql_binary' does not exist, cannot restore. Please edit DB_DUMP_PATH in your .env to point to a directory that contains the mysqldump and mysql binary");
}
$proc_results = proc_open("$mysql_binary -h ".escapeshellarg(config('database.connections.mysql.host')).' -u '.escapeshellarg(config('database.connections.mysql.username')).' '.escapeshellarg(config('database.connections.mysql.database')), // yanked -p since we pass via ENV
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
$pipes,
null,
$env_vars); // this is not super-duper awesome-secure, but definitely more secure than showing it on the CLI, or dropping temporary files with passwords in them.
if($proc_results === false) {
return $this->error("Unable to invoke mysql via CLI");
if ($proc_results === false) {
return $this->error('Unable to invoke mysql via CLI');
}
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
@@ -232,13 +242,17 @@ class RestoreFromBackup extends Command
$this->info($stdout);
$stderr = fgets($pipes[2]);
$this->info($stderr);
return false;
}
$bytes_read = 0;
while(($buffer = fgets($sql_contents)) !== false ) {
//$this->info("Buffer is: '$buffer'");
$bytes_written = fwrite($pipes[0],$buffer);
if($bytes_written === false) {
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
$bytes_read += strlen($buffer);
// \Log::debug("Buffer is: '$buffer'");
$bytes_written = fwrite($pipes[0], $buffer);
if ($bytes_written === false) {
$stdout = fgets($pipes[1]);
$this->info($stdout);
$stderr = fgets($pipes[2]);
@@ -246,6 +260,11 @@ class RestoreFromBackup extends Command
return false;
}
}
if (!feof($sql_contents) || $bytes_read == 0) {
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
}
fclose($pipes[0]);
fclose($sql_contents);
@@ -257,41 +276,40 @@ class RestoreFromBackup extends Command
//wait, have to do fclose() on all pipes first?
$close_results = proc_close($proc_results);
if($close_results != 0) {
return $this->error("There may have been a problem with the database import: Error number ".$close_results);
if ($close_results != 0) {
return $this->error('There may have been a problem with the database import: Error number '.$close_results);
}
//and now copy the files over too (right?)
//FIXME - we don't prune the filesystem space yet!!!!
if($this->option('no-progress')) {
if ($this->option('no-progress')) {
$bar = null;
} else {
$bar = $this->output->createProgressBar(count($interesting_files));
}
foreach($interesting_files AS $pretty_file_name => $file_details) {
foreach ($interesting_files as $pretty_file_name => $file_details) {
$ugly_file_name = $za->statIndex($file_details['index'])['name'];
$fp = $za->getStream($ugly_file_name);
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
$migrated_file = fopen($file_details['dest']."/".basename($pretty_file_name),"w");
while(($buffer = fgets($fp))!== false) {
fwrite($migrated_file,$buffer);
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
while (($buffer = fgets($fp, self::$buffer_size)) !== false) {
fwrite($migrated_file, $buffer);
}
fclose($migrated_file);
fclose($fp);
//$this->info("Wrote $ugly_file_name to $pretty_file_name");
if($bar) {
if ($bar) {
$bar->advance();
}
}
if($bar) {
if ($bar) {
$bar->finish();
$this->line("");
$this->line('');
} else {
$this->info(count($interesting_files)." files were succesfully transferred");
$this->info(count($interesting_files).' files were succesfully transferred');
}
foreach($boring_files as $boring_file) {
$this->warn($boring_file." was skipped.");
foreach ($boring_files as $boring_file) {
$this->warn($boring_file.' was skipped.');
}
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Artisan;
use App\Models\CustomField;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\Setting;
use \Illuminate\Encryption\Encrypter;
use Artisan;
use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter;
class RotateAppKey extends Command
{
@@ -42,9 +42,7 @@ class RotateAppKey extends Command
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nTHIS WILL MODIFY YOUR APP_KEY AND DE-CRYPT YOUR ENCRYPTED CUSTOM FIELDS AND \nRE-ENCRYPT THEM WITH A NEWLY GENERATED KEY. \n\nThere is NO undo. \n\nMake SURE you have a database backup and a backup of your .env generated BEFORE running this command. \n\nIf you do not save the newly generated APP_KEY to your .env in this process, \nyour encrypted data will no longer be decryptable. \n\nAre you SURE you wish to continue, and have confirmed you have a database backup and an .env backup? ")) {
if ($this->confirm("\n****************************************************\nTHIS WILL MODIFY YOUR APP_KEY AND DE-CRYPT YOUR ENCRYPTED CUSTOM FIELDS AND \nRE-ENCRYPT THEM WITH A NEWLY GENERATED KEY. \n\nThere is NO undo. \n\nMake SURE you have a database backup and a backup of your .env generated BEFORE running this command. \n\nIf you do not save the newly generated APP_KEY to your .env in this process, \nyour encrypted data will no longer be decryptable. \n\nAre you SURE you wish to continue, and have confirmed you have a database backup and an .env backup? ")) {
// Get the existing app_key and ciphers
// We put them in a variable since we clear the cache partway through here.
@@ -73,33 +71,26 @@ class RotateAppKey extends Command
$fields = CustomField::where('field_encrypted', '1')->get();
foreach ($fields as $field) {
$assets = Asset::whereNotNull($field->db_column)->get();
foreach ($assets as $asset) {
$asset->{$field->db_column} = $oldEncrypter->decrypt($asset->{$field->db_column});
$this->line('DECRYPTED: '. $field->db_column);
$this->line('DECRYPTED: '.$field->db_column);
$asset->{$field->db_column} = $newEncrypter->encrypt($asset->{$field->db_column});
$this->line('ENCRYPTED: '.$field->db_column);
$asset->save();
}
}
// Handle the LDAP password if one is provided
$setting = Setting::first();
if ($setting->ldap_pword!='') {
$setting->ldap_pword = $oldEncrypter->decrypt($setting->ldap_pword);
$setting->ldap_pword = $newEncrypter->encrypt($setting->ldap_pword);
if ($setting->ldap_pword != '') {
$setting->ldap_pword = $oldEncrypter->decrypt($setting->ldap_pword);
$setting->ldap_pword = $newEncrypter->encrypt($setting->ldap_pword);
$setting->save();
$this->warn('LDAP password has been re-encrypted.');
}
} else {
$this->info('This operation has been canceled. No changes have been made.');
}
@@ -113,7 +104,6 @@ class RotateAppKey extends Command
*/
protected function writeNewEnvironmentFileWith($key)
{
file_put_contents($this->laravel->environmentFilePath(), preg_replace(
$this->keyReplacementPattern(),
'APP_KEY='.$key,
@@ -129,7 +119,7 @@ class RotateAppKey extends Command
protected function keyReplacementPattern()
{
$escaped = preg_quote('='.$this->laravel['config']['app.key'], '/');
return "/^APP_KEY{$escaped}/m";
}
}

View File

@@ -39,22 +39,16 @@ class SendCurrentInventoryToUsers extends Command
*/
public function handle()
{
$users = User::whereNull('deleted_at')->whereNotNull('email')->with('assets', 'accessories', 'licenses')->get();
$count = 0;
foreach ($users as $user) {
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0))
{
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0)) {
$count++;
$user->notify((new CurrentInventory($user)));
}
}
$this->info($count.' users notified.');
}
}

View File

@@ -3,12 +3,12 @@
namespace App\Console\Commands;
use App\Models\Asset;
use App\Models\Recipients\AlertRecipient;
use App\Models\Setting;
use App\Notifications\ExpectedCheckinAdminNotification;
use App\Notifications\ExpectedCheckinNotification;
use Carbon\Carbon;
use Illuminate\Console\Command;
use App\Models\Recipients\AlertRecipient;
class SendExpectedCheckinAlerts extends Command
{
@@ -41,12 +41,12 @@ class SendExpectedCheckinAlerts extends Command
*/
public function handle()
{
$settings = Setting::getSettings();
$settings = Setting::getSettings();
$whenNotify = Carbon::now()->addDays(7);
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
$this->info($whenNotify . ' is deadline');
$this->info($assets->count() . ' assets');
$this->info($whenNotify.' is deadline');
$this->info($assets->count().' assets');
foreach ($assets as $asset) {
if ($asset->assigned && $asset->checkedOutToUser()) {

View File

@@ -41,7 +41,7 @@ class SendExpirationAlerts extends Command
*/
public function handle()
{
$settings = Setting::getSettings();
$settings = Setting::getSettings();
$threshold = $settings->alert_interval;
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {

View File

@@ -4,13 +4,13 @@ namespace App\Console\Commands;
use App\Models\Asset;
use App\Models\License;
use App\Models\Recipients;
use App\Models\Setting;
use App\Notifications\ExpiringAssetsNotification;
use App\Models\Recipients;
use DB;
use Illuminate\Console\Command;
use App\Notifications\SendUpcomingAuditNotification;
use Carbon\Carbon;
use DB;
use Illuminate\Console\Command;
class SendUpcomingAuditReport extends Command
{
@@ -54,7 +54,6 @@ class SendUpcomingAuditReport extends Command
return new \App\Models\Recipients\AlertRecipient($item);
});
// Assets due for auditing
$assets = Asset::whereNotNull('next_audit_date')
@@ -62,7 +61,6 @@ class SendUpcomingAuditReport extends Command
->orderBy('last_audit_date', 'asc')->get();
if ($assets->count() > 0) {
$this->info(trans_choice('mail.upcoming-audits', $assets->count(),
['count' => $assets->count(), 'threshold' => $settings->audit_warning_days]));
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
@@ -70,14 +68,11 @@ class SendUpcomingAuditReport extends Command
} else {
$this->info('No assets to be audited. No report sent.');
}
} elseif ($settings->alert_email=='') {
} elseif ($settings->alert_email == '') {
$this->error('Could not send email. No alert email configured in settings');
} elseif (!$settings->audit_warning_days) {
} elseif (! $settings->audit_warning_days) {
$this->error('No audit warning days set in Admin Notifications. No mail will be sent.');
} elseif ($settings->alerts_enabled!=1) {
} elseif ($settings->alerts_enabled != 1) {
$this->info('Alerts are disabled in the settings. No mail will be sent');
} else {
$this->error('Something went wrong. :( ');
@@ -85,7 +80,5 @@ class SendUpcomingAuditReport extends Command
$this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days);
$this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled);
}
}
}

View File

@@ -45,14 +45,14 @@ class SyncAssetCounters extends Command
if ($assets) {
if ($assets->count() > 0) {
$bar = $this->output->createProgressBar($assets->count());
foreach ($assets as $asset) {
$asset->checkin_counter = (int) $asset->checkins_count;
$asset->checkout_counter = (int) $asset->checkouts_count;
$asset->requests_counter = (int) $asset->user_requests_count;
$asset->unsetEventDispatcher();
$asset->save();
$output['info'][] = 'Asset: ' . $asset->id . ' has ' . $asset->checkin_counter . ' checkins, ' . $asset->checkout_counter . ' checkouts, and ' . $asset->requests_counter . ' requests';
$output['info'][] = 'Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests';
$bar->advance();
}
$bar->finish();
@@ -62,15 +62,10 @@ class SyncAssetCounters extends Command
}
$time_elapsed_secs = microtime(true) - $start;
$this->info('Sync executed in ' . $time_elapsed_secs . ' seconds');
$this->info('Sync executed in '.$time_elapsed_secs.' seconds');
} else {
$this->info('No assets to sync');
}
}
}
}

View File

@@ -38,7 +38,6 @@ class SyncAssetLocations extends Command
*/
public function handle()
{
$output['info'] = [];
$output['warn'] = [];
$output['error'] = [];
@@ -51,96 +50,89 @@ class SyncAssetLocations extends Command
$output['info'][] = 'There are '.$rtd_assets->count().' unassigned assets.';
foreach ($rtd_assets as $rtd_asset) {
$output['info'][] = 'Setting Unassigned Asset ' . $rtd_asset->id . ' ('.$rtd_asset->asset_tag.') to location: ' . $rtd_asset->rtd_location_id . " because their default location is: " . $rtd_asset->rtd_location_id;
$rtd_asset->location_id=$rtd_asset->rtd_location_id;
$output['info'][] = 'Setting Unassigned Asset '.$rtd_asset->id.' ('.$rtd_asset->asset_tag.') to location: '.$rtd_asset->rtd_location_id.' because their default location is: '.$rtd_asset->rtd_location_id;
$rtd_asset->location_id = $rtd_asset->rtd_location_id;
$rtd_asset->unsetEventDispatcher();
$rtd_asset->save();
$bar->advance();
}
$assigned_user_assets = Asset::where('assigned_type','App\Models\User')->whereNotNull('assigned_to')->whereNull('deleted_at')->get();
$assigned_user_assets = Asset::where('assigned_type', \App\Models\User::class)->whereNotNull('assigned_to')->whereNull('deleted_at')->get();
$output['info'][] = 'There are '.$assigned_user_assets->count().' assets checked out to users.';
foreach ($assigned_user_assets as $assigned_user_asset) {
if (($assigned_user_asset->assignedTo) && ($assigned_user_asset->assignedTo->userLoc)) {
$new_location = $assigned_user_asset->assignedTo->userLoc->id;
$output['info'][] ='Setting User Asset ' . $assigned_user_asset->id . ' ('.$assigned_user_asset->asset_tag.') to ' . $assigned_user_asset->assignedTo->userLoc->name . ' which is id: ' . $new_location;
$output['info'][] = 'Setting User Asset '.$assigned_user_asset->id.' ('.$assigned_user_asset->asset_tag.') to '.$assigned_user_asset->assignedTo->userLoc->name.' which is id: '.$new_location;
} else {
$output['warn'][] ='Asset ' . $assigned_user_asset->id . ' ('.$assigned_user_asset->asset_tag.') still has no location! ';
$output['warn'][] = 'Asset '.$assigned_user_asset->id.' ('.$assigned_user_asset->asset_tag.') still has no location! ';
$new_location = $assigned_user_asset->rtd_location_id;
}
$assigned_user_asset->location_id=$new_location;
$assigned_user_asset->location_id = $new_location;
$assigned_user_asset->unsetEventDispatcher();
$assigned_user_asset->save();
$bar->advance();
}
$assigned_location_assets = Asset::where('assigned_type','App\Models\Location')
$assigned_location_assets = Asset::where('assigned_type', \App\Models\Location::class)
->whereNotNull('assigned_to')->whereNull('deleted_at')->get();
$output['info'][] = 'There are '.$assigned_location_assets->count().' assets checked out to locations.';
foreach ($assigned_location_assets as $assigned_location_asset) {
if ($assigned_location_asset->assignedTo) {
$assigned_location_asset->location_id = $assigned_location_asset->assignedTo->id;
$output['info'][] ='Setting Location Assigned asset ' . $assigned_location_asset->id . ' ('.$assigned_location_asset->asset_tag.') that is checked out to '.$assigned_location_asset->assignedTo->name.' (#'.$assigned_location_asset->assignedTo->id.') to location: ' . $assigned_location_asset->assetLoc()->id;
$output['info'][] = 'Setting Location Assigned asset '.$assigned_location_asset->id.' ('.$assigned_location_asset->asset_tag.') that is checked out to '.$assigned_location_asset->assignedTo->name.' (#'.$assigned_location_asset->assignedTo->id.') to location: '.$assigned_location_asset->assetLoc()->id;
$assigned_location_asset->unsetEventDispatcher();
$assigned_location_asset->save();
} else {
$output['warn'][] ='Asset ' . $assigned_location_asset->id . ' ('.$assigned_location_asset->asset_tag.') did not return a valid associated location - perhaps it was deleted?';
$output['warn'][] = 'Asset '.$assigned_location_asset->id.' ('.$assigned_location_asset->asset_tag.') did not return a valid associated location - perhaps it was deleted?';
}
$bar->advance();
}
// Assigned to assets
$assigned_asset_assets = Asset::where('assigned_type','App\Models\Asset')
$assigned_asset_assets = Asset::where('assigned_type', \App\Models\Asset::class)
->whereNotNull('assigned_to')->whereNull('deleted_at')->get();
$output['info'][] ='Asset-assigned assets: '.$assigned_asset_assets->count();
$output['info'][] = 'Asset-assigned assets: '.$assigned_asset_assets->count();
foreach ($assigned_asset_assets as $assigned_asset_asset) {
foreach ($assigned_asset_assets as $assigned_asset_asset) {
// Check to make sure there aren't any invalid relationships
if ($assigned_asset_asset->assetLoc()) {
$assigned_asset_asset->location_id = $assigned_asset_asset->assetLoc()->id;
$output['info'][] ='Setting Asset Assigned asset ' . $assigned_asset_asset->assetLoc()->id. ' ('.$assigned_asset_asset->asset_tag.') location to: ' . $assigned_asset_asset->assetLoc()->id;
$assigned_asset_asset->unsetEventDispatcher();
$assigned_asset_asset->save();
} else {
$output['warn'][] ='Asset Assigned asset ' . $assigned_asset_asset->id. ' ('.$assigned_asset_asset->asset_tag.') does not seem to have a valid location';
}
$bar->advance();
if ($assigned_asset_asset->assetLoc()) {
$assigned_asset_asset->location_id = $assigned_asset_asset->assetLoc()->id;
$output['info'][] = 'Setting Asset Assigned asset '.$assigned_asset_asset->assetLoc()->id.' ('.$assigned_asset_asset->asset_tag.') location to: '.$assigned_asset_asset->assetLoc()->id;
$assigned_asset_asset->unsetEventDispatcher();
$assigned_asset_asset->save();
} else {
$output['warn'][] = 'Asset Assigned asset '.$assigned_asset_asset->id.' ('.$assigned_asset_asset->asset_tag.') does not seem to have a valid location';
}
$unlocated_assets = Asset::whereNull("location_id")->whereNull('deleted_at')->get();
$output['info'][] ='Assets still without a location: '.$unlocated_assets->count();
foreach($unlocated_assets as $unlocated_asset) {
$output['warn'][] ='Asset: '.$unlocated_asset->id.' still has no location. ';
$bar->advance();
}
$unlocated_assets = Asset::whereNull('location_id')->whereNull('deleted_at')->get();
$output['info'][] = 'Assets still without a location: '.$unlocated_assets->count();
foreach ($unlocated_assets as $unlocated_asset) {
$output['warn'][] = 'Asset: '.$unlocated_asset->id.' still has no location. ';
$bar->advance();
}
$bar->finish();
$this->info("\n");
if (($this->option('output')=='all') || ($this->option('output')=='info')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'info')) {
foreach ($output['info'] as $key => $output_text) {
$this->info($output_text);
}
}
if (($this->option('output')=='all') || ($this->option('output')=='warn')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'warn')) {
foreach ($output['warn'] as $key => $output_text) {
$this->warn($output_text);
}
}
if (($this->option('output')=='all') || ($this->option('output')=='error')) {
if (($this->option('output') == 'all') || ($this->option('output') == 'error')) {
foreach ($output['error'] as $key => $output_text) {
$this->error($output_text);
}
}
}
}

View File

@@ -6,7 +6,6 @@ use Illuminate\Console\Command;
class SystemBackup extends Command
{
/**
* The console command name.
*
@@ -40,6 +39,5 @@ class SystemBackup extends Command
{
//
$this->call('backup:run');
}
}

View File

@@ -37,7 +37,6 @@ class Version extends Command
*/
public function handle()
{
$use_branch = $this->option('branch');
$use_type = $this->option('type');
$git_branch = trim(shell_exec('git rev-parse --abbrev-ref HEAD'));
@@ -54,72 +53,66 @@ class Version extends Command
$this->line('Type is: '.$use_type);
$this->line('Current version is: '.$full_hash_version);
if (count($version)==3) {
if (count($version) == 3) {
$this->line('This does not look like an alpha/beta release.');
} else {
if (array_key_exists('3',$version)) {
if (array_key_exists('3', $version)) {
$this->line('The current version looks like a beta release.');
$prerelease_version = $version[1];
$hash_version = $version[3];
}
}
$app_version_raw = explode('.', $app_version);
$maj = str_replace('v', '', $app_version_raw[0]);
$min = $app_version_raw[1];
$patch = '';
// This is a major release that might not have a third .0
if (array_key_exists(2, $app_version_raw)) {
$patch = $app_version_raw[2];
}
if ($use_type=='major') {
$app_version = "v".($maj + 1).".$min.$patch";
} elseif ($use_type=='minor') {
$app_version = "v"."$maj.".($min + 1).".$patch";
} elseif ($use_type=='pre') {
$pre_raw = str_replace('beta','', $prerelease_version);
$pre_raw = str_replace('alpha','', $pre_raw);
$pre_raw = str_ireplace('rc','', $pre_raw);
if ($use_type == 'major') {
$app_version = 'v'.($maj + 1).".$min.$patch";
} elseif ($use_type == 'minor') {
$app_version = 'v'."$maj.".($min + 1).".$patch";
} elseif ($use_type == 'pre') {
$pre_raw = str_replace('beta', '', $prerelease_version);
$pre_raw = str_replace('alpha', '', $pre_raw);
$pre_raw = str_ireplace('rc', '', $pre_raw);
$pre_raw = $pre_raw++;
$this->line('Setting the pre-release to '. $prerelease_version.'-'.$pre_raw);
$app_version = "v"."$maj.".($min + 1).".$patch";
} elseif ($use_type=='patch') {
$app_version = "v" . "$maj.$min." . ($patch + 1);
$this->line('Setting the pre-release to '.$prerelease_version.'-'.$pre_raw);
$app_version = 'v'."$maj.".($min + 1).".$patch";
} elseif ($use_type == 'patch') {
$app_version = 'v'."$maj.$min.".($patch + 1);
// If nothing is passed, leave the version as it is, just increment the build
} else {
$app_version = "v" . "$maj.$min." . $patch;
$app_version = 'v'."$maj.$min.".$patch;
}
// Determine if this tag already exists, or if this prior to a release
$this->line('Running: git rev-parse master '.$current_app_version);
// $pre_release = trim(shell_exec('git rev-parse '.$use_branch.' '.$current_app_version.' 2>&1 1> /dev/null'));
if ($use_branch=='develop') {
if ($use_branch == 'develop') {
$app_version = $app_version.'-pre';
}
$full_app_version = $app_version.' - build '.$build_version.'-'.$hash_version;
$array = var_export(
array(
[
'app_version' => $app_version,
'full_app_version' => $full_app_version,
'build_version' => $build_version,
'prerelease_version' => $prerelease_version,
'hash_version' => $hash_version,
'full_hash' => $full_hash_version,
'branch' => $git_branch),
'branch' => $git_branch, ],
true
);
// Construct our file content
$content = <<<CON
@@ -129,7 +122,6 @@ CON;
// And finally write the file and output the current version
\File::put($versionFile, $content);
$this->info('Setting NEW version: '. $full_app_version.' ('.$git_branch.')');
$this->info('Setting NEW version: '.$full_app_version.' ('.$git_branch.')');
}
}

View File

@@ -10,7 +10,6 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*

View File

@@ -18,6 +18,6 @@ class CheckoutAccepted
*/
public function __construct(CheckoutAcceptance $acceptance)
{
$this->acceptance = $acceptance;
$this->acceptance = $acceptance;
}
}

View File

@@ -10,7 +10,7 @@ use Illuminate\Queue\SerializesModels;
class CheckoutDeclined
{
use Dispatchable, SerializesModels;
/**
* Create a new event instance.
*
@@ -18,6 +18,6 @@ class CheckoutDeclined
*/
public function __construct(CheckoutAcceptance $acceptance)
{
$this->acceptance = $acceptance;
$this->acceptance = $acceptance;
}
}

View File

@@ -25,8 +25,8 @@ class CheckoutableCheckedIn
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedInBy = $checkedInBy;
$this->note = $note;
$this->action_date = $action_date ?? date('Y-m-d');
$this->checkedInBy = $checkedInBy;
$this->note = $note;
$this->action_date = $action_date ?? date('Y-m-d');
}
}

View File

@@ -25,6 +25,6 @@ class CheckoutableCheckedOut
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedOutBy = $checkedOutBy;
$this->note = $note;
$this->note = $note;
}
}

View File

@@ -6,17 +6,17 @@ use Exception;
class CheckoutNotAllowed extends Exception
{
private $errorMessage;
function __construct($errorMessage = null)
public function __construct($errorMessage = null)
{
$this->errorMessage = $errorMessage;
parent::__construct($errorMessage);
}
public function __toString()
{
return is_null($this->errorMessage) ? "A checkout is not allowed under these circumstances" : $this->errorMessage;
return is_null($this->errorMessage) ? 'A checkout is not allowed under these circumstances' : $this->errorMessage;
}
}

View File

@@ -2,18 +2,19 @@
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Helpers\Helper;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException;
use Log;
use Throwable;
use JsonException;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
* A list of the exception types that are not reported.
*
* @var array
*/
@@ -26,6 +27,7 @@ class Handler extends ExceptionHandler
\Illuminate\Validation\ValidationException::class,
\Intervention\Image\Exception\NotSupportedException::class,
\League\OAuth2\Server\Exception\OAuthServerException::class,
JsonException::class,
];
/**
@@ -33,25 +35,25 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @param \Throwable $exception
* @return void
*/
public function report(Exception $exception)
public function report(Throwable $exception)
{
if ($this->shouldReport($exception)) {
\Log::error($exception);
Log::error($exception);
return parent::report($exception);
}
}
/**
* Render an exception into an HTTP response.
*
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
public function render($request, Throwable $e)
{
@@ -60,6 +62,12 @@ class Handler extends ExceptionHandler
return redirect()->back()->with('error', trans('general.token_expired'));
}
// Invalid JSON exception
// TODO: don't understand why we have to do this when we have the invalidJson() method, below, but, well, whatever
if ($e instanceof JsonException) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422);
}
// Handle Ajax requests that fail because the model doesn't exist
if ($request->ajax() || $request->wantsJson()) {
@@ -76,10 +84,12 @@ class Handler extends ExceptionHandler
switch ($e->getStatusCode()) {
case '404':
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
case '405':
case '429':
return response()->json(Helper::formatStandardApiResponse('error', null, 'Too many requests'), 429);
case '405':
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
default:
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), 405);
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
}
}
@@ -96,7 +106,7 @@ class Handler extends ExceptionHandler
}
/**
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
@@ -112,15 +122,27 @@ class Handler extends ExceptionHandler
return redirect()->guest('login');
}
/**
* Convert a validation exception into a JSON response.
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Validation\ValidationException $exception
* @return \Illuminate\Http\JsonResponse
* @var array
*/
protected function invalidJson($request, ValidationException $exception)
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
return response()->json(Helper::formatStandardApiResponse('error', null, $exception->errors(), 400));
$this->reportable(function (Throwable $e) {
//
});
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,17 @@
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Storage;
class StorageHelper
{
static function downloader($filename, $disk = 'default') {
if($disk == 'default') {
public static function downloader($filename, $disk = 'default')
{
if ($disk == 'default') {
$disk = config('filesystems.default');
}
switch(config("filesystems.disks.$disk.driver")) {
switch (config("filesystems.disks.$disk.driver")) {
case 'local':
return response()->download(Storage::disk($disk)->path($filename)); //works for PRIVATE or public?!
@@ -20,4 +22,4 @@ class StorageHelper
return Storage::disk($disk)->download($filename);
}
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Accessories;
use App\Helpers\Helper;
@@ -30,10 +31,10 @@ class AccessoriesController extends Controller
public function index()
{
$this->authorize('index', Accessory::class);
return view('accessories/index');
}
/**
* Returns a view with a form to create a new Accessory.
*
@@ -45,11 +46,11 @@ class AccessoriesController extends Controller
{
$this->authorize('create', Accessory::class);
$category_type = 'accessory';
return view('accessories/edit')->with('category_type', $category_type)
->with('item', new Accessory);
}
/**
* Validate and save new Accessory from form post
*
@@ -78,14 +79,17 @@ class AccessoriesController extends Controller
$accessory->qty = request('qty');
$accessory->user_id = Auth::user()->id;
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory created?
if ($accessory->save()) {
// Redirect to the new accessory page
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
@@ -102,6 +106,7 @@ class AccessoriesController extends Controller
if ($item = Accessory::find($accessoryId)) {
$this->authorize($item);
return view('accessories/edit', compact('item'))->with('category_type', 'accessory');
}
@@ -140,6 +145,7 @@ class AccessoriesController extends Controller
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
@@ -147,6 +153,7 @@ class AccessoriesController extends Controller
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
@@ -168,11 +175,11 @@ class AccessoriesController extends Controller
if ($accessory->hasUsers() > 0) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers())));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', ['count'=> $accessory->hasUsers()]));
}
if ($accessory->image) {
try {
try {
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
} catch (\Exception $e) {
\Log::debug($e);
@@ -180,6 +187,7 @@ class AccessoriesController extends Controller
}
$accessory->delete();
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success'));
}
@@ -202,6 +210,7 @@ class AccessoriesController extends Controller
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]));
}
}

View File

@@ -17,7 +17,7 @@ class AccessoryCheckinController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param integer $accessoryUserId
* @param int $accessoryUserId
* @param string $backto
* @return View
* @internal param int $accessoryId
@@ -33,6 +33,7 @@ class AccessoryCheckinController extends Controller
$accessory = Accessory::find($accessory_user->accessory_id);
$this->authorize('checkin', $accessory);
return view('accessories/checkin', compact('accessory'))->with('backto', $backto);
}
@@ -49,7 +50,7 @@ class AccessoryCheckinController extends Controller
*/
public function store(Request $request, $accessoryUserId = null, $backto = null)
{
// Check if the accessory exists
// Check if the accessory exists
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
@@ -60,7 +61,7 @@ class AccessoryCheckinController extends Controller
$this->authorize('checkin', $accessory);
$checkin_at = date('Y-m-d');
if($request->filled('checkin_at')){
if ($request->filled('checkin_at')) {
$checkin_at = $request->input('checkin_at');
}
@@ -70,7 +71,7 @@ class AccessoryCheckinController extends Controller
event(new CheckoutableCheckedIn($accessory, User::find($return_to), Auth::user(), $request->input('note'), $checkin_at));
return redirect()->route("accessories.show", $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
}
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));

View File

@@ -14,7 +14,6 @@ use Illuminate\Support\Facades\Input;
class AccessoryCheckoutController extends Controller
{
/**
* Return the form to checkout an Accessory to a user.
*
@@ -32,7 +31,6 @@ class AccessoryCheckoutController extends Controller
}
if ($accessory->category) {
$this->authorize('checkout', $accessory);
// Get the dropdown of users and then pass it to the checkout view
@@ -56,7 +54,7 @@ class AccessoryCheckoutController extends Controller
*/
public function store(Request $request, $accessoryId)
{
// Check if the accessory exists
// Check if the accessory exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.user_not_found'));
@@ -64,11 +62,11 @@ class AccessoryCheckoutController extends Controller
$this->authorize('checkout', $accessory);
if (!$user = User::find($request->input('assigned_to'))) {
if (! $user = User::find($request->input('assigned_to'))) {
return redirect()->route('checkout/accessory', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
}
// Update the accessory data
// Update the accessory data
$accessory->assigned_to = e($request->input('assigned_to'));
$accessory->users()->attach($accessory->id, [
@@ -76,14 +74,14 @@ class AccessoryCheckoutController extends Controller
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'assigned_to' => $request->get('assigned_to'),
'note' => $request->input('note')
'note' => $request->input('note'),
]);
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
// Redirect to the new accessory page
// Redirect to the new accessory page
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success'));
}
}

View File

@@ -1,4 +1,5 @@
<?php
<?php
namespace App\Http\Controllers\Account;
use App\Events\CheckoutAccepted;
@@ -14,14 +15,15 @@ use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class AcceptanceController extends Controller {
class AcceptanceController extends Controller
{
/**
* Show a listing of pending checkout acceptances for the current user
*
*
* @return View
*/
public function index() {
public function index()
{
$acceptances = CheckoutAcceptance::forUser(Auth::user())->pending()->get();
return view('account/accept.index', compact('acceptances'));
@@ -29,12 +31,12 @@ class AcceptanceController extends Controller {
/**
* Shows a form to either accept or decline the checkout acceptance
*
*
* @param int $id
* @return mixed
*/
public function create($id) {
public function create($id)
{
$acceptance = CheckoutAcceptance::find($id);
if (is_null($acceptance)) {
@@ -43,28 +45,28 @@ class AcceptanceController extends Controller {
if (! $acceptance->isPending()) {
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
}
}
if (! $acceptance->isCheckedOutTo(Auth::user())) {
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
if (! Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
}
}
return view('account/accept.create', compact('acceptance'));
}
}
/**
* Stores the accept/decline of the checkout acceptance
*
*
* @param Request $request
* @param int $id
* @return Redirect
*/
public function store(Request $request, $id) {
public function store(Request $request, $id)
{
$acceptance = CheckoutAcceptance::find($id);
if (is_null($acceptance)) {
@@ -73,55 +75,50 @@ class AcceptanceController extends Controller {
if (! $acceptance->isPending()) {
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
}
}
if (! $acceptance->isCheckedOutTo(Auth::user())) {
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
if (! Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
}
}
if (!$request->filled('asset_acceptance')) {
if (! $request->filled('asset_acceptance')) {
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
}
/**
* Get the signature and save it
*/
if (!Storage::exists('private_uploads/signatures')) Storage::makeDirectory('private_uploads/signatures', 775);
if (! Storage::exists('private_uploads/signatures')) {
Storage::makeDirectory('private_uploads/signatures', 775);
}
$sig_filename = '';
if ($request->filled('signature_output')) {
$sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png";
$sig_filename = 'siglog-'.Str::uuid().'-'.date('Y-m-d-his').'.png';
$data_uri = e($request->input('signature_output'));
$encoded_image = explode(",", $data_uri);
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/'.$sig_filename, (string)$decoded_image);
Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
}
if ($request->input('asset_acceptance') == 'accepted') {
$acceptance->accept($sig_filename);
event(new CheckoutAccepted($acceptance));
$return_msg = trans('admin/users/message.accepted');
} else {
$acceptance->decline($sig_filename);
$acceptance->decline($sig_filename);
event(new CheckoutDeclined($acceptance));
$return_msg = trans('admin/users/message.declined');
}
return redirect()->to('account/accept')->with('success', $return_msg);
}
}
}

View File

@@ -9,10 +9,21 @@ class ActionlogController extends Controller
{
public function displaySig($filename)
{
// PHP doesn't let you handle file not found errors well with
// file_get_contents, so we set the error reporting for just this class
error_reporting(0);
$this->authorize('view', \App\Models\Asset::class);
$file = config('app.private_uploads') . '/signatures/' . $filename;
$file = config('app.private_uploads').'/signatures/'.$filename;
$filetype = Helper::checkUploadIsImage($file);
$contents = file_get_contents($file);
return Response::make($contents)->header('Content-Type', $filetype);
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
if ($contents === false) {
\Log::warn('File '.$file.' not found');
return false;
} else {
return Response::make($contents)->header('Content-Type', $filetype);
}
}
}

View File

@@ -9,8 +9,8 @@ use App\Http\Transformers\SelectlistTransformer;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Carbon\Carbon;
use Auth;
use Carbon\Carbon;
use DB;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
@@ -27,6 +27,7 @@ class AccessoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Accessory::class);
$allowed_columns = ['id', 'name', 'model_number', 'eol', 'notes', 'created_at', 'min_amt', 'company_id'];
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
@@ -39,7 +40,8 @@ class AccessoriesController extends Controller
'notes',
'created_at',
'min_amt',
'company_id'
'company_id',
'notes',
];
@@ -50,25 +52,29 @@ class AccessoriesController extends Controller
}
if ($request->filled('company_id')) {
$accessories->where('company_id','=',$request->input('company_id'));
$accessories->where('company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {
$accessories->where('category_id','=',$request->input('category_id'));
$accessories->where('category_id', '=', $request->input('category_id'));
}
if ($request->filled('manufacturer_id')) {
$accessories->where('manufacturer_id','=',$request->input('manufacturer_id'));
$accessories->where('manufacturer_id', '=', $request->input('manufacturer_id'));
}
if ($request->filled('supplier_id')) {
$accessories->where('supplier_id','=',$request->input('supplier_id'));
$accessories->where('supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('location_id')) {
$accessories->where('location_id','=',$request->input('location_id'));
}
if ($request->filled('notes')) {
$accessories->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($accessories) && ($request->get('offset') > $accessories->count())) ? $accessories->count() : $request->get('offset', 0);
@@ -100,10 +106,10 @@ class AccessoriesController extends Controller
$accessories = $accessories->orderBy($column_sort, $order);
break;
}
$total = $accessories->count();
$accessories = $accessories->skip($offset)->take($limit)->get();
return (new AccessoriesTransformer)->transformAccessories($accessories, $total);
}
@@ -126,6 +132,7 @@ class AccessoriesController extends Controller
if ($accessory->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $accessory, trans('admin/accessories/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $accessory->getErrors()));
}
@@ -142,6 +149,7 @@ class AccessoriesController extends Controller
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::findOrFail($id);
return (new AccessoriesTransformer)->transformAccessory($accessory);
}
@@ -158,6 +166,7 @@ class AccessoriesController extends Controller
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::findOrFail($id);
return (new AccessoriesTransformer)->transformAccessory($accessory);
}
@@ -175,7 +184,7 @@ class AccessoriesController extends Controller
$this->authorize('view', Accessory::class);
$accessory = Accessory::with('lastCheckout')->findOrFail($id);
if (!Company::isCurrentUserHasAccess($accessory)) {
if (! Company::isCurrentUserHasAccess($accessory)) {
return ['total' => 0, 'rows' => []];
}
@@ -185,7 +194,7 @@ class AccessoriesController extends Controller
$accessory_users = $accessory->users;
$total = $accessory_users->count();
if($total < $offset){
if ($total < $offset) {
$offset = 0;
}
@@ -245,12 +254,12 @@ class AccessoriesController extends Controller
$this->authorize($accessory);
if ($accessory->hasUsers() > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers()))));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.assoc_users', ['count'=> $accessory->hasUsers()])));
}
$accessory->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.delete.success')));
}
@@ -276,7 +285,7 @@ class AccessoriesController extends Controller
if ($accessory->numRemaining() > 0) {
if (!$user = User::find($request->input('assigned_to'))) {
if (! $user = User::find($request->input('assigned_to'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkout.user_does_not_exist')));
}
@@ -288,12 +297,12 @@ class AccessoriesController extends Controller
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'assigned_to' => $request->get('assigned_to'),
'note' => $request->get('note')
'note' => $request->get('note'),
]);
$accessory->logCheckout($request->input('note'), $user);
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'No accessories remaining'));
@@ -306,7 +315,7 @@ class AccessoriesController extends Controller
* @uses Accessory::checkin_email() to determine if an email can and should be sent
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param integer $accessoryUserId
* @param int $accessoryUserId
* @param string $backto
* @return Redirect
* @internal param int $accessoryId
@@ -324,7 +333,7 @@ class AccessoriesController extends Controller
// Was the accessory updated?
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
if (!is_null($accessory_user->assigned_to)) {
if (! is_null($accessory_user->assigned_to)) {
$user = User::find($accessory_user->assigned_to);
}
@@ -339,7 +348,7 @@ class AccessoriesController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
}
@@ -355,7 +364,7 @@ class AccessoriesController extends Controller
$accessories = Accessory::select([
'accessories.id',
'accessories.name'
'accessories.name',
]);
if ($request->filled('search')) {
@@ -364,10 +373,7 @@ class AccessoriesController extends Controller
$accessories = $accessories->orderBy('name', 'ASC')->paginate(50);
return (new SelectlistTransformer)->transformSelectlist($accessories);
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
@@ -29,11 +30,12 @@ class AssetMaintenancesController extends Controller
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return String JSON
* @return string JSON
*/
public function index(Request $request)
{
$maintenances = AssetMaintenance::with('asset', 'asset.model','asset.location', 'supplier', 'asset.company', 'admin');
$this->authorize('view', Asset::class);
$maintenances = AssetMaintenance::with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
if ($request->filled('search')) {
$maintenances = $maintenances->TextSearch($request->input('search'));
@@ -50,7 +52,6 @@ class AssetMaintenancesController extends Controller
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$allowed_columns = [
'id',
'title',
@@ -62,7 +63,7 @@ class AssetMaintenancesController extends Controller
'notes',
'asset_tag',
'asset_name',
'user_id'
'user_id',
];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
@@ -97,10 +98,11 @@ class AssetMaintenancesController extends Controller
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return String JSON
* @return string JSON
*/
public function store(Request $request)
{
$this->authorize('update', Asset::class);
// create a new model instance
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
@@ -109,24 +111,24 @@ class AssetMaintenancesController extends Controller
$assetMaintenance->notes = e($request->input('notes'));
$asset = Asset::find(e($request->input('asset_id')));
if (!Company::isCurrentUserHasAccess($asset)) {
if (! Company::isCurrentUserHasAccess($asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot add a maintenance for that asset'));
}
// Save the asset maintenance data
$assetMaintenance->asset_id = $request->input('asset_id');
$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');
$assetMaintenance->user_id = Auth::id();
$assetMaintenance->title = $request->input('title');
$assetMaintenance->start_date = $request->input('start_date');
$assetMaintenance->completion_date = $request->input('completion_date');
$assetMaintenance->user_id = Auth::id();
if (( $assetMaintenance->completion_date !== null )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')
&& ($assetMaintenance->start_date !== '0000-00-00')
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
@@ -140,7 +142,6 @@ class AssetMaintenancesController extends Controller
}
/**
* Validates and stores an update to an asset maintenance
*
@@ -149,14 +150,15 @@ class AssetMaintenancesController extends Controller
* @param int $request
* @version v1.0
* @since [v4.0]
* @return String JSON
* @return string JSON
*/
public function update(Request $request, $assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
}
@@ -167,41 +169,41 @@ class AssetMaintenancesController extends Controller
$asset = Asset::find(request('asset_id'));
if (!Company::isCurrentUserHasAccess($asset)) {
if (! Company::isCurrentUserHasAccess($asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
}
// Save the asset maintenance data
$assetMaintenance->asset_id = $request->input('asset_id');
$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');
$assetMaintenance->title = $request->input('title');
$assetMaintenance->start_date = $request->input('start_date');
$assetMaintenance->completion_date = $request->input('completion_date');
if (( $assetMaintenance->completion_date == null )
if (($assetMaintenance->completion_date == null)
) {
if (( $assetMaintenance->asset_maintenance_time !== 0 )
|| ( !is_null($assetMaintenance->asset_maintenance_time) )
if (($assetMaintenance->asset_maintenance_time !== 0)
|| (! is_null($assetMaintenance->asset_maintenance_time))
) {
$assetMaintenance->asset_maintenance_time = null;
}
}
if (( $assetMaintenance->completion_date !== null )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')
&& ($assetMaintenance->start_date !== '0000-00-00')
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
// Was the asset maintenance created?
if ($assetMaintenance->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.edit.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors()));
}
@@ -212,14 +214,15 @@ class AssetMaintenancesController extends Controller
* @param int $assetMaintenanceId
* @version v1.0
* @since [v4.0]
* @return String JSON
* @return string JSON
*/
public function destroy($assetMaintenanceId)
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot delete a maintenance for that asset'));
}
@@ -237,14 +240,16 @@ class AssetMaintenancesController extends Controller
* @param int $assetMaintenanceId
* @version v1.0
* @since [v4.0]
* @return String JSON
* @return string JSON
*/
public function show($assetMaintenanceId)
{
$this->authorize('view', Asset::class);
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot view a maintenance for that asset'));
}
return (new AssetMaintenancesTransformer())->transformAssetMaintenance($assetMaintenance);
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
@@ -43,7 +44,7 @@ class AssetModelsController extends Controller
'manufacturer',
'requestable',
'assets_count',
'category'
'category',
];
$assetmodels = AssetModel::select([
@@ -62,11 +63,9 @@ class AssetModelsController extends Controller
'models.deleted_at',
'models.updated_at',
])
->with('category','depreciation', 'manufacturer','fieldset')
->with('category', 'depreciation', 'manufacturer', 'fieldset')
->withCount('assets as assets_count');
if ($request->input('status')=='deleted') {
$assetmodels->onlyTrashed();
}
@@ -99,6 +98,7 @@ class AssetModelsController extends Controller
$total = $assetmodels->count();
$assetmodels = $assetmodels->skip($offset)->take($limit)->get();
return (new AssetModelsTransformer)->transformAssetModels($assetmodels, $total);
}
@@ -123,6 +123,7 @@ class AssetModelsController extends Controller
}
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
}
/**
@@ -137,6 +138,7 @@ class AssetModelsController extends Controller
{
$this->authorize('view', AssetModel::class);
$assetmodel = AssetModel::withCount('assets as assets_count')->findOrFail($id);
return (new AssetModelsTransformer)->transformAssetModel($assetmodel);
}
@@ -151,7 +153,8 @@ class AssetModelsController extends Controller
public function assets($id)
{
$this->authorize('view', AssetModel::class);
$assets = Asset::where('model_id','=',$id)->get();
$assets = Asset::where('model_id', '=', $id)->get();
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
@@ -181,7 +184,7 @@ class AssetModelsController extends Controller
* it, but I'll be damned if I can think of one. - snipe
*/
if ($request->filled('custom_fieldset_id')) {
$assetmodel->fieldset_id = $request->get("custom_fieldset_id");
$assetmodel->fieldset_id = $request->get('custom_fieldset_id');
}
@@ -207,11 +210,11 @@ class AssetModelsController extends Controller
$this->authorize('delete', $assetmodel);
if ($assetmodel->assets()->count() > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.assoc_users')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.assoc_users')));
}
if ($assetmodel->image) {
try {
try {
Storage::disk('public')->delete('assetmodels/'.$assetmodel->image);
} catch (\Exception $e) {
\Log::info($e);
@@ -219,8 +222,8 @@ class AssetModelsController extends Controller
}
$assetmodel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/models/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/models/message.delete.success')));
}
/**
@@ -229,11 +232,11 @@ class AssetModelsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$assetmodels = AssetModel::select([
'models.id',
'models.name',
@@ -241,7 +244,7 @@ class AssetModelsController extends Controller
'models.model_number',
'models.manufacturer_id',
'models.category_id',
])->with('manufacturer','category');
])->with('manufacturer', 'category');
$settings = \App\Models\Setting::getSettings();
@@ -252,7 +255,6 @@ class AssetModelsController extends Controller
$assetmodels = $assetmodels->OrderCategory('ASC')->OrderManufacturer('ASC')->orderby('models.name', 'asc')->orderby('models.model_number', 'asc')->paginate(50);
foreach ($assetmodels as $assetmodel) {
$assetmodel->use_text = '';
if ($settings->modellistCheckedValue('category')) {
@@ -263,10 +265,10 @@ class AssetModelsController extends Controller
$assetmodel->use_text .= (($assetmodel->manufacturer) ? $assetmodel->manufacturer->name.' ' : '');
}
$assetmodel->use_text .= $assetmodel->name;
$assetmodel->use_text .= $assetmodel->name;
if (($settings->modellistCheckedValue('model_number')) && ($assetmodel->model_number!='')) {
$assetmodel->use_text .= ' (#'.$assetmodel->model_number.')';
if (($settings->modellistCheckedValue('model_number')) && ($assetmodel->model_number != '')) {
$assetmodel->use_text .= ' (#'.$assetmodel->model_number.')';
}
$assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null;
@@ -274,5 +276,4 @@ class AssetModelsController extends Controller
return (new SelectlistTransformer)->transformSelectlist($assetmodels);
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Api;
use App\Events\CheckoutableCheckedIn;
@@ -32,7 +33,6 @@ use TCPDF;
use Validator;
use Route;
/**
* This class controls all actions related to assets for
* the Snipe-IT Asset Management application.
@@ -42,7 +42,6 @@ use Route;
*/
class AssetsController extends Controller
{
/**
* Returns JSON listing of all assets
*
@@ -53,9 +52,8 @@ class AssetsController extends Controller
*/
public function index(Request $request, $audit = null)
{
\Log::debug(Route::currentRouteName());
$filter_non_deprecable_assets = false;
/**
* This looks MAD janky (and it is), but the AssetsController@index does a LOT of heavy lifting throughout the
@@ -69,6 +67,7 @@ class AssetsController extends Controller
* which would have been far worse of a mess. *sad face* - snipe (Sept 1, 2021)
*/
if (Route::currentRouteName()=='api.depreciation-report.index') {
$filter_non_deprecable_assets = true;
$transformer = 'App\Http\Transformers\DepreciationReportTransformer';
$this->authorize('reports.view');
} else {
@@ -103,7 +102,7 @@ class AssetsController extends Controller
'requests_counter',
];
$filter = array();
$filter = [];
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
@@ -111,22 +110,38 @@ class AssetsController extends Controller
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
foreach ($all_custom_fields as $field) {
$allowed_columns[]=$field->db_column_name();
$allowed_columns[] = $field->db_column_name();
}
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
$assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets')
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier'); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
if ($filter_non_deprecable_assets) {
$non_deprecable_models = AssetModel::select('id')->whereNotNull('depreciation_id')->get();
$assets->InModelList($non_deprecable_models->toArray());
}
// These are used by the API to query against specific ID numbers.
// They are also used by the individual searches on detail pages like
// locations, etc.
// Search custom fields by column name
foreach ($all_custom_fields as $field) {
if ($request->filled($field->db_column_name())) {
$assets->where($field->db_column_name(), '=', $request->input($field->db_column_name()));
}
}
if ($request->filled('status_id')) {
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
if ($request->input('requestable')=='true') {
if ($request->input('requestable') == 'true') {
$assets->where('assets.requestable', '=', '1');
}
@@ -181,7 +196,6 @@ class AssetsController extends Controller
// This is used by the audit reporting routes
if (Gate::allows('audit', Asset::class)) {
switch ($audit) {
case 'due':
$assets->DueOrOverdueForAudit($settings);
@@ -204,19 +218,19 @@ class AssetsController extends Controller
$assets->onlyTrashed();
break;
case 'Pending':
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',0)
->where('status_alias.pending','=',1)
$assets->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id')
->where('status_alias.deployable', '=', 0)
->where('status_alias.pending', '=', 1)
->where('status_alias.archived', '=', 0);
});
break;
case 'RTD':
$assets->whereNull('assets.assigned_to')
->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',1)
->where('status_alias.pending','=',0)
->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id')
->where('status_alias.deployable', '=', 1)
->where('status_alias.pending', '=', 0)
->where('status_alias.archived', '=', 0);
});
break;
@@ -224,19 +238,19 @@ class AssetsController extends Controller
$assets->Undeployable();
break;
case 'Archived':
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',0)
->where('status_alias.pending','=',0)
$assets->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id')
->where('status_alias.deployable', '=', 0)
->where('status_alias.pending', '=', 0)
->where('status_alias.archived', '=', 1);
});
break;
case 'Requestable':
$assets->where('assets.requestable', '=', 1)
->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',1)
->where('status_alias.pending','=',0)
->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id')
->where('status_alias.deployable', '=', 1)
->where('status_alias.pending', '=', 0)
->where('status_alias.archived', '=', 0);
});
@@ -247,34 +261,34 @@ class AssetsController extends Controller
break;
default:
if ((!$request->filled('status_id')) && ($settings->show_archived_in_list!='1')) {
if ((! $request->filled('status_id')) && ($settings->show_archived_in_list != '1')) {
// terrible workaround for complex-query Laravel bug in fulltext
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
$assets->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id')
->where('status_alias.archived', '=', 0);
});
// If there is a status ID, don't take show_archived_in_list into consideration
} else {
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id");
$assets->join('status_labels AS status_alias', function ($join) {
$join->on('status_alias.id', '=', 'assets.status_id');
});
}
}
if ((!is_null($filter)) && (count($filter)) > 0) {
if ((! is_null($filter)) && (count($filter)) > 0) {
$assets->ByFilter($filter);
} elseif ($request->filled('search')) {
$assets->TextSearch($request->input('search'));
}
// This is kinda gross, but we need to do this because the Bootstrap Tables
// API passes custom field ordering as custom_fields.fieldname, and we have to strip
// that out to let the default sorter below order them correctly on the assets table.
$sort_override = str_replace('custom_fields.','', $request->input('sort')) ;
$sort_override = str_replace('custom_fields.', '', $request->input('sort'));
// This handles all of the pivot sorting (versus the assets.* fields
// in the allowed_columns array)
@@ -320,7 +334,7 @@ class AssetsController extends Controller
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
/**
* Include additional associated relationships
*/
@@ -330,8 +344,6 @@ class AssetsController extends Controller
}]);
}
/**
* Here we're just determining which Transformer (via $transformer) to use based on the
@@ -351,8 +363,9 @@ class AssetsController extends Controller
*/
public function showByTag(Request $request, $tag)
{
if ($asset = Asset::with('assetstatus')->with('assignedTo')->where('asset_tag',$tag)->first()) {
if ($asset = Asset::with('assetstatus')->with('assignedTo')->where('asset_tag', $tag)->first()) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset, $request);
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
@@ -370,12 +383,17 @@ class AssetsController extends Controller
public function showBySerial(Request $request, $serial)
{
$this->authorize('index', Asset::class);
if ($assets = Asset::with('assetstatus')->with('assignedTo')
->withTrashed()->where('serial', $serial)->get()) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
$assets = Asset::with('assetstatus')->with('assignedTo');
if ($request->input('deleted', 'false') === 'true') {
$assets = $assets->withTrashed();
}
}
$assets = $assets->where('serial', $serial)->get();
if ($assets) {
@@ -398,17 +416,20 @@ class AssetsController extends Controller
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()
->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')->findOrFail($id)) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset, $request->input('components') );
}
}
public function licenses(Request $request, $id)
{
$this->authorize('view', Asset::class);
$this->authorize('view', License::class);
$asset = Asset::where('id', $id)->withTrashed()->first();
$licenses = $asset->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
}
@@ -431,7 +452,7 @@ class AssetsController extends Controller
'assets.model_id',
'assets.assigned_to',
'assets.assigned_type',
'assets.status_id'
'assets.status_id',
])->with('model', 'assetstatus', 'assignedTo')->NotArchived(), 'company_id', 'assets');
if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') {
@@ -458,15 +479,14 @@ class AssetsController extends Controller
}
if ($asset->assetstatus->getStatuslabelType()=='pending') {
$asset->use_text .= '('.$asset->assetstatus->getStatuslabelType().')';
if ($asset->assetstatus->getStatuslabelType() == 'pending') {
$asset->use_text .= '('.$asset->assetstatus->getStatuslabelType().')';
}
$asset->use_image = ($asset->getImageUrl()) ? $asset->getImageUrl() : null;
}
return (new SelectlistTransformer)->transformSelectlist($assets);
}
@@ -480,7 +500,6 @@ class AssetsController extends Controller
*/
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Asset::class);
$asset = new Asset();
@@ -535,13 +554,12 @@ class AssetsController extends Controller
// if the field is set to encrypted, make sure we encrypt the value
if ($field->field_encrypted == '1') {
\Log::debug('This model field is encrypted in this fieldset.');
if (Gate::allows('admin')) {
// If input value is null, use custom field's default value
if (($field_val == null) && ($request->has('model_id')!='')){
if (($field_val == null) && ($request->has('model_id') != '')) {
$field_val = \Crypt::encrypt($field->defaultValue($request->get('model_id')));
} else {
$field_val = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
@@ -551,12 +569,10 @@ class AssetsController extends Controller
$asset->{$field->convertUnicodeDbSlug()} = $field_val;
}
}
if ($asset->save()) {
if ($request->get('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif ($request->get('assigned_asset')) {
@@ -618,7 +634,7 @@ class AssetsController extends Controller
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
foreach ($model->fieldset->fields as $field) {
if ($request->has($field->convertUnicodeDbSlug())) {
if ($field->field_encrypted=='1') {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
@@ -631,15 +647,13 @@ class AssetsController extends Controller
if ($asset->save()) {
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
$location = $target->location_id;
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) {
$location = $target->location_id;
Asset::where('assigned_type', '\\App\\Models\\Asset')->where('assigned_to', $id)
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $id)
->update(['location_id' => $target->location_id]);
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
$location = $target->id;
}
@@ -654,8 +668,10 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
@@ -673,12 +689,11 @@ class AssetsController extends Controller
$this->authorize('delete', Asset::class);
if ($asset = Asset::find($id)) {
$this->authorize('delete', $asset);
DB::table('assets')
->where('id', $asset->id)
->update(array('assigned_to' => null));
->update(['assigned_to' => null]);
$asset->delete();
@@ -715,7 +730,6 @@ class AssetsController extends Controller
$logaction->logaction('restored');
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.restore.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
@@ -736,7 +750,7 @@ class AssetsController extends Controller
$this->authorize('checkout', Asset::class);
$asset = Asset::findOrFail($asset_id);
if (!$asset->availableForCheckout()) {
if (! $asset->availableForCheckout()) {
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.not_available')));
}
@@ -750,21 +764,21 @@ class AssetsController extends Controller
// This item is checked out to a location
if (request('checkout_to_type')=='location') {
if (request('checkout_to_type') == 'location') {
$target = Location::find(request('assigned_location'));
$asset->location_id = ($target) ? $target->id : '';
$error_payload['target_id'] = $request->input('assigned_location');
$error_payload['target_type'] = 'location';
} elseif (request('checkout_to_type')=='asset') {
$target = Asset::where('id','!=',$asset_id)->find(request('assigned_asset'));
} elseif (request('checkout_to_type') == 'asset') {
$target = Asset::where('id', '!=', $asset_id)->find(request('assigned_asset'));
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
$error_payload['target_id'] = $request->input('assigned_asset');
$error_payload['target_type'] = 'asset';
} elseif (request('checkout_to_type')=='user') {
} elseif (request('checkout_to_type') == 'user') {
// Fetch the target and set the asset's new location_id
$target = User::find(request('assigned_user'));
$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
@@ -774,13 +788,13 @@ class AssetsController extends Controller
if (!isset($target)) {
if (! isset($target)) {
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset '.e($asset->asset_tag).' is invalid - '.$error_payload['target_type'].' does not exist.'));
}
$checkout_at = request('checkout_at', date("Y-m-d H:i:s"));
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
$expected_checkin = request('expected_checkin', null);
$note = request('note', null);
$asset_name = request('name', null);
@@ -819,8 +833,8 @@ class AssetsController extends Controller
$this->authorize('checkin', $asset);
$user = $asset->assignedUser;
if (is_null($target = $asset->assignedTo)) {
$target = $asset->assignedTo;
if (is_null($target)) {
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.already_checked_in')));
}
@@ -833,24 +847,50 @@ class AssetsController extends Controller
if ($request->filled('name')) {
$asset->name = $request->input('name');
}
$asset->location_id = $asset->rtd_location_id;
$asset->location_id = $asset->rtd_location_id;
if ($request->filled('location_id')) {
$asset->location_id = $request->input('location_id');
$asset->location_id = $request->input('location_id');
}
if ($request->has('status_id')) {
$asset->status_id = $request->input('status_id');
$asset->status_id = $request->input('status_id');
}
$checkin_at = null;
if ($request->filled('checkin_at')) {
$checkin_at = $request->input('checkin_at');
}
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note')));
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at));
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success')));
}
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.error')));
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.error')));
}
/**
* Checkin an asset by asset tag
*
* @author [A. Janes] [<ajanes@adagiohealth.org>]
* @since [v6.0]
* @return JsonResponse
*/
public function checkinByTag(Request $request)
{
$this->authorize('checkin', Asset::class);
$asset = Asset::where('asset_tag', $request->input('asset_tag'))->first();
if($asset) {
return $this->checkin($request, $asset->id);
}
return response()->json(Helper::formatStandardApiResponse('error', [
'asset'=> e($request->input('asset_tag'))
], 'Asset with tag '.e($request->input('asset_tag')).' not found'));
}
@@ -862,15 +902,15 @@ class AssetsController extends Controller
* @since [v4.0]
* @return JsonResponse
*/
public function audit(Request $request) {
public function audit(Request $request)
{
$this->authorize('audit', Asset::class);
$rules = array(
$rules = [
'asset_tag' => 'required',
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable'
);
'next_audit_date' => 'date|nullable',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
@@ -880,7 +920,7 @@ class AssetsController extends Controller
$settings = Setting::getSettings();
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
$asset = Asset::where('asset_tag','=', $request->input('asset_tag'))->first();
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
if ($asset) {
@@ -894,28 +934,24 @@ class AssetsController extends Controller
// Check to see if they checked the box to update the physical location,
// not just note it in the audit notes
if ($request->input('update_location')=='1') {
if ($request->input('update_location') == '1') {
$asset->location_id = $request->input('location_id');
}
$asset->last_audit_date = date('Y-m-d H:i:s');
if ($asset->save()) {
$log = $asset->logAudit(request('note'),request('location_id'));
$log = $asset->logAudit(request('note'), request('location_id'));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag'=> e($asset->asset_tag),
'note'=> e($request->input('note')),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date)
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
], trans('admin/hardware/message.audit.success')));
}
}
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.e($request->input('asset_tag')).' not found'));
}
@@ -931,14 +967,16 @@ class AssetsController extends Controller
{
$this->authorize('viewRequestable', Asset::class);
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
$assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets')
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier')->where('assets.requestable', '=', '1');
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier')->requestableAssets();
$offset = request('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$assets->TextSearch($request->input('search'));
if ($request->filled('search')) {
$assets->TextSearch($request->input('search'));
}
switch ($request->input('sort')) {
case 'model':
@@ -958,9 +996,9 @@ class AssetsController extends Controller
break;
}
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
return (new AssetsTransformer)->transformRequestedAssets($assets, $total);
}
}

View File

@@ -23,10 +23,10 @@ class CategoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Category::class);
$allowed_columns = ['id', 'name','category_type', 'category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email', 'assets_count', 'accessories_count', 'consumables_count', 'components_count','licenses_count', 'image'];
$allowed_columns = ['id', 'name', 'category_type', 'category_type', 'use_default_eula', 'eula_text', 'require_acceptance', 'checkin_email', 'assets_count', 'accessories_count', 'consumables_count', 'components_count', 'licenses_count', 'image'];
$categories = Category::select(['id', 'created_at', 'updated_at', 'name','category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email','image'])
->withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count','licenses as licenses_count');
$categories = Category::select(['id', 'created_at', 'updated_at', 'name', 'category_type', 'use_default_eula', 'eula_text', 'require_acceptance', 'checkin_email', 'image'])
->withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
if ($request->filled('search')) {
$categories = $categories->TextSearch($request->input('search'));
@@ -45,6 +45,7 @@ class CategoriesController extends Controller
$total = $categories->count();
$categories = $categories->skip($offset)->take($limit)->get();
return (new CategoriesTransformer)->transformCategories($categories, $total);
}
@@ -127,14 +128,14 @@ class CategoriesController extends Controller
$this->authorize('delete', Category::class);
$category = Category::findOrFail($id);
if (!$category->isDeletable()) {
if (! $category->isDeletable()) {
return response()->json(
Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>$category->category_type]))
Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>$category->category_type]))
);
}
$category->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success')));
}
@@ -144,11 +145,10 @@ class CategoriesController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request, $category_type = 'asset')
{
$this->authorize('view.selectlists');
$categories = Category::select([
'id',
'name',
@@ -169,7 +169,5 @@ class CategoriesController extends Controller
}
return (new SelectlistTransformer)->transformSelectlist($categories);
}
}

View File

@@ -37,7 +37,7 @@ class CompaniesController extends Controller
'components_count',
];
$companies = Company::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');
$companies = Company::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');
if ($request->filled('search')) {
$companies->TextSearch($request->input('search'));
@@ -79,9 +79,9 @@ class CompaniesController extends Controller
if ($company->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new CompaniesTransformer)->transformCompany($company), trans('admin/companies/message.create.success')));
}
return response()
->json(Helper::formatStandardApiResponse('error', null, $company->getErrors()));
}
/**
@@ -140,13 +140,14 @@ class CompaniesController extends Controller
$company = Company::findOrFail($id);
$this->authorize('delete', $company);
if ( !$company->isDeletable() ) {
if (! $company->isDeletable()) {
return response()
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
}
$company->delete();
return response()
->json(Helper::formatStandardApiResponse('success', null, trans('admin/companies/message.delete.success')));
->json(Helper::formatStandardApiResponse('success', null, trans('admin/companies/message.delete.success')));
}
/**
@@ -155,11 +156,10 @@ class CompaniesController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$companies = Company::select([
'companies.id',
'companies.name',

View File

@@ -40,6 +40,7 @@ class ComponentsController extends Controller
'purchase_cost',
'qty',
'image',
'notes',
];
@@ -51,15 +52,19 @@ class ComponentsController extends Controller
}
if ($request->filled('company_id')) {
$components->where('company_id','=',$request->input('company_id'));
$components->where('company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {
$components->where('category_id','=',$request->input('category_id'));
$components->where('category_id', '=', $request->input('category_id'));
}
if ($request->filled('location_id')) {
$components->where('location_id','=',$request->input('location_id'));
$components->where('location_id', '=', $request->input('location_id'));
}
if ($request->filled('notes')) {
$components->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
@@ -91,6 +96,7 @@ class ComponentsController extends Controller
$total = $components->count();
$components = $components->skip($offset)->take($limit)->get();
return (new ComponentsTransformer)->transformComponents($components, $total);
}
@@ -113,6 +119,7 @@ class ComponentsController extends Controller
if ($component->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $component, trans('admin/components/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $component->getErrors()));
}
@@ -133,7 +140,6 @@ class ComponentsController extends Controller
}
}
/**
* Update the specified resource in storage.
*
@@ -172,6 +178,7 @@ class ComponentsController extends Controller
$component = Component::findOrFail($id);
$this->authorize('delete', $component);
$component->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.delete.success')));
}
@@ -195,6 +202,7 @@ class ComponentsController extends Controller
$limit = $request->input('limit', 50);
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
return (new ComponentsTransformer)->transformCheckedoutComponents($assets, $total);
}

View File

@@ -42,6 +42,7 @@ class ConsumablesController extends Controller
'item_no',
'qty',
'image',
'notes',
];
@@ -55,11 +56,11 @@ class ConsumablesController extends Controller
}
if ($request->filled('company_id')) {
$consumables->where('company_id','=',$request->input('company_id'));
$consumables->where('company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {
$consumables->where('category_id','=',$request->input('category_id'));
$consumables->where('category_id', '=', $request->input('category_id'));
}
if ($request->filled('model_number')) {
@@ -67,13 +68,17 @@ class ConsumablesController extends Controller
}
if ($request->filled('manufacturer_id')) {
$consumables->where('manufacturer_id','=',$request->input('manufacturer_id'));
$consumables->where('manufacturer_id', '=', $request->input('manufacturer_id'));
}
if ($request->filled('location_id')) {
$consumables->where('location_id','=',$request->input('location_id'));
}
if ($request->filled('notes')) {
$consumables->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
@@ -82,7 +87,7 @@ class ConsumablesController extends Controller
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$allowed_columns = ['id', 'name', 'order_number', 'min_amt', 'purchase_date', 'purchase_cost', 'company', 'category', 'model_number', 'item_no', 'manufacturer', 'location', 'qty', 'image'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort_override = $request->input('sort');
@@ -107,15 +112,12 @@ class ConsumablesController extends Controller
break;
}
$total = $consumables->count();
$consumables = $consumables->skip($offset)->take($limit)->get();
return (new ConsumablesTransformer)->transformConsumables($consumables, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -134,6 +136,7 @@ class ConsumablesController extends Controller
if ($consumable->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $consumable, trans('admin/consumables/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $consumable->getErrors()));
}
@@ -148,10 +151,10 @@ class ConsumablesController extends Controller
{
$this->authorize('view', Consumable::class);
$consumable = Consumable::findOrFail($id);
return (new ConsumablesTransformer)->transformConsumable($consumable);
}
/**
* Update the specified resource in storage.
*
@@ -189,7 +192,8 @@ class ConsumablesController extends Controller
$consumable = Consumable::findOrFail($id);
$this->authorize('delete', $consumable);
$consumable->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success')));
}
/**
@@ -203,21 +207,20 @@ class ConsumablesController extends Controller
*/
public function getDataView($consumableId)
{
$consumable = Consumable::with(array('consumableAssignments'=>
function ($query) {
$consumable = Consumable::with(['consumableAssignments'=> function ($query) {
$query->orderBy($query->getModel()->getTable().'.created_at', 'DESC');
},
'consumableAssignments.admin'=> function ($query) {
},
'consumableAssignments.user'=> function ($query) {
},
))->find($consumableId);
])->find($consumableId);
if (!Company::isCurrentUserHasAccess($consumable)) {
if (! Company::isCurrentUserHasAccess($consumable)) {
return ['total' => 0, 'rows' => []];
}
$this->authorize('view', Consumable::class);
$rows = array();
$rows = [];
foreach ($consumable->consumableAssignments as $consumable_assignment) {
$rows[] = [
@@ -228,7 +231,8 @@ class ConsumablesController extends Controller
}
$consumableCount = $consumable->users->count();
$data = array('total' => $consumableCount, 'rows' => $rows);
$data = ['total' => $consumableCount, 'rows' => $rows];
return $data;
}
@@ -264,7 +268,7 @@ class ConsumablesController extends Controller
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'user_id' => $user->id,
'assigned_to' => $assigned_to
'assigned_to' => $assigned_to,
]);
// Log checkout event
@@ -277,7 +281,7 @@ class ConsumablesController extends Controller
$data['note'] = $logaction->note;
$data['require_acceptance'] = $consumable->requireAcceptance();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'No consumables remaining'));
@@ -287,14 +291,12 @@ class ConsumablesController extends Controller
* Gets a paginated collection for the select2 menus
*
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$consumables = Consumable::select([
'consumables.id',
'consumables.name'
'consumables.name',
]);
if ($request->filled('search')) {
@@ -303,7 +305,6 @@ class ConsumablesController extends Controller
$consumables = $consumables->orderBy('name', 'ASC')->paginate(50);
return (new SelectlistTransformer)->transformSelectlist($consumables);
}
}

View File

@@ -18,26 +18,26 @@ class CustomFieldsController extends Controller
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v3.0]
* @return Array
* @return array
*/
public function index()
{
$this->authorize('index', CustomField::class);
$fields = CustomField::get();
return (new CustomFieldsTransformer)->transformCustomFields($fields, $fields->count());
}
/**
* Shows the given field
* @author [V. Cordes] [<volker@fdatek.de>]
* @param int $id
* @since [v4.1.10]
* @return View
*/
* Shows the given field
* @author [V. Cordes] [<volker@fdatek.de>]
* @param int $id
* @since [v4.1.10]
* @return View
*/
public function show($id)
{
$this->authorize('view', CustomField::class);
$this->authorize('view', CustomField::class);
if ($field = CustomField::find($id)) {
return (new CustomFieldsTransformer)->transformCustomField($field);
}
@@ -45,7 +45,7 @@ class CustomFieldsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/custom_fields/message.field.invalid')), 200);
}
/**
/**
* Update the specified field
*
* @author [V. Cordes] [<volker@fdatek.de>]
@@ -80,7 +80,6 @@ class CustomFieldsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, $field->getErrors()));
}
/**
* Store a newly created field.
*
@@ -96,9 +95,9 @@ class CustomFieldsController extends Controller
$data = $request->all();
$regex_format = null;
if (str_contains($data["format"], "regex:")){
$regex_format = $data["format"];
if (str_contains($data['format'], 'regex:')) {
$regex_format = $data['format'];
}
$validator = Validator::make($data, $field->validationRules($regex_format));
@@ -111,8 +110,8 @@ class CustomFieldsController extends Controller
if ($field->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $field, trans('admin/custom_fields/message.field.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $field->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $field->getErrors()));
}
public function postReorder(Request $request, $id)
@@ -121,8 +120,8 @@ class CustomFieldsController extends Controller
$this->authorize('update', $fieldset);
$fields = array();
$order_array = array();
$fields = [];
$order_array = [];
$items = $request->input('item');
@@ -135,7 +134,6 @@ class CustomFieldsController extends Controller
}
return $fieldset->fields()->sync($fields);
}
public function associate(Request $request, $field_id)
@@ -152,7 +150,8 @@ class CustomFieldsController extends Controller
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fieldset->fields()->attach($field->id, ["required" => ($request->input('required') == "on"), "order" => $request->input('order', $fieldset->fields->count())]);
$fieldset->fields()->attach($field->id, ['required' => ($request->input('required') == 'on'), 'order' => $request->input('order', $fieldset->fields->count())]);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
@@ -166,10 +165,12 @@ class CustomFieldsController extends Controller
foreach ($field->fieldset as $fieldset) {
if ($fieldset->id == $fieldset_id) {
$fieldset->fields()->detach($field->id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
@@ -186,13 +187,12 @@ class CustomFieldsController extends Controller
$this->authorize('delete', $field);
if ($field->fieldset->count() >0) {
if ($field->fieldset->count() > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Field is in use.'));
}
$field->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.field.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.field.delete.success')));
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
@@ -20,47 +21,43 @@ use View;
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @author [Josh Gibson]
*/
class CustomFieldsetsController extends Controller
{
/**
* Shows the given fieldset and its fields
* @author [A. Gianotto] [<snipe@snipe.net>]
* @author [Josh Gibson]
* @param int $id
* @since [v1.8]
* @return View
*/
* Shows the given fieldset and its fields
* @author [A. Gianotto] [<snipe@snipe.net>]
* @author [Josh Gibson]
* @param int $id
* @since [v1.8]
* @return View
*/
public function index()
{
$this->authorize('index', CustomFieldset::class);
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
}
/**
* Shows the given fieldset and its fields
* @author [A. Gianotto] [<snipe@snipe.net>]
* @author [Josh Gibson]
* @param int $id
* @since [v1.8]
* @return View
*/
* Shows the given fieldset and its fields
* @author [A. Gianotto] [<snipe@snipe.net>]
* @author [Josh Gibson]
* @param int $id
* @since [v1.8]
* @return View
*/
public function show($id)
{
$this->authorize('view', CustomFieldset::class);
$this->authorize('view', CustomFieldset::class);
if ($fieldset = CustomFieldset::find($id)) {
return (new CustomFieldsetsTransformer)->transformCustomFieldset($fieldset);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/custom_fields/message.fieldset.does_not_exist')), 200);
}
/**
/**
* Update the specified resource in storage.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
@@ -82,7 +79,6 @@ class CustomFieldsetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, $fieldset->getErrors()));
}
/**
* Store a newly created resource in storage.
*
@@ -100,11 +96,10 @@ class CustomFieldsetsController extends Controller
if ($fieldset->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $fieldset->getErrors()));
}
/**
* Delete a custom fieldset.
*
@@ -120,18 +115,15 @@ class CustomFieldsetsController extends Controller
$modelsCount = $fieldset->models->count();
$fieldsCount = $fieldset->fields->count();
if (($modelsCount > 0) || ($fieldsCount > 0) ){
if (($modelsCount > 0) || ($fieldsCount > 0)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Fieldset is in use.'));
}
if ($fieldset->delete()) {
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.fieldset.delete.success')));
}
if ($fieldset->delete()) {
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.fieldset.delete.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Unspecified error'));
}
/**
@@ -147,6 +139,7 @@ class CustomFieldsetsController extends Controller
$this->authorize('view', CustomFieldset::class);
$set = CustomFieldset::findOrFail($id);
$fields = $set->fields;
return (new CustomFieldsTransformer)->transformCustomFields($fields, $fields->count());
}

View File

@@ -6,6 +6,7 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\DepartmentsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Company;
use App\Models\Department;
use Auth;
use Illuminate\Http\Request;
@@ -24,9 +25,9 @@ class DepartmentsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Department::class);
$allowed_columns = ['id','name','image','users_count'];
$allowed_columns = ['id', 'name', 'image', 'users_count'];
$departments = Department::select([
$departments = Company::scopeCompanyables(Department::select(
'departments.id',
'departments.name',
'departments.location_id',
@@ -34,8 +35,8 @@ class DepartmentsController extends Controller
'departments.manager_id',
'departments.created_at',
'departments.updated_at',
'departments.image'
])->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
'departments.image'),
"company_id", "departments")->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
if ($request->filled('search')) {
$departments = $departments->TextSearch($request->input('search'));
@@ -85,7 +86,7 @@ class DepartmentsController extends Controller
$department = $request->handleImages($department);
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
if ($department->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.create.success')));
@@ -106,6 +107,7 @@ class DepartmentsController extends Controller
{
$this->authorize('view', Department::class);
$department = Department::findOrFail($id);
return (new DepartmentsTransformer)->transformDepartment($department);
}
@@ -133,7 +135,6 @@ class DepartmentsController extends Controller
}
/**
* Validates and deletes selected department.
*
@@ -163,11 +164,11 @@ class DepartmentsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$departments = Department::select([
'id',
'name',
@@ -188,7 +189,5 @@ class DepartmentsController extends Controller
}
return (new SelectlistTransformer)->transformSelectlist($departments);
}
}

View File

@@ -41,10 +41,10 @@ class DepreciationsController extends Controller
$total = $depreciations->count();
$depreciations = $depreciations->skip($offset)->take($limit)->get();
return (new DepreciationsTransformer)->transformDepreciations($depreciations, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -62,8 +62,8 @@ class DepreciationsController extends Controller
if ($depreciation->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $depreciation, trans('admin/depreciations/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $depreciation->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $depreciation->getErrors()));
}
/**
@@ -78,10 +78,10 @@ class DepreciationsController extends Controller
{
$this->authorize('view', Depreciation::class);
$depreciation = Depreciation::findOrFail($id);
return (new DepreciationsTransformer)->transformDepreciation($depreciation);
}
/**
* Update the specified resource in storage.
*
@@ -123,10 +123,7 @@ class DepreciationsController extends Controller
}
$depreciation->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/depreciations/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/depreciations/message.delete.success')));
}
}

View File

@@ -20,9 +20,9 @@ class GroupsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Group::class);
$allowed_columns = ['id','name','created_at', 'users_count'];
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
$groups = Group::select('id','name','permissions','created_at','updated_at')->withCount('users as users_count');
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at')->withCount('users as users_count');
if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search'));
@@ -41,10 +41,10 @@ class GroupsController extends Controller
$total = $groups->count();
$groups = $groups->skip($offset)->take($limit)->get();
return (new GroupsTransformer)->transformGroups($groups, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -62,8 +62,8 @@ class GroupsController extends Controller
if ($group->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
}
/**
@@ -78,10 +78,10 @@ class GroupsController extends Controller
{
$this->authorize('view', Group::class);
$group = Group::findOrFail($id);
return (new GroupsTransformer)->transformGroup($group);
}
/**
* Update the specified resource in storage.
*
@@ -118,9 +118,7 @@ class GroupsController extends Controller
$group = Group::findOrFail($id);
$this->authorize('delete', $group);
$group->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/groups/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/groups/message.delete.success')));
}
}

View File

@@ -27,8 +27,8 @@ class ImportController extends Controller
{
$this->authorize('import');
$imports = Import::latest()->get();
return (new ImportsTransformer)->transformImports($imports);
return (new ImportsTransformer)->transformImports($imports);
}
/**
@@ -40,27 +40,28 @@ class ImportController extends Controller
public function store()
{
$this->authorize('import');
if (!config('app.lock_passwords')) {
if (! config('app.lock_passwords')) {
$files = Request::file('files');
$path = config('app.private_uploads').'/imports';
$results = [];
$import = new Import;
foreach ($files as $file) {
if (!in_array($file->getMimeType(), array(
if (! in_array($file->getMimeType(), [
'application/vnd.ms-excel',
'text/csv',
'application/csv',
'text/x-Algol68', // because wtf CSV files?
'text/plain',
'text/comma-separated-values',
'text/tsv'))) {
$results['error']='File type must be CSV. Uploaded file is '.$file->getMimeType();
'text/tsv', ])) {
$results['error'] = 'File type must be CSV. Uploaded file is '.$file->getMimeType();
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
}
//TODO: is there a lighter way to do this?
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
if (! ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$import->header_row = $reader->fetchOne(0);
@@ -68,20 +69,20 @@ class ImportController extends Controller
//duplicate headers check
$duplicate_headers = [];
for($i = 0; $i<count($import->header_row); $i++) {
for ($i = 0; $i < count($import->header_row); $i++) {
$header = $import->header_row[$i];
if(in_array($header, $import->header_row)) {
if (in_array($header, $import->header_row)) {
$found_at = array_search($header, $import->header_row);
if($i > $found_at) {
if ($i > $found_at) {
//avoid reporting duplicates twice, e.g. "1 is same as 17! 17 is same as 1!!!"
//as well as "1 is same as 1!!!" (which is always true)
//has to be > because otherwise the first result of array_search will always be $i itself(!)
array_push($duplicate_headers,"Duplicate header '$header' detected, first at column: ".($found_at+1).", repeats at column: ".($i+1));
array_push($duplicate_headers, "Duplicate header '$header' detected, first at column: ".($found_at + 1).', repeats at column: '.($i + 1));
}
}
}
if(count($duplicate_headers) > 0) {
return response()->json(Helper::formatStandardApiResponse('error',null, implode("; ",$duplicate_headers)), 500); //should this be '4xx'?
if (count($duplicate_headers) > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)), 500); //should this be '4xx'?
}
// Grab the first row to display via ajax as the user picks fields
@@ -92,10 +93,11 @@ class ImportController extends Controller
try {
$file->move($path, $date.'-'.$fixed_filename);
} catch (FileException $exception) {
$results['error']=trans('admin/hardware/message.upload.error');
$results['error'] = trans('admin/hardware/message.upload.error');
if (config('app.debug')) {
$results['error'].= ' ' . $exception->getMessage();
$results['error'] .= ' '.$exception->getMessage();
}
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
}
$file_name = date('Y-m-d-his').'-'.$fixed_filename;
@@ -105,12 +107,15 @@ class ImportController extends Controller
$results[] = $import;
}
$results = (new ImportsTransformer)->transformImports($results);
return [
'files' => $results,
];
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 500);
}
/**
* Processes the specified Import.
*
@@ -130,25 +135,25 @@ class ImportController extends Controller
}
$errors = $request->import(Import::find($import_id));
$redirectTo = "hardware.index";
$redirectTo = 'hardware.index';
switch ($request->get('import-type')) {
case "asset":
$redirectTo = "hardware.index";
case 'asset':
$redirectTo = 'hardware.index';
break;
case "accessory":
$redirectTo = "accessories.index";
case 'accessory':
$redirectTo = 'accessories.index';
break;
case "consumable":
$redirectTo = "consumables.index";
case 'consumable':
$redirectTo = 'consumables.index';
break;
case "component":
$redirectTo = "components.index";
case 'component':
$redirectTo = 'components.index';
break;
case "license":
$redirectTo = "licenses.index";
case 'license':
$redirectTo = 'licenses.index';
break;
case "user":
$redirectTo = "users.index";
case 'user':
$redirectTo = 'users.index';
break;
}
@@ -157,8 +162,8 @@ class ImportController extends Controller
}
//Flash message before the redirect
Session::flash('success', trans('admin/hardware/message.import.success'));
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
}
/**
@@ -170,20 +175,20 @@ class ImportController extends Controller
public function destroy($import_id)
{
$this->authorize('create', Asset::class);
if ($import = Import::find($import_id)) {
try {
// Try to delete the file
Storage::delete('imports/'.$import->file_path);
$import->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success')));
} catch (\Exception $e) {
// If the file delete didn't work, remove it from the database anyway and return a warning
$import->delete();
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
}
}
}
}

View File

@@ -32,7 +32,7 @@ class LicenseSeatsController extends Controller
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
if ($request->input('sort')=='department') {
if ($request->input('sort') == 'department') {
$seats->OrderDepartments($order);
} else {
$seats->orderBy('id', $order);
@@ -41,7 +41,7 @@ class LicenseSeatsController extends Controller
$total = $seats->count();
$offset = (($seats) && (request('offset') > $total)) ? 0 : request('offset', 0);
$limit = request('limit', 50);
$seats = $seats->skip($offset)->take($limit)->get();
if ($seats) {
@@ -65,13 +65,14 @@ class LicenseSeatsController extends Controller
$this->authorize('view', License::class);
// sanity checks:
// 1. does the license seat exist?
if (!$licenseSeat = LicenseSeat::find($seatId)) {
if (! $licenseSeat = LicenseSeat::find($seatId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat not found'));
}
// 2. does the seat belong to the specified license?
if (!$license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
if (! $license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat does not belong to the specified license'));
}
return (new LicenseSeatsTransformer)->transformLicenseSeat($licenseSeat);
}
@@ -89,11 +90,11 @@ class LicenseSeatsController extends Controller
// sanity checks:
// 1. does the license seat exist?
if (!$licenseSeat = LicenseSeat::find($seatId)) {
if (! $licenseSeat = LicenseSeat::find($seatId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat not found'));
}
// 2. does the seat belong to the specified license?
if (!$license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
if (! $license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat does not belong to the specified license'));
}
@@ -103,14 +104,14 @@ class LicenseSeatsController extends Controller
// attempt to update the license seat
$licenseSeat->fill($request->all());
$licenseSeat->user_id = Auth::user()->id;
// check if this update is a checkin operation
// 1. are relevant fields touched at all?
$touched = $licenseSeat->isDirty('assigned_to') || $licenseSeat->isDirty('asset_id');
// 2. are they cleared? if yes then this is a checkin operation
$is_checkin = ($touched && $licenseSeat->assigned_to === null && $licenseSeat->asset_id === null);
if (!$touched) {
if (! $touched) {
// nothing to update
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
@@ -128,11 +129,13 @@ class LicenseSeatsController extends Controller
if ($is_checkin) {
$licenseSeat->logCheckin($target, $request->input('note'));
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
// in this case, relevant fields are touched but it's not a checkin operation. so it must be a checkout operation.
$licenseSeat->logCheckout($request->input('note'), $target);
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}

View File

@@ -26,62 +26,75 @@ class LicensesController extends Controller
public function index(Request $request)
{
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'freeSeats', 'supplier','category')->withCount('freeSeats as free_seats_count'));
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier', 'category')->withCount('freeSeats as free_seats_count'));
if ($request->filled('company_id')) {
$licenses->where('company_id','=',$request->input('company_id'));
$licenses->where('company_id', '=', $request->input('company_id'));
}
if ($request->filled('name')) {
$licenses->where('licenses.name','=',$request->input('name'));
$licenses->where('licenses.name', '=', $request->input('name'));
}
if ($request->filled('product_key')) {
$licenses->where('licenses.serial','=',$request->input('product_key'));
$licenses->where('licenses.serial', '=', $request->input('product_key'));
}
if ($request->filled('order_number')) {
$licenses->where('order_number','=',$request->input('order_number'));
$licenses->where('order_number', '=', $request->input('order_number'));
}
if ($request->filled('purchase_order')) {
$licenses->where('purchase_order','=',$request->input('purchase_order'));
$licenses->where('purchase_order', '=', $request->input('purchase_order'));
}
if ($request->filled('license_name')) {
$licenses->where('license_name','=',$request->input('license_name'));
$licenses->where('license_name', '=', $request->input('license_name'));
}
if ($request->filled('license_email')) {
$licenses->where('license_email','=',$request->input('license_email'));
$licenses->where('license_email', '=', $request->input('license_email'));
}
if ($request->filled('manufacturer_id')) {
$licenses->where('manufacturer_id','=',$request->input('manufacturer_id'));
$licenses->where('manufacturer_id', '=', $request->input('manufacturer_id'));
}
if ($request->filled('supplier_id')) {
$licenses->where('supplier_id','=',$request->input('supplier_id'));
$licenses->where('supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('category_id')) {
$licenses->where('category_id','=',$request->input('category_id'));
$licenses->where('category_id', '=', $request->input('category_id'));
}
if ($request->filled('depreciation_id')) {
$licenses->where('depreciation_id','=',$request->input('depreciation_id'));
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
}
if ($request->filled('supplier_id')) {
$licenses->where('supplier_id','=',$request->input('supplier_id'));
$licenses->where('supplier_id', '=', $request->input('supplier_id'));
}
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
$licenses->where('maintained','=',1);
} elseif (($request->filled('maintained')) && ($request->input('maintained')=='false')) {
$licenses->where('maintained','=',0);
}
if (($request->filled('expires')) && ($request->input('expires')=='true')) {
$licenses->whereNotNull('expiration_date');
} elseif (($request->filled('expires')) && ($request->input('expires')=='false')) {
$licenses->whereNull('expiration_date');
}
if ($request->filled('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
if ($request->input('deleted')=='true') {
$licenses->onlyTrashed();
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
@@ -92,7 +105,6 @@ class LicensesController extends Controller
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
switch ($request->input('sort')) {
case 'manufacturer':
$licenses = $licenses->leftJoin('manufacturers', 'licenses.manufacturer_id', '=', 'manufacturers.id')->orderBy('manufacturers.name', $order);
@@ -128,25 +140,19 @@ class LicensesController extends Controller
'free_seats_count',
'seats',
'termination_date',
'depreciation_id'
'depreciation_id',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$licenses = $licenses->orderBy($sort, $order);
break;
}
$total = $licenses->count();
$licenses = $licenses->skip($offset)->take($limit)->get();
return (new LicensesTransformer)->transformLicenses($licenses, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -162,9 +168,10 @@ class LicensesController extends Controller
$license = new License;
$license->fill($request->all());
if($license->save()) {
if ($license->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $license, trans('admin/licenses/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $license->getErrors()));
}
@@ -180,10 +187,10 @@ class LicensesController extends Controller
$this->authorize('view', License::class);
$license = License::withCount('freeSeats')->findOrFail($id);
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
return (new LicensesTransformer)->transformLicense($license);
}
/**
* Update the specified resource in storage.
*
@@ -222,22 +229,23 @@ class LicensesController extends Controller
$license = License::findOrFail($id);
$this->authorize('delete', $license);
if($license->assigned_seats_count == 0) {
if ($license->assigned_seats_count == 0) {
// Delete the license and the associated license seats
DB::table('license_seats')
->where('id', $license->id)
->update(array('assigned_to' => null,'asset_id' => null));
->update(['assigned_to' => null, 'asset_id' => null]);
$licenseSeats = $license->licenseseats();
$licenseSeats->delete();
$license->delete();
// Redirect to the licenses management page
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/licenses/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/licenses/message.delete.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.assoc_users')));
}
/**
* Gets a paginated collection for the select2 menus
*
@@ -245,10 +253,9 @@ class LicensesController extends Controller
*/
public function selectlist(Request $request)
{
$licenses = License::select([
'licenses.id',
'licenses.name'
'licenses.name',
]);
if ($request->filled('search')) {
@@ -257,9 +264,6 @@ class LicensesController extends Controller
$licenses = $licenses->orderBy('name', 'ASC')->paginate(50);
return (new SelectlistTransformer)->transformSelectlist($licenses);
}
}

View File

@@ -2,13 +2,13 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Location;
use App\Http\Transformers\LocationsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Location;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -25,9 +25,9 @@ class LocationsController extends Controller
{
$this->authorize('view', Location::class);
$allowed_columns = [
'id','name','address','address2','city','state','country','zip','created_at',
'updated_at','manager_id','image',
'assigned_assets_count','users_count','assets_count','currency','ldap_ou'];
'id', 'name', 'address', 'address2', 'city', 'state', 'country', 'zip', 'created_at',
'updated_at', 'manager_id', 'image',
'assigned_assets_count', 'users_count', 'assets_count', 'currency', 'ldap_ou', ];
$locations = Location::with('parent', 'manager', 'children')->select([
'locations.id',
@@ -44,7 +44,7 @@ class LocationsController extends Controller
'locations.updated_at',
'locations.image',
'locations.ldap_ou',
'locations.currency'
'locations.currency',
])->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('users as users_count');
@@ -53,8 +53,6 @@ class LocationsController extends Controller
$locations = $locations->TextSearch($request->input('search'));
}
$offset = (($locations) && (request('offset') > $locations->count())) ? $locations->count() : request('offset', 0);
// Check to make sure the limit is not higher than the max allowed
@@ -78,6 +76,7 @@ class LocationsController extends Controller
$total = $locations->count();
$locations = $locations->skip($offset)->take($limit)->get();
return (new LocationsTransformer)->transformLocations($locations, $total);
}
@@ -100,6 +99,7 @@ class LocationsController extends Controller
if ($location->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new LocationsTransformer)->transformLocation($location), trans('admin/locations/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
}
@@ -129,11 +129,12 @@ class LocationsController extends Controller
'locations.created_at',
'locations.updated_at',
'locations.image',
'locations.currency'
'locations.currency',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('users as users_count')->findOrFail($id);
return (new LocationsTransformer)->transformLocation($location);
}
@@ -182,12 +183,13 @@ class LocationsController extends Controller
{
$this->authorize('delete', Location::class);
$location = Location::findOrFail($id);
if(!$location->isDeletable()) {
if (! $location->isDeletable()) {
return response()
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
}
$this->authorize('delete', $location);
$location->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success')));
}
@@ -218,11 +220,12 @@ class LocationsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$locations = Location::select([
'locations.id',
'locations.name',
@@ -244,26 +247,22 @@ class LocationsController extends Controller
$locations_with_children = [];
foreach ($locations as $location) {
if (!array_key_exists($location->parent_id, $locations_with_children)) {
if (! array_key_exists($location->parent_id, $locations_with_children)) {
$locations_with_children[$location->parent_id] = [];
}
$locations_with_children[$location->parent_id][] = $location;
}
if ($request->filled('search')) {
$locations_formatted = $locations;
$locations_formatted = $locations;
} else {
$location_options = Location::indenter($locations_with_children);
$locations_formatted = new Collection($location_options);
}
$paginated_results = new LengthAwarePaginator($locations_formatted->forPage($page, 500), $locations_formatted->count(), 500, $page, []);
$paginated_results = new LengthAwarePaginator($locations_formatted->forPage($page, 500), $locations_formatted->count(), 500, $page, []);
//return [];
return (new SelectlistTransformer)->transformSelectlist($paginated_results);
}
}

View File

@@ -23,13 +23,13 @@ class ManufacturersController extends Controller
public function index(Request $request)
{
$this->authorize('view', Manufacturer::class);
$allowed_columns = ['id','name','url','support_url','support_email','support_phone','created_at','updated_at','image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
$manufacturers = Manufacturer::select(
array('id','name','url','support_url','support_email','support_phone','created_at','updated_at','image', 'deleted_at')
['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'deleted_at']
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count');
if ($request->input('deleted')=='true') {
if ($request->input('deleted') == 'true') {
$manufacturers->onlyTrashed();
}
@@ -37,7 +37,6 @@ class ManufacturersController extends Controller
$manufacturers = $manufacturers->TextSearch($request->input('search'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($manufacturers) && ($request->get('offset') > $manufacturers->count())) ? $manufacturers->count() : $request->get('offset', 0);
@@ -51,10 +50,10 @@ class ManufacturersController extends Controller
$total = $manufacturers->count();
$manufacturers = $manufacturers->skip($offset)->take($limit)->get();
return (new ManufacturersTransformer)->transformManufacturers($manufacturers, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -89,10 +88,10 @@ class ManufacturersController extends Controller
{
$this->authorize('view', Manufacturer::class);
$manufacturer = Manufacturer::withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count')->findOrFail($id);
return (new ManufacturersTransformer)->transformManufacturer($manufacturer);
}
/**
* Update the specified resource in storage.
*
@@ -126,7 +125,6 @@ class ManufacturersController extends Controller
*/
public function destroy($id)
{
$this->authorize('delete', Manufacturer::class);
$manufacturer = Manufacturer::findOrFail($id);
$this->authorize('delete', $manufacturer);
@@ -138,10 +136,6 @@ class ManufacturersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.assoc_users')));
}
/**
@@ -150,11 +144,11 @@ class ManufacturersController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$manufacturers = Manufacturer::select([
'id',
'name',
@@ -176,6 +170,5 @@ class ManufacturersController extends Controller
}
return (new SelectlistTransformer)->transformSelectlist($manufacturers);
}
}

View File

@@ -31,17 +31,16 @@ class PredefinedKitsController extends Controller
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets_count';
$order = $request->input('order') === 'desc' ? 'desc' : 'asc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'name';
$kits->orderBy($sort, $order);
$total = $kits->count();
$kits = $kits->skip($offset)->take($limit)->get();
return (new PredefinedKitsTransformer)->transformPredefinedKits($kits, $total);
}
/**
* Store a newly created resource in storage.
*
@@ -57,8 +56,8 @@ class PredefinedKitsController extends Controller
if ($kit->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.create_success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $kit->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $kit->getErrors()));
}
/**
@@ -71,10 +70,10 @@ class PredefinedKitsController extends Controller
{
$this->authorize('view', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($id);
return (new PredefinedKitsTransformer)->transformPredefinedKit($kit);
}
/**
* Update the specified resource in storage.
*
@@ -89,7 +88,7 @@ class PredefinedKitsController extends Controller
$kit->fill($request->all());
if ($kit->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.update_success'))); // TODO: trans
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.update_success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $kit->getErrors()));
@@ -113,23 +112,20 @@ class PredefinedKitsController extends Controller
$kit->accessories()->detach();
$kit->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/kits/general.delete_success'))); // TODO: trans
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/kits/general.delete_success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$kits = PredefinedKit::select([
'id',
'name'
'name',
]);
if ($request->filled('search')) {
@@ -139,7 +135,6 @@ class PredefinedKitsController extends Controller
$kits = $kits->orderBy('name', 'ASC')->paginate(50);
return (new SelectlistTransformer)->transformSelectlist($kits);
}
/**
@@ -148,38 +143,40 @@ class PredefinedKitsController extends Controller
* @param int $id
* @return \Illuminate\Http\Response
*/
public function indexLicenses($kit_id) {
public function indexLicenses($kit_id)
{
$this->authorize('view', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$licenses = $kit->licenses;
return (new PredefinedKitsTransformer)->transformElements($licenses, $licenses->count());
}
/**
* Store the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function storeLicense(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
public function storeLicense(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$license_id = $request->get('license');
$relation = $kit->licenses();
if( $relation->find($license_id) ) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['license' => 'License already attached to kit']));
}
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$relation->attach( $license_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License added successfull')); // TODO: trans
$license_id = $request->get('license');
$relation = $kit->licenses();
if ($relation->find($license_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['license' => trans('admin/kits/general.license_error')]));
}
$relation->attach($license_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.license_added_success')));
}
/**
@@ -189,20 +186,20 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function updateLicense(Request $request, $kit_id, $license_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
$kit->licenses()->syncWithoutDetaching([$license_id => ['quantity' => $quantity]]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License updated')); // TODO: trans
}
public function updateLicense(Request $request, $kit_id, $license_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$kit->licenses()->syncWithoutDetaching([$license_id => ['quantity' => $quantity]]);
/**
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.license_updated')));
}
/**
* Remove the specified resource from storage.
*
* @param int $kit_id
@@ -214,48 +211,49 @@ class PredefinedKitsController extends Controller
$kit = PredefinedKit::findOrFail($kit_id);
$kit->licenses()->detach($license_id);
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.delete_success')));
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.delete_success')));
}
/**
* Display the specified resource.
*
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function indexModels($kit_id) {
public function indexModels($kit_id)
{
$this->authorize('view', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$models = $kit->models;
return (new PredefinedKitsTransformer)->transformElements($models, $models->count());
}
/**
* Store the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function storeModel(Request $request, $kit_id)
{
public function storeModel(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$kit = PredefinedKit::findOrFail($kit_id);
$model_id = $request->get('model');
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
if ($quantity < 1) {
$quantity = 1;
}
$relation = $kit->models();
if( $relation->find($model_id) ) {
if ($relation->find($model_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['model' => 'Model already attached to kit']));
}
$relation->attach($model_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Model added successfull'));
}
@@ -266,20 +264,20 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function updateModel(Request $request, $kit_id, $model_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
$kit->models()->syncWithoutDetaching([$model_id => ['quantity' => $quantity]]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License updated')); // TODO: trans
}
public function updateModel(Request $request, $kit_id, $model_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$kit->models()->syncWithoutDetaching([$model_id => ['quantity' => $quantity]]);
/**
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.license_updated')));
}
/**
* Remove the specified resource from storage.
*
* @param int $kit_id
@@ -291,49 +289,50 @@ class PredefinedKitsController extends Controller
$kit = PredefinedKit::findOrFail($kit_id);
$kit->models()->detach($model_id);
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.model_removed_success')));
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.model_removed_success')));
}
/**
* Display the specified resource.
*
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function indexConsumables($kit_id) {
public function indexConsumables($kit_id)
{
$this->authorize('view', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$consumables = $kit->consumables;
return (new PredefinedKitsTransformer)->transformElements($consumables, $consumables->count());
}
/**
* Store the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function storeConsumable(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
public function storeConsumable(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$consumable_id = $request->get('consumable');
$relation = $kit->consumables();
if( $relation->find($consumable_id) ) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['consumable' => 'Consumable already attached to kit']));
}
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$relation->attach( $consumable_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable added successfull')); // TODO: trans
$consumable_id = $request->get('consumable');
$relation = $kit->consumables();
if ($relation->find($consumable_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['consumable' => trans('admin/kits/general.consumable_error')]));
}
$relation->attach($consumable_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.consumable_added_success')));
}
/**
@@ -343,20 +342,20 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function updateConsumable(Request $request, $kit_id, $consumable_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
$kit->consumables()->syncWithoutDetaching([$consumable_id => ['quantity' => $quantity]]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable updated')); // TODO: trans
}
public function updateConsumable(Request $request, $kit_id, $consumable_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$kit->consumables()->syncWithoutDetaching([$consumable_id => ['quantity' => $quantity]]);
/**
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.consumable_updated')));
}
/**
* Remove the specified resource from storage.
*
* @param int $kit_id
@@ -368,48 +367,50 @@ class PredefinedKitsController extends Controller
$kit = PredefinedKit::findOrFail($kit_id);
$kit->consumables()->detach($consumable_id);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.consumable_deleted')));
}
/**
* Display the specified resource.
*
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function indexAccessories($kit_id) {
public function indexAccessories($kit_id)
{
$this->authorize('view', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$accessories = $kit->accessories;
return (new PredefinedKitsTransformer)->transformElements($accessories, $accessories->count());
}
/**
* Store the specified resource.
*
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function storeAccessory(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
public function storeAccessory(Request $request, $kit_id)
{
$this->authorize('update', PredefinedKit::class);
$accessory_id = $request->get('accessory');
$relation = $kit->accessories();
if( $relation->find($accessory_id) ) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['accessory' => 'Accessory already attached to kit']));
}
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$relation->attach( $accessory_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory added successfull')); // TODO: trans
$accessory_id = $request->get('accessory');
$relation = $kit->accessories();
if ($relation->find($accessory_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['accessory' => trans('admin/kits/general.accessory_error')]));
}
$relation->attach($accessory_id, ['quantity' => $quantity]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.accessory_added_success')));
}
/**
@@ -419,20 +420,20 @@ class PredefinedKitsController extends Controller
* @param int $kit_id
* @return \Illuminate\Http\Response
*/
public function updateAccessory(Request $request, $kit_id, $accessory_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if( $quantity < 1) {
$quantity = 1;
}
$kit->accessories()->syncWithoutDetaching([$accessory_id => ['quantity' => $quantity]]);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory updated')); // TODO: trans
}
public function updateAccessory(Request $request, $kit_id, $accessory_id)
{
$this->authorize('update', PredefinedKit::class);
$kit = PredefinedKit::findOrFail($kit_id);
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
}
$kit->accessories()->syncWithoutDetaching([$accessory_id => ['quantity' => $quantity]]);
/**
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.accessory_updated')));
}
/**
* Remove the specified resource from storage.
*
* @param int $kit_id
@@ -444,6 +445,7 @@ class PredefinedKitsController extends Controller
$kit = PredefinedKit::findOrFail($kit_id);
$kit->accessories()->detach($accessory_id);
return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans
return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.accessory_deleted')));
}
}

View File

@@ -15,7 +15,7 @@ class ProfileController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.3.0]
*
* @return Array
* @return array
*/
public function requestedAssets()
{
@@ -24,7 +24,6 @@ class ProfileController extends Controller
$results = [];
$results['total'] = $checkoutRequests->count();
foreach ($checkoutRequests as $checkoutRequest) {
// Make sure the asset and request still exist
@@ -39,10 +38,8 @@ class ProfileController extends Controller
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
];
}
}
return $results;
}
}

View File

@@ -19,25 +19,25 @@ class ReportsController extends Controller
public function index(Request $request)
{
$this->authorize('reports.view');
$actionlogs = Actionlog::with('item', 'user', 'target','location');
$actionlogs = Actionlog::with('item', 'user', 'target', 'location');
if ($request->filled('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
}
if (($request->filled('target_type')) && ($request->filled('target_id'))) {
$actionlogs = $actionlogs->where('target_id','=',$request->input('target_id'))
->where('target_type','=',"App\\Models\\".ucwords($request->input('target_type')));
if (($request->filled('target_type')) && ($request->filled('target_id'))) {
$actionlogs = $actionlogs->where('target_id', '=', $request->input('target_id'))
->where('target_type', '=', 'App\\Models\\'.ucwords($request->input('target_type')));
}
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
$actionlogs = $actionlogs->where('item_id','=',$request->input('item_id'))
->where('item_type','=',"App\\Models\\".ucwords($request->input('item_type')));
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
}
if ($request->filled('action_type')) {
$actionlogs = $actionlogs->where('action_type','=',$request->input('action_type'))->orderBy('created_at', 'desc');
$actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc');
}
if ($request->filled('uploads')) {
@@ -51,9 +51,9 @@ class ReportsController extends Controller
'user_id',
'accept_signature',
'action_type',
'note'
'note',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
$offset = request('offset', 0);
@@ -62,6 +62,5 @@ class ReportsController extends Controller
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
return response()->json((new ActionlogsTransformer)->transformActionlogs($actionlogs, $total), 200, ['Content-Type' => 'application/json;charset=utf8'], JSON_UNESCAPED_UNICODE);
}
}

View File

@@ -2,125 +2,92 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Transformers\LoginAttemptsTransformer;
use App\Models\Setting;
use App\Notifications\MailTest;
use App\Services\LdapAd;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Ldap;
use App\Models\Setting;
use Mail;
use App\Notifications\SlackTest;
use App\Notifications\MailTest;
use GuzzleHttp\Client;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use App\Models\Ldap; // forward-port of v4 LDAP model for Sync
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\SlackSettingsRequest;
class SettingsController extends Controller
{
/**
* Test the ldap settings
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @param App\Models\LdapAd $ldap
*
* @return \Illuminate\Http\JsonResponse
*/
public function ldapAdSettingsTest(LdapAd $ldap): JsonResponse
public function ldaptest()
{
if(!$ldap->init()) {
Log::info('LDAP is not enabled so we cannot test.');
$settings = Setting::getSettings();
if ($settings->ldap_enabled!='1') {
\Log::debug('LDAP is not enabled cannot test.');
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
}
// The connect, bind and resulting users message
$message = [];
\Log::debug('Preparing to test LDAP connection');
// This is all kinda fucked right now. The connection test doesn't actually do what you think,
// // and the way we parse the errors
// on the JS side is horrible.
Log::info('Preparing to test LDAP user login');
// Test user can connect to the LDAP server
$message = []; //where we collect together test messages
try {
$ldap->testLdapAdUserConnection();
$message['login'] = [
'message' => 'Successfully connected to LDAP server.'
];
} catch (\Exception $ex) {
\Log::debug('Connection to LDAP server '.Setting::getSettings()->ldap_server.' failed. Please check your LDAP settings and try again. Server Responded with error: ' . $ex->getMessage());
return response()->json(
['message' => 'Connection to LDAP server '.Setting::getSettings()->ldap_server." failed. Verify that the LDAP hostname is entered correctly and that it can be reached from this web server. \n\nServer Responded with error: " . $ex->getMessage()
], 400);
}
Log::info('Preparing to test LDAP bind connection');
// Test user can bind to the LDAP server
try {
Log::info('Testing Bind');
$ldap->testLdapAdBindConnection();
$message['bind'] = [
'message' => 'Successfully bound to LDAP server.'
];
} catch (\Exception $ex) {
Log::info('LDAP Bind failed');
return response()->json(['message' => 'Connection to LDAP successful, but we were unable to Bind the LDAP user '.Setting::getSettings()->ldap_uname.". Verify your that your LDAP Bind username and password are correct. \n\nServer Responded with error: " . $ex->getMessage()
], 400);
}
Log::info('Preparing to get sample user set from LDAP directory');
// Get a sample of 10 users so user can verify the data is correct
$settings = Setting::getSettings();
try {
Log::info('Testing LDAP sync');
error_reporting(E_ALL & ~E_DEPRECATED); // workaround for php7.4, which deprecates ldap_control_paged_result
// $users = $ldap->testUserImportSync(); // from AdLdap2 from v5, disabling and falling back to v4's sync code
$users = collect(Ldap::findLdapUsers())->slice(0, 11)->filter(function ($value, $key) { //choosing ELEVEN because one is going to be the count, which we're about to filter out in the next line
return is_int($key);
})->map(function ($item) use ($settings) {
return (object) [
'username' => $item[$settings['ldap_username_field']][0] ?? null,
'employee_number' => $item[$settings['ldap_emp_num']][0] ?? null,
'lastname' => $item[$settings['ldap_lname_field']][0] ?? null,
'firstname' => $item[$settings['ldap_fname_field']][0] ?? null,
'email' => $item[$settings['ldap_email']][0] ?? null,
$connection = Ldap::connectToLdap();
try {
$message['bind'] = ['message' => 'Successfully bound to LDAP server.'];
\Log::debug('attempting to bind to LDAP for LDAP test');
Ldap::bindAdminToLdap($connection);
$message['login'] = [
'message' => 'Successfully connected to LDAP server.',
];
});
if ($users->count() > 0) {
$message['user_sync'] = [
'users' => $users
];
} else {
$message['user_sync'] = [
'message' => 'Connection to LDAP was successful, however there were no users returned from your query. You should confirm the Base Bind DN above.'
];
return response()->json($message, 400);
$users = collect(Ldap::findLdapUsers(null,10))->filter(function ($value, $key) {
return is_int($key);
})->slice(0, 10)->map(function ($item) use ($settings) {
return (object) [
'username' => $item[$settings['ldap_username_field']][0] ?? null,
'employee_number' => $item[$settings['ldap_emp_num']][0] ?? null,
'lastname' => $item[$settings['ldap_lname_field']][0] ?? null,
'firstname' => $item[$settings['ldap_fname_field']][0] ?? null,
'email' => $item[$settings['ldap_email']][0] ?? null,
];
});
if ($users->count() > 0) {
$message['user_sync'] = [
'users' => $users,
];
} else {
$message['user_sync'] = [
'message' => 'Connection to LDAP was successful, however there were no users returned from your query. You should confirm the Base Bind DN above.',
];
return response()->json($message, 400);
}
return response()->json($message, 200);
} catch (\Exception $e) {
\Log::debug('Bind failed');
\Log::debug("Exception was: ".$e->getMessage());
return response()->json(['message' => $e->getMessage()], 400);
//return response()->json(['message' => $e->getMessage()], 500);
}
} catch (\Exception $ex) {
Log::info('LDAP sync failed');
$message['user_sync'] = [
'message' => 'Error getting users from LDAP directory, error: ' . $ex->getMessage()
];
return response()->json($message, 400);
} catch (\Exception $e) {
\Log::debug('Connection failed but we cannot debug it any further on our end.');
return response()->json(['message' => $e->getMessage()], 500);
}
return response()->json($message, 200);
}
public function ldaptestlogin(Request $request, LdapAd $ldap)
public function ldaptestlogin(Request $request)
{
if (Setting::getSettings()->ldap_enabled!='1') {
if (Setting::getSettings()->ldap_enabled != '1') {
\Log::debug('LDAP is not enabled. Cannot test.');
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
}
@@ -139,57 +106,77 @@ class SettingsController extends Controller
}
\Log::debug('Preparing to test LDAP login');
try {
DB::beginTransaction(); //this was the easiest way to invoke a full test of an LDAP login without adding new users to the DB (which may not be desired)
$connection = Ldap::connectToLdap();
try {
Ldap::bindAdminToLdap($connection);
\Log::debug('Attempting to bind to LDAP for LDAP test');
try {
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
if ($ldap_user) {
\Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
}
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
// $results = $ldap->ldap->auth()->attempt($request->input('ldaptest_username'), $request->input('ldaptest_password'), true);
// can't do this because that's a protected property.
} catch (\Exception $e) {
\Log::debug('LDAP login failed');
return response()->json(['message' => $e->getMessage()], 400);
}
$results = $ldap->ldapLogin($request->input('ldaptest_user'), $request->input('ldaptest_password')); // this would normally create a user on success (if they didn't already exist), but for the transaction
if($results) {
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
} else {
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
} catch (\Exception $e) {
\Log::debug('Bind failed');
return response()->json(['message' => $e->getMessage()], 400);
//return response()->json(['message' => $e->getMessage()], 500);
}
} catch (\Exception $e) {
\Log::debug('Connection failed');
return response()->json(['message' => $e->getMessage()], 400);
} finally {
DB::rollBack(); // ALWAYS rollback, whether success or failure
return response()->json(['message' => $e->getMessage()], 500);
}
}
public function slacktest(Request $request)
public function slacktest(SlackSettingsRequest $request)
{
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false
]
$validator = Validator::make($request->all(), [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:'
]);
try {
$slack->post($request->input('slack_endpoint'),['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'Oops! Please check the channel name and webhook endpoint URL. Slack responded with: '.$e->getMessage()], 400);
if ($validator->fails()) {
return response()->json(['message' => 'Validation failed', 'errors' => $validator->errors()], 422);
}
return response()->json(['message' => 'Something went wrong :( '], 400);
// If validation passes, continue to the curl request
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($request->input('slack_endpoint'), ['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'Please check the channel name and webhook endpoint URL ('.e($request->input('slack_endpoint')).'). Slack responded with: '.$e->getMessage()], 400);
}
//}
return response()->json(['message' => 'Something went wrong :( '], 400);
}
@@ -224,23 +211,21 @@ class SettingsController extends Controller
*/
public function purgeBarcodes()
{
$file_count = 0;
$files = Storage::disk('public')->files('barcodes');
foreach ($files as $file) { // iterate files
$file_parts = explode(".", $file);
$file_parts = explode('.', $file);
$extension = end($file_parts);
\Log::debug($extension);
// Only generated barcodes would have a .png file extension
if ($extension =='png') {
if ($extension == 'png') {
\Log::debug('Deleting: '.$file);
try {
try {
Storage::disk('public')->delete($file);
\Log::debug('Deleting: '.$file);
$file_count++;
@@ -248,11 +233,9 @@ class SettingsController extends Controller
\Log::debug($e);
}
}
}
return response()->json(['message' => 'Deleted '.$file_count.' barcodes'], 200);
}
@@ -269,20 +252,16 @@ class SettingsController extends Controller
*/
public function showLoginAttempts(Request $request)
{
$allowed_columns = ['id', 'username', 'remote_ip', 'user_agent','successful','created_at'];
$allowed_columns = ['id', 'username', 'remote_ip', 'user_agent', 'successful', 'created_at'];
$login_attempts = DB::table('login_attempts');
$login_attempts = DB::table('login_attempts');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'created_at';
$total = $login_attempts->count();
$login_attempts->orderBy($sort, $order);
$login_attempt_results = $login_attempts->skip(request('offset', 0))->take(request('limit', 20))->get();
$login_attempt_results = $login_attempts->skip(request('offset', 0))->take(request('limit', 20))->get();
return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total);
}
}
}

View File

@@ -22,7 +22,7 @@ class StatuslabelsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Statuslabel::class);
$allowed_columns = ['id','name','created_at', 'assets_count','color', 'notes','default_label'];
$allowed_columns = ['id', 'name', 'created_at', 'assets_count', 'color', 'notes', 'default_label'];
$statuslabels = Statuslabel::withCount('assets as assets_count');
@@ -30,6 +30,20 @@ class StatuslabelsController extends Controller
$statuslabels = $statuslabels->TextSearch($request->input('search'));
}
// if a status_type is passed, filter by that
if ($request->filled('status_type')) {
if (strtolower($request->input('status_type'))== 'pending') {
$statuslabels = $statuslabels->Pending();
} elseif (strtolower($request->input('status_type'))== 'archived') {
$statuslabels = $statuslabels->Archived();
} elseif (strtolower($request->input('status_type'))== 'deployable') {
$statuslabels = $statuslabels->Deployable();
} elseif (strtolower($request->input('status_type'))== 'undeployable') {
$statuslabels = $statuslabels->Undeployable();
}
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($statuslabels) && ($request->get('offset') > $statuslabels->count())) ? $statuslabels->count() : $request->get('offset', 0);
@@ -43,6 +57,7 @@ class StatuslabelsController extends Controller
$total = $statuslabels->count();
$statuslabels = $statuslabels->skip($offset)->take($limit)->get();
return (new StatuslabelsTransformer)->transformStatuslabels($statuslabels, $total);
}
@@ -58,19 +73,19 @@ class StatuslabelsController extends Controller
public function store(Request $request)
{
$this->authorize('create', Statuslabel::class);
$request->except('deployable', 'pending','archived');
$request->except('deployable', 'pending', 'archived');
if (!$request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, ["type" => ["Status label type is required."]]),500);
if (! $request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['type' => ['Status label type is required.']]), 500);
}
$statuslabel = new Statuslabel;
$statuslabel->fill($request->all());
$statusType = Statuslabel::getStatuslabelTypesForDB($request->input('type'));
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);
@@ -79,8 +94,8 @@ class StatuslabelsController extends Controller
if ($statuslabel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
}
/**
@@ -95,10 +110,10 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$statuslabel = Statuslabel::findOrFail($id);
return (new StatuslabelsTransformer)->transformStatuslabel($statuslabel);
}
/**
* Update the specified resource in storage.
*
@@ -113,19 +128,21 @@ class StatuslabelsController extends Controller
$this->authorize('update', Statuslabel::class);
$statuslabel = Statuslabel::findOrFail($id);
$request->except('deployable', 'pending','archived');
$request->except('deployable', 'pending', 'archived');
if (! $request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
}
$statuslabel->fill($request->all());
$statusType = Statuslabel::getStatuslabelTypesForDB($request->input('type'));
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav');
$statuslabel->default_label = $request->input('default_label');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);
if ($statuslabel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.update.success')));
@@ -151,15 +168,13 @@ class StatuslabelsController extends Controller
// Check that there are no assets associated
if ($statuslabel->assets()->count() == 0) {
$statuslabel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/statuslabels/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/statuslabels/message.delete.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/statuslabels/message.assoc_assets')));
}
/**
* Show a count of assets by status label for pie chart
*
@@ -167,24 +182,23 @@ class StatuslabelsController extends Controller
* @since [v3.0]
* @return \Illuminate\Http\Response
*/
public function getAssetCountByStatuslabel()
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::withCount('assets')->get();
$labels=[];
$points=[];
$labels = [];
$points = [];
$default_color_count = 0;
$colors_array = array();
$colors_array = [];
foreach ($statuslabels as $statuslabel) {
if ($statuslabel->assets_count > 0) {
$labels[]=$statuslabel->name. ' ('.number_format($statuslabel->assets_count).')';
$points[]=$statuslabel->assets_count;
$labels[] = $statuslabel->name.' ('.number_format($statuslabel->assets_count).')';
$points[] = $statuslabel->assets_count;
if ($statuslabel->color!='') {
if ($statuslabel->color != '') {
$colors_array[] = $statuslabel->color;
} else {
$colors_array[] = Helper::defaultChartColors($default_color_count);
@@ -193,14 +207,15 @@ class StatuslabelsController extends Controller
}
}
$result= [
"labels" => $labels,
"datasets" => [ [
"data" => $points,
"backgroundColor" => $colors_array,
"hoverBackgroundColor" => $colors_array
]]
$result = [
'labels' => $labels,
'datasets' => [[
'data' => $points,
'backgroundColor' => $colors_array,
'hoverBackgroundColor' => $colors_array,
]],
];
return $result;
}
@@ -216,7 +231,7 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$this->authorize('index', Asset::class);
$assets = Asset::where('status_id','=',$id)->with('assignedTo');
$assets = Asset::where('status_id', '=', $id)->with('assignedTo');
$allowed_columns = [
'id',
@@ -246,11 +261,12 @@ class StatuslabelsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return Bool
* @return bool
*/
public function checkIfDeployable($id) {
public function checkIfDeployable($id)
{
$statuslabel = Statuslabel::findOrFail($id);
if ($statuslabel->getStatuslabelType()=='deployable') {
if ($statuslabel->getStatuslabelType() == 'deployable') {
return '1';
}

View File

@@ -23,10 +23,10 @@ class SuppliersController extends Controller
public function index(Request $request)
{
$this->authorize('view', Supplier::class);
$allowed_columns = ['id','name','address','phone','contact','fax','email','image','assets_count','licenses_count', 'accessories_count','url'];
$allowed_columns = ['id', 'name', 'address', 'phone', 'contact', 'fax', 'email', 'image', 'assets_count', 'licenses_count', 'accessories_count', 'url'];
$suppliers = Supplier::select(
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image','notes')
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'updated_at', 'deleted_at', 'image', 'notes']
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('accessories as accessories_count');
@@ -47,6 +47,7 @@ class SuppliersController extends Controller
$total = $suppliers->count();
$suppliers = $suppliers->skip($offset)->take($limit)->get();
return (new SuppliersTransformer)->transformSuppliers($suppliers, $total);
}
@@ -85,6 +86,7 @@ class SuppliersController extends Controller
{
$this->authorize('view', Supplier::class);
$supplier = Supplier::findOrFail($id);
return (new SuppliersTransformer)->transformSupplier($supplier);
}
@@ -123,16 +125,16 @@ class SuppliersController extends Controller
public function destroy($id)
{
$this->authorize('delete', Supplier::class);
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count','assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
$this->authorize('delete', $supplier);
if ($supplier->assets_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count])));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count])));
}
if ($supplier->asset_maintenances_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count])));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count])));
}
if ($supplier->licenses_count > 0) {
@@ -140,8 +142,8 @@ class SuppliersController extends Controller
}
$supplier->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success')));
}
/**
@@ -150,11 +152,12 @@ class SuppliersController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view.selectlists');
$suppliers = Supplier::select([
'id',
'name',
@@ -176,7 +179,5 @@ class SuppliersController extends Controller
}
return (new SelectlistTransformer)->transformSelectlist($suppliers);
}
}

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserRequest;
use App\Http\Transformers\AccessoriesTransformer;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\ConsumablesTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Http\Transformers\UsersTransformer;
@@ -62,16 +63,17 @@ class UsersController extends Controller
'users.updated_at',
'users.username',
'users.zip',
'users.remote',
'users.ldap_import',
])->with('manager', 'groups', 'userloc', 'company', 'department','assets','licenses','accessories','consumables')
->withCount('assets as assets_count','licenses as licenses_count','accessories as accessories_count','consumables as consumables_count');
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables')
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
$users = Company::scopeCompanyables($users);
if (($request->filled('deleted')) && ($request->input('deleted')=='true')) {
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
$users = $users->onlyTrashed();
} elseif (($request->filled('all')) && ($request->input('all')=='true')) {
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
$users = $users->withTrashed();
}
@@ -124,13 +126,37 @@ class UsersController extends Controller
}
if ($request->filled('department_id')) {
$users = $users->where('users.department_id','=',$request->input('department_id'));
$users = $users->where('users.department_id', '=', $request->input('department_id'));
}
if ($request->filled('manager_id')) {
$users = $users->where('users.manager_id','=',$request->input('manager_id'));
}
if ($request->filled('ldap_import')) {
$users = $users->where('ldap_import', '=', $request->input('ldap_import'));
}
if ($request->filled('remote')) {
$users = $users->where('remote', '=', $request->input('remote'));
}
if ($request->filled('assets_count')) {
$users->has('assets', '=', $request->input('assets_count'));
}
if ($request->filled('consumables_count')) {
$users->has('consumables', '=', $request->input('consumables_count'));
}
if ($request->filled('licenses_count')) {
$users->has('licenses', '=', $request->input('licenses_count'));
}
if ($request->filled('accessories_count')) {
$users->has('accessories', '=', $request->input('accessories_count'));
}
if ($request->filled('search')) {
$users = $users->TextSearch($request->input('search'));
}
@@ -162,11 +188,11 @@ class UsersController extends Controller
default:
$allowed_columns =
[
'last_name','first_name','email','jobtitle','username','employee_num',
'assets','accessories', 'consumables','licenses','groups','activated','created_at',
'two_factor_enrolled','two_factor_optin','last_login', 'assets_count', 'licenses_count',
'last_name', 'first_name', 'email', 'jobtitle', 'username', 'employee_num',
'assets', 'accessories', 'consumables', 'licenses', 'groups', 'activated', 'created_at',
'two_factor_enrolled', 'two_factor_optin', 'last_login', 'assets_count', 'licenses_count',
'consumables_count', 'accessories_count', 'phone', 'address', 'city', 'state',
'country', 'zip', 'id', 'ldap_import'
'country', 'zip', 'id', 'ldap_import', 'remote',
];
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
@@ -174,24 +200,21 @@ class UsersController extends Controller
break;
}
$total = $users->count();
$users = $users->skip($offset)->take($limit)->get();
return (new UsersTransformer)->transformUsers($users, $total);
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$users = User::select(
[
'users.id',
@@ -218,16 +241,16 @@ class UsersController extends Controller
foreach ($users as $user) {
$name_str = '';
if ($user->last_name!='') {
if ($user->last_name != '') {
$name_str .= $user->last_name.', ';
}
$name_str .= $user->first_name;
if ($user->username!='') {
if ($user->username != '') {
$name_str .= ' ('.$user->username.')';
}
if ($user->employee_num!='') {
if ($user->employee_num != '') {
$name_str .= ' - #'.$user->employee_num;
}
@@ -236,7 +259,6 @@ class UsersController extends Controller
}
return (new SelectlistTransformer)->transformSelectlist($users);
}
@@ -257,17 +279,16 @@ class UsersController extends Controller
$user->fill($request->all());
if ($request->has('permissions')) {
$permissions_array = $request->input('permissions');
// Strip out the superuser permission if the API user isn't a superadmin
if (!Auth::user()->isSuperUser()) {
if (! Auth::user()->isSuperUser()) {
unset($permissions_array['superuser']);
}
$user->permissions = $permissions_array;
$user->permissions = $permissions_array;
}
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
$user->password = bcrypt($request->get('password', $tmp_pass));
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
@@ -276,11 +297,12 @@ class UsersController extends Controller
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync(array());
$user->groups()->sync([]);
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.create')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
}
@@ -294,7 +316,8 @@ class UsersController extends Controller
public function show($id)
{
$this->authorize('view', User::class);
$user = User::withCount('assets as assets_count','licenses as licenses_count','accessories as accessories_count','consumables as consumables_count')->findOrFail($id);
$user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count')->findOrFail($id);
return (new UsersTransformer)->transformUser($user);
}
@@ -343,19 +366,17 @@ class UsersController extends Controller
// here because we need to overwrite permissions
// if someone needs to null them out
if ($request->has('permissions')) {
$permissions_array = $request->input('permissions');
// Strip out the superuser permission if the API user isn't a superadmin
if (!Auth::user()->isSuperUser()) {
if (! Auth::user()->isSuperUser()) {
unset($permissions_array['superuser']);
}
$user->permissions = $permissions_array;
$user->permissions = $permissions_array;
}
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
@@ -375,8 +396,8 @@ class UsersController extends Controller
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
// The groups field has been passed but it is null, so we should blank it out
} elseif ($request->has('groups')) {
$user->groups()->sync(array());
} elseif ($request->has('groups')) {
$user->groups()->sync([]);
}
@@ -400,36 +421,37 @@ class UsersController extends Controller
$user = User::findOrFail($id);
$this->authorize('delete', $user);
if (($user->assets) && ($user->assets->count() > 0)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets')));
}
if (($user->licenses) && ($user->licenses->count() > 0)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->licenses->count() . ' license(s) associated with them and cannot be deleted.'));
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->licenses->count().' license(s) associated with them and cannot be deleted.'));
}
if (($user->accessories) && ($user->accessories->count() > 0)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->accessories->count() . ' accessories associated with them.'));
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->accessories->count().' accessories associated with them.'));
}
if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.'));
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->managedLocations()->count().' locations that they manage.'));
}
if ($user->delete()) {
// Remove the user's avatar if they have one
if (Storage::disk('public')->exists('avatars/'.$user->avatar)) {
try {
try {
Storage::disk('public')->delete('avatars/'.$user->avatar);
} catch (\Exception $e) {
\Log::debug($e);
}
}
}
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
}
/**
@@ -445,9 +467,28 @@ class UsersController extends Controller
$this->authorize('view', User::class);
$this->authorize('view', Asset::class);
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model')->get();
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
}
/**
* Return JSON containing a list of consumables assigned to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $userId
* @return string JSON
*/
public function consumables(Request $request, $id)
{
$this->authorize('view', User::class);
$this->authorize('view', Consumable::class);
$user = User::findOrFail($id);
$consumables = $user->consumables;
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
}
/**
* Return JSON containing a list of accessories assigned to a user.
*
@@ -462,6 +503,7 @@ class UsersController extends Controller
$user = User::findOrFail($id);
$this->authorize('view', Accessory::class);
$accessories = $user->accessories;
return (new AccessoriesTransformer)->transformAccessories($accessories, $accessories->count());
}
@@ -479,12 +521,11 @@ class UsersController extends Controller
$this->authorize('view', License::class);
$user = User::where('id', $id)->withTrashed()->first();
$licenses = $user->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
}
/**
* Reset the user's two-factor status
*
* @author [A. Gianotto] [<snipe@snipe.net>]
@@ -494,7 +535,6 @@ class UsersController extends Controller
*/
public function postTwoFactorReset(Request $request)
{
$this->authorize('update', User::class);
if ($request->filled('id')) {
@@ -503,6 +543,7 @@ class UsersController extends Controller
$user->two_factor_secret = null;
$user->two_factor_enrolled = 0;
$user->save();
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
} catch (\Exception $e) {
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_error')], 500);
@@ -510,6 +551,7 @@ class UsersController extends Controller
}
return response()->json(['message' => 'No ID provided'], 500);
}
/**
@@ -524,4 +566,28 @@ class UsersController extends Controller
{
return (new UsersTransformer)->transformUser($request->user());
}
/**
* Restore a soft-deleted user.
*
* @author [E. Taylor] [<dev@evantaylor.name>]
* @param int $userId
* @since [v6.0.0]
* @return JsonResponse
*/
public function restore($userId = null)
{
// Get asset information
$user = User::withTrashed()->find($userId);
$this->authorize('delete', $user);
if (isset($user->id)) {
// Restore the user
User::withTrashed()->where('id', $userId)->restore();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')));
}
$id = $userId;
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))), 200);
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
@@ -21,7 +22,6 @@ use View;
*/
class AssetMaintenancesController extends Controller
{
/**
* Checks for permissions for this action.
*
@@ -50,11 +50,10 @@ class AssetMaintenancesController extends Controller
*/
public function index()
{
$this->authorize('view', Asset::class);
return view('asset_maintenances/index');
}
/**
* Returns a form view to create a new asset maintenance.
*
@@ -66,6 +65,7 @@ class AssetMaintenancesController extends Controller
*/
public function create()
{
$this->authorize('update', Asset::class);
$asset = null;
if ($asset = Asset::find(request('asset_id'))) {
@@ -96,6 +96,7 @@ class AssetMaintenancesController extends Controller
*/
public function store(Request $request)
{
$this->authorize('update', Asset::class);
// create a new model instance
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
@@ -104,24 +105,24 @@ class AssetMaintenancesController extends Controller
$assetMaintenance->notes = $request->input('notes');
$asset = Asset::find($request->input('asset_id'));
if ((!Company::isCurrentUserHasAccess($asset)) && ($asset!=null)) {
if ((! Company::isCurrentUserHasAccess($asset)) && ($asset != null)) {
return static::getInsufficientPermissionsRedirect();
}
// Save the asset maintenance data
$assetMaintenance->asset_id = $request->input('asset_id');
$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');
$assetMaintenance->user_id = Auth::id();
$assetMaintenance->title = $request->input('title');
$assetMaintenance->start_date = $request->input('start_date');
$assetMaintenance->completion_date = $request->input('completion_date');
$assetMaintenance->user_id = Auth::id();
if (( $assetMaintenance->completion_date !== null )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')
&& ($assetMaintenance->start_date !== '0000-00-00')
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
@@ -133,7 +134,6 @@ class AssetMaintenancesController extends Controller
}
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
}
/**
@@ -148,16 +148,16 @@ class AssetMaintenancesController extends Controller
*/
public function edit($assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the improvement management page
return redirect()->route('maintenances.index')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (!$assetMaintenance->asset) {
} elseif (! $assetMaintenance->asset) {
return redirect()->route('maintenances.index')
->with('error', 'The asset associated with this maintenance does not exist.');
} elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
@@ -184,7 +184,6 @@ class AssetMaintenancesController extends Controller
->with('selectedAsset', null)
->with('assetMaintenanceType', $assetMaintenanceType)
->with('item', $assetMaintenance);
}
/**
@@ -200,12 +199,13 @@ class AssetMaintenancesController extends Controller
*/
public function update(Request $request, $assetMaintenanceId = null)
{
$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 (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
@@ -216,32 +216,32 @@ class AssetMaintenancesController extends Controller
$asset = Asset::find(request('asset_id'));
if (!Company::isCurrentUserHasAccess($asset)) {
if (! Company::isCurrentUserHasAccess($asset)) {
return static::getInsufficientPermissionsRedirect();
}
// Save the asset maintenance data
$assetMaintenance->asset_id = $request->input('asset_id');
$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');
$assetMaintenance->title = $request->input('title');
$assetMaintenance->start_date = $request->input('start_date');
$assetMaintenance->completion_date = $request->input('completion_date');
if (( $assetMaintenance->completion_date == null )
if (($assetMaintenance->completion_date == null)
) {
if (( $assetMaintenance->asset_maintenance_time !== 0 )
|| ( !is_null($assetMaintenance->asset_maintenance_time) )
if (($assetMaintenance->asset_maintenance_time !== 0)
|| (! is_null($assetMaintenance->asset_maintenance_time))
) {
$assetMaintenance->asset_maintenance_time = null;
}
}
if (( $assetMaintenance->completion_date !== null )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')
&& ($assetMaintenance->start_date !== '0000-00-00')
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
@@ -252,6 +252,7 @@ class AssetMaintenancesController extends Controller
return redirect()->route('maintenances.index')
->with('success', trans('admin/asset_maintenances/message.edit.success'));
}
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
}
@@ -266,12 +267,13 @@ class AssetMaintenancesController extends Controller
*/
public function destroy($assetMaintenanceId)
{
$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 (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
@@ -294,12 +296,14 @@ class AssetMaintenancesController extends Controller
*/
public function show($assetMaintenanceId)
{
$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)) {
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
@@ -10,7 +11,6 @@ use Illuminate\Support\Facades\View;
use Redirect;
use Request;
use Storage;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
@@ -34,6 +34,7 @@ class AssetModelsController extends Controller
public function index()
{
$this->authorize('index', AssetModel::class);
return view('models/index');
}
@@ -48,12 +49,12 @@ class AssetModelsController extends Controller
public function create()
{
$this->authorize('create', AssetModel::class);
return view('models/edit')->with('category_type', 'asset')
->with('depreciation_list', Helper::depreciationList())
->with('item', new AssetModel);
}
/**
* Validate and process the new Asset Model data.
*
@@ -65,7 +66,6 @@ class AssetModelsController extends Controller
*/
public function store(ImageUploadRequest $request)
{
$this->authorize('create', AssetModel::class);
// Create a new asset model
$model = new AssetModel;
@@ -73,29 +73,30 @@ class AssetModelsController extends Controller
// Save the model data
$model->eol = $request->input('eol');
$model->depreciation_id = $request->input('depreciation_id');
$model->name = $request->input('name');
$model->model_number = $request->input('model_number');
$model->manufacturer_id = $request->input('manufacturer_id');
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->user_id = Auth::id();
$model->requestable = Request::has('requestable');
$model->name = $request->input('name');
$model->model_number = $request->input('model_number');
$model->manufacturer_id = $request->input('manufacturer_id');
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->user_id = Auth::id();
$model->requestable = Request::has('requestable');
if ($request->input('custom_fieldset')!='') {
if ($request->input('custom_fieldset') != '') {
$model->fieldset_id = e($request->input('custom_fieldset'));
}
$model = $request->handleImages($model);
// Was it created?
// Was it created?
if ($model->save()) {
if ($this->shouldAddDefaultValues($request->input())) {
$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'));
}
// Redirect to the new model page
return redirect()->route("models.index")->with('success', trans('admin/models/message.create.success'));
return redirect()->route('models.index')->with('success', trans('admin/models/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($model->getErrors());
}
@@ -113,13 +114,13 @@ class AssetModelsController extends Controller
$this->authorize('update', AssetModel::class);
if ($item = AssetModel::find($modelId)) {
$category_type = 'asset';
$view = View::make('models/edit', compact('item','category_type'));
$view = View::make('models/edit', compact('item', 'category_type'));
$view->with('depreciation_list', Helper::depreciationList());
return $view;
}
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
@@ -145,20 +146,18 @@ class AssetModelsController extends Controller
$model = $request->handleImages($model);
$model->depreciation_id = $request->input('depreciation_id');
$model->eol = $request->input('eol');
$model->name = $request->input('name');
$model->model_number = $request->input('model_number');
$model->manufacturer_id = $request->input('manufacturer_id');
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->requestable = $request->input('requestable', '0');
$model->depreciation_id = $request->input('depreciation_id');
$model->eol = $request->input('eol');
$model->name = $request->input('name');
$model->model_number = $request->input('model_number');
$model->manufacturer_id = $request->input('manufacturer_id');
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->requestable = $request->input('requestable', '0');
$this->removeCustomFieldsDefaultValues($model);
if ($request->input('custom_fieldset')=='') {
if ($request->input('custom_fieldset') == '') {
$model->fieldset_id = null;
} else {
$model->fieldset_id = $request->input('custom_fieldset');
@@ -168,10 +167,10 @@ class AssetModelsController extends Controller
}
}
if ($model->save()) {
return redirect()->route("models.index")->with('success', trans('admin/models/message.update.success'));
return redirect()->route('models.index')->with('success', trans('admin/models/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($model->getErrors());
}
@@ -199,7 +198,7 @@ class AssetModelsController extends Controller
}
if ($model->image) {
try {
try {
Storage::disk('public')->delete('models/'.$model->image);
} catch (\Exception $e) {
\Log::info($e);
@@ -213,7 +212,6 @@ class AssetModelsController extends Controller
return redirect()->route('models.index')->with('success', trans('admin/models/message.delete.success'));
}
/**
* Restore a given Asset Model (mark as un-deleted)
*
@@ -231,6 +229,7 @@ class AssetModelsController extends Controller
if (isset($model->id)) {
$model->restore();
return redirect()->route('models.index')->with('success', trans('admin/models/message.restore.success'));
}
return redirect()->back()->with('error', trans('admin/models/message.not_found'));
@@ -260,15 +259,16 @@ class AssetModelsController extends Controller
}
/**
* Get the clone page to clone a model
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
* Get the clone page to clone a model
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
public function getClone($modelId = null)
{
$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'));
@@ -286,21 +286,20 @@ class AssetModelsController extends Controller
/**
* Get the custom fields form
*
* @author [B. Wetherington] [<uberbrady@gmail.com>]
* @since [v2.0]
* @param int $modelId
* @return View
*/
* Get the custom fields form
*
* @author [B. Wetherington] [<uberbrady@gmail.com>]
* @since [v2.0]
* @param int $modelId
* @return View
*/
public function getCustomFields($modelId)
{
return view("models.custom_fields_form")->with("model", AssetModel::find($modelId));
return view('models.custom_fields_form')->with('model', AssetModel::find($modelId));
}
/**
* Returns a view that allows the user to bulk edit model attrbutes
*
@@ -310,28 +309,25 @@ class AssetModelsController extends Controller
*/
public function postBulkEdit(Request $request)
{
$models_raw_array = $request->input('ids');
// Make sure some IDs have been selected
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->orderBy('assets_count', 'ASC')->get();
// If deleting....
if ($request->input('bulk_actions')=='delete') {
if ($request->input('bulk_actions') == 'delete') {
$valid_count = 0;
foreach ($models as $model) {
if ($model->assets_count == 0) {
$valid_count++;
}
}
return view('models/bulk-delete', compact('models'))->with('valid_count', $valid_count);
// Otherwise display the bulk edit screen
} else {
$nochange = ['NC' => 'No Change'];
$fieldset_list = $nochange + Helper::customFieldsetList();
$depreciation_list = $nochange + Helper::depreciationList();
@@ -340,12 +336,10 @@ class AssetModelsController extends Controller
->with('fieldset_list', $fieldset_list)
->with('depreciation_list', $depreciation_list);
}
}
return redirect()->route('models.index')
->with('error', 'You must select at least one model to edit.');
}
@@ -359,35 +353,33 @@ class AssetModelsController extends Controller
*/
public function postBulkEditSave(Request $request)
{
$models_raw_array = $request->input('ids');
$update_array = array();
$update_array = [];
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) {
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id') != 'NC'))) {
$update_array['manufacturer_id'] = $request->input('manufacturer_id');
}
if (($request->filled('category_id') && ($request->input('category_id')!='NC'))) {
if (($request->filled('category_id') && ($request->input('category_id') != 'NC'))) {
$update_array['category_id'] = $request->input('category_id');
}
if ($request->input('fieldset_id')!='NC') {
if ($request->input('fieldset_id') != 'NC') {
$update_array['fieldset_id'] = $request->input('fieldset_id');
}
if ($request->input('depreciation_id')!='NC') {
if ($request->input('depreciation_id') != 'NC') {
$update_array['depreciation_id'] = $request->input('depreciation_id');
}
if (count($update_array) > 0) {
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
return redirect()->route('models.index')
->with('success', trans('admin/models/message.bulkedit.success'));
}
return redirect()->route('models.index')
->with('warning', trans('admin/models/message.bulkedit.error'));
}
/**
@@ -404,7 +396,6 @@ class AssetModelsController extends Controller
$models_raw_array = $request->input('ids');
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->get();
$del_error_count = 0;
@@ -426,7 +417,7 @@ class AssetModelsController extends Controller
if ($del_error_count == 0) {
return redirect()->route('models.index')
->with('success', trans('admin/models/message.bulkdelete.success',['success_count'=> $del_count] ));
->with('success', trans('admin/models/message.bulkdelete.success', ['success_count'=> $del_count]));
}
return redirect()->route('models.index')
@@ -435,7 +426,6 @@ class AssetModelsController extends Controller
return redirect()->route('models.index')
->with('error', trans('admin/models/message.bulkdelete.error'));
}
/**
@@ -443,13 +433,13 @@ class AssetModelsController extends Controller
* any default values were entered into the form.
*
* @param array $input
* @return boolean
* @return bool
*/
private function shouldAddDefaultValues(array $input)
{
return !empty($input['add_default_values'])
&& !empty($input['default_values'])
&& !empty($input['custom_fieldset']);
return ! empty($input['add_default_values'])
&& ! empty($input['default_values'])
&& ! empty($input['custom_fieldset']);
}
/**
@@ -462,7 +452,9 @@ class AssetModelsController extends Controller
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues)
{
foreach ($defaultValues as $customFieldId => $defaultValue) {
if ($defaultValue) {
if(is_array($defaultValue)){
$model->defaultValues()->attach($customFieldId, ['default_value' => implode(', ', $defaultValue)]);
}elseif ($defaultValue) {
$model->defaultValues()->attach($customFieldId, ['default_value' => $defaultValue]);
}
}

View File

@@ -7,13 +7,14 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckinRequest;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class AssetCheckinController extends Controller
{
/**
* Returns a view that presents a form to check an asset back into inventory.
*
@@ -33,6 +34,7 @@ class AssetCheckinController extends Controller
}
$this->authorize('checkin', $asset);
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto);
}
@@ -73,7 +75,7 @@ class AssetCheckinController extends Controller
$asset->name = $request->get('name');
if ($request->filled('status_id')) {
$asset->status_id = e($request->get('status_id'));
$asset->status_id = e($request->get('status_id'));
}
// This is just meant to correct legacy issues where some user data would have 0
@@ -81,14 +83,14 @@ class AssetCheckinController extends Controller
// rules, so it's necessary to fix this for long-time users. It's kinda gross, but will help
// people (and their data) in the long run
if ($asset->rtd_location_id=='0') {
if ($asset->rtd_location_id == '0') {
\Log::debug('Manually override the RTD location IDs');
\Log::debug('Original RTD Location ID: '.$asset->rtd_location_id);
$asset->rtd_location_id = '';
\Log::debug('New RTD Location ID: '.$asset->rtd_location_id);
}
if ($asset->location_id=='0') {
if ($asset->location_id == '0') {
\Log::debug('Manually override the location IDs');
\Log::debug('Original Location ID: '.$asset->location_id);
$asset->location_id = '';
@@ -99,27 +101,37 @@ class AssetCheckinController extends Controller
\Log::debug('After Location ID: '.$asset->location_id);
\Log::debug('After RTD Location ID: '.$asset->rtd_location_id);
if ($request->filled('location_id')) {
\Log::debug('NEW Location ID: '.$request->get('location_id'));
$asset->location_id = e($request->get('location_id'));
$asset->location_id = e($request->get('location_id'));
}
$checkin_at = date('Y-m-d');
if($request->filled('checkin_at')){
if ($request->filled('checkin_at')) {
$checkin_at = $request->input('checkin_at');
}
// Get all pending Acceptances for this asset and delete them
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
[Asset::class],
function (Builder $query) use ($asset) {
$query->where('id', $asset->id);
})->get();
$acceptances->map(function($acceptance) {
$acceptance->delete();
});
// Was the asset updated?
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at));
if ((isset($user)) && ($backto =='user')) {
return redirect()->route("users.show", $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
if ((isset($user)) && ($backto == 'user')) {
return redirect()->route('users.show', $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
}
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkin.success'));
}
// Redirect to the asset management page with error
return redirect()->route("hardware.index")->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
}
}

View File

@@ -2,7 +2,6 @@
namespace App\Http\Controllers\Assets;
use App\Exceptions\CheckoutNotAllowed;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
@@ -15,15 +14,16 @@ use Illuminate\Support\Facades\Auth;
class AssetCheckoutController extends Controller
{
use CheckInOutRequest;
/**
* Returns a view that presents a form to check an asset out to a
* user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $assetId
* @since [v1.0]
* @return View
*/
* Returns a view that presents a form to check an asset out to a
* user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $assetId
* @since [v1.0]
* @return View
*/
public function create($assetId)
{
// Check if the asset exists
@@ -37,9 +37,8 @@ class AssetCheckoutController extends Controller
return view('hardware/checkout', compact('asset'))
->with('statusLabel_list', Helper::deployableStatusLabelList());
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
}
/**
@@ -55,9 +54,9 @@ class AssetCheckoutController extends Controller
{
try {
// Check if the asset exists
if (!$asset = Asset::find($assetId)) {
if (! $asset = Asset::find($assetId)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
} elseif (!$asset->availableForCheckout()) {
} elseif (! $asset->availableForCheckout()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
}
$this->authorize('checkout', $asset);
@@ -67,8 +66,8 @@ class AssetCheckoutController extends Controller
$asset = $this->updateAssetLocation($asset, $target);
$checkout_at = date("Y-m-d H:i:s");
if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
$checkout_at = date('Y-m-d H:i:s');
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->get('checkout_at');
}
@@ -82,7 +81,7 @@ class AssetCheckoutController extends Controller
}
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $request->get('name'))) {
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkout.success'));
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
}
// Redirect to the asset management page with error
@@ -93,5 +92,4 @@ class AssetCheckoutController extends Controller
return redirect()->back()->with('error', $e->getMessage());
}
}
}

View File

@@ -2,13 +2,13 @@
namespace App\Http\Controllers\Assets;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetFileRequest;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use App\Helpers\StorageHelper;
use enshrined\svgSanitize\Sanitizer;
class AssetFilesController extends Controller
@@ -25,15 +25,16 @@ class AssetFilesController extends Controller
*/
public function store(AssetFileRequest $request, $assetId = null)
{
if (!$asset = Asset::find($assetId)) {
if (! $asset = Asset::find($assetId)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('update', $asset);
if ($request->hasFile('file')) {
if (!Storage::exists('private_uploads/assets')) Storage::makeDirectory('private_uploads/assets', 775);
if (! Storage::exists('private_uploads/assets')) {
Storage::makeDirectory('private_uploads/assets', 775);
}
foreach ($request->file('file') as $file) {
@@ -55,12 +56,13 @@ class AssetFilesController extends Controller
\Log::debug($e);
}
} else {
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
}
$asset->logUpload($file_name, e($request->get('notes')));
}
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
}
@@ -84,7 +86,7 @@ class AssetFilesController extends Controller
if (isset($asset->id)) {
$this->authorize('view', $asset);
if (!$log = Actionlog::find($fileId)) {
if (! $log = Actionlog::find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
@@ -92,21 +94,23 @@ class AssetFilesController extends Controller
$file = 'private_uploads/assets/'.$log->filename;
\Log::debug('Checking for '.$file);
if ($log->action_type =='audit') {
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
if (!Storage::exists($file)) {
if (! Storage::exists($file)) {
return response('File '.$file.' not found on server', 404)
->header('Content-Type', 'text/plain');
}
if ($download != 'true') {
if ($contents = file_get_contents(Storage::url($file))) {
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
}
return JsonResponse::create(["error" => "Failed validation: "], 500);
if ($contents = file_get_contents(Storage::url($file))) {
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
}
return JsonResponse::create(['error' => 'Failed validation: '], 500);
}
return StorageHelper::downloader($file);
}
// Prepare the error message
@@ -141,6 +145,7 @@ class AssetFilesController extends Controller
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Assets;
use App\Helpers\Helper;
@@ -14,13 +15,13 @@ use App\Models\Setting;
use App\Models\User;
use Auth;
use Carbon\Carbon;
use Intervention\Image\Facades\Image;
use DB;
use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Input;
use Intervention\Image\Facades\Image;
use League\Csv\Reader;
use League\Csv\Statement;
use Paginator;
@@ -40,9 +41,8 @@ use View;
*/
class AssetsController extends Controller
{
protected $qrCodeDimensions = array( 'height' => 3.5, 'width' => 3.5);
protected $barCodeDimensions = array( 'height' => 2, 'width' => 22);
protected $qrCodeDimensions = ['height' => 3.5, 'width' => 3.5];
protected $barCodeDimensions = ['height' => 2, 'width' => 22];
public function __construct()
{
@@ -65,6 +65,7 @@ class AssetsController extends Controller
{
$this->authorize('index', Asset::class);
$company = Company::find($request->input('company_id'));
return view('hardware/index')->with('company', $company);
}
@@ -89,6 +90,7 @@ class AssetsController extends Controller
$selected_model = AssetModel::find($request->input('model_id'));
$view->with('selected_model', $selected_model);
}
return $view;
}
@@ -114,18 +116,17 @@ class AssetsController extends Controller
$serials = $request->input('serials');
for ($a = 1; $a <= count($asset_tags); $a++) {
$asset = new Asset();
$asset->model()->associate(AssetModel::find($request->input('model_id')));
$asset->name = $request->input('name');
$asset->name = $request->input('name');
// Check for a corresponding serial
if (($serials) && (array_key_exists($a, $serials))) {
$asset->serial = $serials[$a];
$asset->serial = $serials[$a];
}
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
$asset->asset_tag = $asset_tags[$a];
$asset->asset_tag = $asset_tags[$a];
}
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
@@ -145,11 +146,11 @@ class AssetsController extends Controller
$asset->requestable = request('requestable', 0);
$asset->rtd_location_id = request('rtd_location_id', null);
if (!empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
if (! empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
}
if ($asset->assigned_to=='') {
if ($asset->assigned_to == '') {
$asset->location_id = $request->input('rtd_location_id', null);
}
@@ -164,17 +165,18 @@ class AssetsController extends Controller
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted=='1') {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if(is_array($request->input($field->convertUnicodeDbSlug()))){
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
}else{
} else {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
} }
}
}
} else {
if(is_array($request->input($field->convertUnicodeDbSlug()))){
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
}else{
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
@@ -183,7 +185,6 @@ class AssetsController extends Controller
// Validate the asset before saving
if ($asset->isValid() && $asset->save()) {
if (request('assigned_user')) {
$target = User::find(request('assigned_user'));
$location = $target->location_id;
@@ -196,14 +197,11 @@ class AssetsController extends Controller
}
if (isset($target)) {
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', e($request->get('name')), $location);
$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);
}
$success = true;
}
}
if ($success) {
@@ -213,7 +211,6 @@ class AssetsController extends Controller
}
return redirect()->back()->withInput()->withErrors($asset->getErrors());
}
/**
@@ -226,7 +223,7 @@ class AssetsController extends Controller
*/
public function edit($assetId = null)
{
if (!$item = Asset::find($assetId)) {
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'));
}
@@ -262,17 +259,17 @@ class AssetsController extends Controller
if ($asset->location) {
$use_currency = $asset->location->currency;
} else {
if ($settings->default_currency!='') {
if ($settings->default_currency != '') {
$use_currency = $settings->default_currency;
} else {
$use_currency = trans('general.currency');
}
}
$qr_code = (object) array(
$qr_code = (object) [
'display' => $settings->qr_code == '1',
'url' => route('qr_code/hardware', $asset->id)
);
'url' => route('qr_code/hardware', $asset->id),
];
return view('hardware/view', compact('asset', 'qr_code', 'settings'))
->with('use_currency', $use_currency)->with('audit_log', $audit_log);
@@ -281,7 +278,6 @@ class AssetsController extends Controller
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
/**
* Validate and process asset edit form.
*
@@ -290,11 +286,10 @@ class AssetsController extends Controller
* @since [v1.0]
* @return Redirect
*/
public function update(ImageUploadRequest $request, $assetId = null)
{
// Check if the asset exists
if (!$asset = Asset::find($assetId)) {
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'));
}
@@ -311,7 +306,7 @@ class AssetsController extends Controller
$asset->requestable = $request->filled('requestable');
$asset->rtd_location_id = $request->input('rtd_location_id', null);
if ($asset->assigned_to=='') {
if ($asset->assigned_to == '') {
$asset->location_id = $request->input('rtd_location_id', null);
}
@@ -323,21 +318,19 @@ class AssetsController extends Controller
} catch (\Exception $e) {
\Log::info($e);
}
}
// Update the asset data
$asset_tag = $request->input('asset_tags');
$serial = $request->input('serials');
$asset->name = $request->input('name');
$asset->serial = $serial[1];
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$asset->model_id = $request->input('model_id');
$asset_tag = $request->input('asset_tags');
$serial = $request->input('serials');
$asset->name = $request->input('name');
$asset->serial = $serial[1];
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->asset_tag = $asset_tag[1];
$asset->notes = $request->input('notes');
$asset->physical = '1';
$asset->asset_tag = $asset_tag[1];
$asset->notes = $request->input('notes');
$asset->physical = '1';
$asset = $request->handleImages($asset);
@@ -348,18 +341,18 @@ class AssetsController extends Controller
$model = AssetModel::find($request->get('model_id'));
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted=='1') {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if(is_array($request->input($field->convertUnicodeDbSlug()))){
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
}else{
} else {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
}
}
} else {
if(is_array($request->input($field->convertUnicodeDbSlug()))){
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
}else{
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
@@ -368,7 +361,7 @@ class AssetsController extends Controller
if ($asset->save()) {
return redirect()->route("hardware.show", $assetId)
return redirect()->route('hardware.show', $assetId)
->with('success', trans('admin/hardware/message.update.success'));
}
@@ -395,10 +388,10 @@ class AssetsController extends Controller
DB::table('assets')
->where('id', $asset->id)
->update(array('assigned_to' => null));
->update(['assigned_to' => null]);
if ($asset->image) {
try {
try {
Storage::disk('public')->delete('assets'.'/'.$asset->image);
} catch (\Exception $e) {
\Log::debug($e);
@@ -410,7 +403,23 @@ class AssetsController extends Controller
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
}
/**
* Searches the assets table by serial, and redirects if it finds one
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function getAssetBySerial(Request $request)
{
$topsearch = ($request->get('topsearch')=="true");
if (!$asset = Asset::where('serial', '=', $request->get('serial'))->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('view', $asset);
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
}
/**
* Searches the assets table by asset tag, and redirects if it finds one
@@ -421,14 +430,17 @@ class AssetsController extends Controller
*/
public function getAssetByTag(Request $request)
{
$topsearch = ($request->get('topsearch')=="true");
$topsearch = ($request->get('topsearch') == 'true');
if (!$asset = Asset::where('asset_tag', '=', $request->get('assetTag'))->first()) {
if (! $asset = Asset::where('asset_tag', '=', $request->get('assetTag'))->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('view', $asset);
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
}
/**
* Return a QR code for the asset
*
@@ -450,20 +462,22 @@ class AssetsController extends Controller
if (isset($asset->id, $asset->asset_tag)) {
if (file_exists($qr_file)) {
$header = ['Content-type' => 'image/png'];
return response()->file($qr_file, $header);
} else {
$barcode = new \Com\Tecnick\Barcode\Barcode();
$barcode_obj = $barcode->getBarcodeObj($settings->barcode_type, route('hardware.show', $asset->id), $size['height'], $size['width'], 'black', array(-2, -2, -2, -2));
$barcode_obj = $barcode->getBarcodeObj($settings->barcode_type, route('hardware.show', $asset->id), $size['height'], $size['width'], 'black', [-2, -2, -2, -2]);
file_put_contents($qr_file, $barcode_obj->getPngData());
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
}
}
}
return 'That asset is invalid';
}
}
/**
* Return a 2D barcode for the asset
*
@@ -481,6 +495,7 @@ class AssetsController extends Controller
if (isset($asset->id, $asset->asset_tag)) {
if (file_exists($barcode_file)) {
$header = ['Content-type' => 'image/png'];
return response()->file($barcode_file, $header);
} else {
// Calculate barcode width in pixel based on label width (inch)
@@ -488,20 +503,19 @@ class AssetsController extends Controller
$barcode = new \Com\Tecnick\Barcode\Barcode();
try {
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode,$asset->asset_tag,($barcode_width < 300 ? $barcode_width : 300),50);
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode, $asset->asset_tag, ($barcode_width < 300 ? $barcode_width : 300), 50);
file_put_contents($barcode_file, $barcode_obj->getPngData());
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
} catch(\Exception $e) {
} catch (\Exception $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');
}
}
}
}
/**
* Return a label for an individual asset.
*
@@ -523,7 +537,6 @@ class AssetsController extends Controller
}
}
/**
* Returns a view that presents a form to clone an asset.
*
@@ -564,6 +577,7 @@ class AssetsController extends Controller
public function getImportHistory()
{
$this->authorize('admin');
return view('hardware/history');
}
@@ -572,49 +586,48 @@ class AssetsController extends Controller
*
* This needs a LOT of love. It's done very inelegantly right now, and there are
* a ton of optimizations that could (and should) be done.
*
*
* Updated to respect checkin dates:
* No checkin column, assume all items are checked in (todays date)
* Checkin date in the past, update history.
* Checkin date in future or empty, check the item out to the user.
*
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.3]
* @return View
*/
public function postImportHistory(Request $request)
{
if (!$request->hasFile('user_import_csv')) {
if (! $request->hasFile('user_import_csv')) {
return back()->with('error', 'No file provided. Please select a file for import and try again. ');
}
if (!ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
if (! ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
$csv = Reader::createFromPath($request->file('user_import_csv'));
$csv->setHeaderOffset(0);
$header = $csv->getHeader();
$isCheckinHeaderExplicit = in_array("checkin date", (array_map('strtolower', $header)));
$isCheckinHeaderExplicit = in_array('checkin date', (array_map('strtolower', $header)));
$results = $csv->getRecords();
$item = array();
$status = array();
$status['error'] = array();
$status['success'] = array();
$item = [];
$status = [];
$status['error'] = [];
$status['success'] = [];
foreach ($results as $row) {
if (is_array($row)) {
$row = array_change_key_case($row, CASE_LOWER);
$asset_tag = Helper::array_smart_fetch($row, "asset tag");
if (!array_key_exists($asset_tag, $item)) {
$item[$asset_tag] = array();
$asset_tag = Helper::array_smart_fetch($row, 'asset tag');
if (! array_key_exists($asset_tag, $item)) {
$item[$asset_tag] = [];
}
$batch_counter = count($item[$asset_tag]);
$item[$asset_tag][$batch_counter]['checkout_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkout date"))->format('Y-m-d H:i:s');
if ($isCheckinHeaderExplicit){
$item[$asset_tag][$batch_counter]['checkout_date'] = Carbon::parse(Helper::array_smart_fetch($row, 'checkout date'))->format('Y-m-d H:i:s');
if ($isCheckinHeaderExplicit) {
//checkin date not empty, assume past transaction or future checkin date (expected)
if (!empty(Helper::array_smart_fetch($row, "checkin date"))) {
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkin date"))->format('Y-m-d H:i:s');
if (! empty(Helper::array_smart_fetch($row, 'checkin date'))) {
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, 'checkin date'))->format('Y-m-d H:i:s');
} else {
$item[$asset_tag][$batch_counter]['checkin_date'] = '';
}
@@ -623,44 +636,44 @@ class AssetsController extends Controller
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(now())->format('Y-m-d H:i:s');
}
$item[$asset_tag][$batch_counter]['asset_tag'] = Helper::array_smart_fetch($row, "asset tag");
$item[$asset_tag][$batch_counter]['name'] = Helper::array_smart_fetch($row, "name");
$item[$asset_tag][$batch_counter]['email'] = Helper::array_smart_fetch($row, "email");
$item[$asset_tag][$batch_counter]['asset_tag'] = Helper::array_smart_fetch($row, 'asset tag');
$item[$asset_tag][$batch_counter]['name'] = Helper::array_smart_fetch($row, 'name');
$item[$asset_tag][$batch_counter]['email'] = Helper::array_smart_fetch($row, 'email');
if ($asset = Asset::where('asset_tag', '=', $asset_tag)->first()) {
$item[$asset_tag][$batch_counter]['asset_id'] = $asset->id;
$base_username = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $item[$asset_tag][$batch_counter]['name']);
$user = User::where('username', '=', $base_username['username']);
$user_query = ' on username '.$base_username['username'];
if ($request->input('match_firstnamelastname')=='1') {
if ($request->input('match_firstnamelastname') == '1') {
$firstnamedotlastname = User::generateFormattedNameFromFullName('firstname.lastname', $item[$asset_tag][$batch_counter]['name']);
$item[$asset_tag][$batch_counter]['username'][] = $firstnamedotlastname['username'];
$user->orWhere('username', '=', $firstnamedotlastname['username']);
$user_query .= ', or on username '.$firstnamedotlastname['username'];
}
if ($request->input('match_flastname')=='1') {
if ($request->input('match_flastname') == '1') {
$flastname = User::generateFormattedNameFromFullName('filastname', $item[$asset_tag][$batch_counter]['name']);
$item[$asset_tag][$batch_counter]['username'][] = $flastname['username'];
$user->orWhere('username', '=', $flastname['username']);
$user_query .= ', or on username '.$flastname['username'];
}
if ($request->input('match_firstname')=='1') {
if ($request->input('match_firstname') == '1') {
$firstname = User::generateFormattedNameFromFullName('firstname', $item[$asset_tag][$batch_counter]['name']);
$item[$asset_tag][$batch_counter]['username'][] = $firstname['username'];
$user->orWhere('username', '=', $firstname['username']);
$user_query .= ', or on username '.$firstname['username'];
}
if ($request->input('match_email')=='1') {
if ($item[$asset_tag][$batch_counter]['name']=='') {
if ($request->input('match_email') == '1') {
if ($item[$asset_tag][$batch_counter]['name'] == '') {
$item[$asset_tag][$batch_counter]['username'][] = $user_email = User::generateEmailFromFullName($item[$asset_tag][$batch_counter]['name']);
$user->orWhere('username', '=', $user_email);
$user_query .= ', or on username '.$user_email;
}
}
if ($request->input('match_username') == '1'){
if ($request->input('match_username') == '1') {
// Added #8825: add explicit username lookup
$raw_username = $item[$asset_tag][$batch_counter]['name'];
$user->orWhere('username', '=', $raw_username);
$user_query .= ', or on username ' . $raw_username;
$raw_username = $item[$asset_tag][$batch_counter]['name'];
$user->orWhere('username', '=', $raw_username);
$user_query .= ', or on username '.$raw_username;
}
// A matching user was found
@@ -668,7 +681,7 @@ class AssetsController extends Controller
//$user is now matched user from db
$item[$asset_tag][$batch_counter]['user_id'] = $user->id;
Actionlog::firstOrCreate(array(
Actionlog::firstOrCreate([
'item_id' => $asset->id,
'item_type' => Asset::class,
'user_id' => Auth::user()->id,
@@ -677,7 +690,7 @@ class AssetsController extends Controller
'target_type' => User::class,
'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'],
'action_type' => 'checkout',
));
]);
$checkin_date = $item[$asset_tag][$batch_counter]['checkin_date'];
@@ -685,7 +698,7 @@ class AssetsController extends Controller
//if checkin date header exists, assume that empty or future date is still checked out
//if checkin is before todays date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items is checked out
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date))
) {
//only do this if item is checked out
@@ -694,29 +707,27 @@ class AssetsController extends Controller
}
}
if (!empty($checkin_date)) {
if (! empty($checkin_date)) {
//only make a checkin there is a valid checkin date or we created one on import.
Actionlog::firstOrCreate(array(
'item_id' =>
$item[$asset_tag][$batch_counter]['asset_id'],
Actionlog::firstOrCreate([
'item_id' => $item[$asset_tag][$batch_counter]['asset_id'],
'item_type' => Asset::class,
'user_id' => Auth::user()->id,
'note' => 'Checkin imported by ' . Auth::user()->present()->fullName() . ' from history importer',
'note' => 'Checkin imported by '.Auth::user()->present()->fullName().' from history importer',
'target_id' => null,
'created_at' => $checkin_date,
'action_type' => 'checkin'
));
'action_type' => 'checkin',
]);
}
if ($asset->save()) {
$status['success'][]['asset'][$asset_tag]['msg'] = 'Asset successfully matched for '.Helper::array_smart_fetch($row, "name").$user_query.' on '.$item[$asset_tag][$batch_counter]['checkout_date'];
$status['success'][]['asset'][$asset_tag]['msg'] = 'Asset successfully matched for '.Helper::array_smart_fetch($row, 'name').$user_query.' on '.$item[$asset_tag][$batch_counter]['checkout_date'];
} else {
$status['error'][]['asset'][$asset_tag]['msg'] = 'Asset and user was matched but could not be saved.';
}
} else {
$item[$asset_tag][$batch_counter]['user_id'] = null;
$status['error'][]['user'][Helper::array_smart_fetch($row, "name")]['msg'] = 'User does not exist so no checkin log was created.';
$status['error'][]['user'][Helper::array_smart_fetch($row, 'name')]['msg'] = 'User does not exist so no checkin log was created.';
}
} else {
$item[$asset_tag][$batch_counter]['asset_id'] = null;
@@ -724,6 +735,7 @@ class AssetsController extends Controller
}
}
}
return view('hardware/history')->with('status', $status);
}
@@ -752,12 +764,13 @@ class AssetsController extends Controller
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = Auth::user()->id;
$logaction->logaction('restored');
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
@@ -765,10 +778,16 @@ class AssetsController extends Controller
{
$this->authorize('audit', Asset::class);
$dt = Carbon::now()->addMonths(12)->toDateString();
return view('hardware/quickscan')->with('next_audit_date', $dt);
}
public function quickScanCheckin()
{
$this->authorize('checkin', Asset::class);
return view('hardware/quickscan-checkin');
}
public function audit($id)
{
@@ -776,18 +795,21 @@ class AssetsController extends Controller
$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');
}
public function dueForAudit()
{
$this->authorize('audit', Asset::class);
return view('hardware/audit-due');
}
public function overdueForAudit()
{
$this->authorize('audit', Asset::class);
return view('hardware/audit-overdue');
}
@@ -796,10 +818,10 @@ class AssetsController extends Controller
{
$this->authorize('audit', Asset::class);
$rules = array(
$rules = [
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable'
);
'next_audit_date' => 'date|nullable',
];
$validator = \Validator::make($request->all(), $rules);
@@ -817,7 +839,7 @@ class AssetsController extends Controller
// Check to see if they checked the box to update the physical location,
// not just note it in the audit notes
if ($request->input('update_location')=='1') {
if ($request->input('update_location') == '1') {
\Log::debug('update location in audit');
$asset->location_id = $request->input('location_id');
}
@@ -828,7 +850,9 @@ class AssetsController extends Controller
// Upload an image, if attached
if ($request->hasFile('image')) {
$path = 'private_uploads/audits';
if (!Storage::exists($path)) Storage::makeDirectory($path, 775);
if (! Storage::exists($path)) {
Storage::makeDirectory($path, 775);
}
$upload = $image = $request->file('image');
$ext = $image->getClientOriginalExtension();
$file_name = 'audit-'.str_random(18).'.'.$ext;
@@ -837,7 +861,7 @@ class AssetsController extends Controller
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success'));
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.audit.success'));
}
}
@@ -853,5 +877,4 @@ class AssetsController extends Controller
return view('hardware/requested', compact('requestedItems'));
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Assets;
use App\Models\Actionlog;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
@@ -28,15 +29,15 @@ class BulkAssetsController extends Controller
{
$this->authorize('update', Asset::class);
if (!$request->filled('ids')) {
if (! $request->filled('ids')) {
return redirect()->back()->with('error', 'No assets selected');
}
$asset_ids = array_values(array_unique($request->input('ids')));
if ($request->filled('bulk_actions')) {
switch($request->input('bulk_actions')) {
switch ($request->input('bulk_actions')) {
case 'labels':
return view('hardware/labels')
->with('assets', Asset::find($asset_ids))
@@ -48,6 +49,7 @@ class BulkAssetsController extends Controller
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
return view('hardware/bulk-delete')->with('assets', $assets);
case 'edit':
return view('hardware/bulk')
@@ -55,6 +57,7 @@ class BulkAssetsController extends Controller
->with('statuslabel_list', Helper::statusLabelList());
}
}
return redirect()->back()->with('error', 'No action selected');
}
@@ -72,8 +75,8 @@ class BulkAssetsController extends Controller
\Log::debug($request->input('ids'));
if(!$request->filled('ids') || count($request->input('ids')) <= 0) {
return redirect()->route("hardware.index")->with('warning', trans('No assets selected, so nothing was updated.'));
if (! $request->filled('ids') || count($request->input('ids')) <= 0) {
return redirect()->route('hardware.index')->with('warning', trans('No assets selected, so nothing was updated.'));
}
$assets = array_keys($request->input('ids'));
@@ -108,8 +111,8 @@ class BulkAssetsController extends Controller
}
if ($request->filled('company_id')) {
$this->update_array['company_id'] = $request->input('company_id');
if ($request->input('company_id')=="clear") {
$this->update_array['company_id'] = $request->input('company_id');
if ($request->input('company_id') == 'clear') {
$this->update_array['company_id'] = null;
}
}
@@ -121,33 +124,53 @@ class BulkAssetsController extends Controller
}
}
$changed = [];
$asset = Asset::where('id' ,$assetId)->get();
foreach ($this->update_array as $key => $value) {
if ($this->update_array[$key] != $asset->toArray()[0][$key]) {
$changed[$key]['old'] = $asset->toArray()[0][$key];
$changed[$key]['new'] = $this->update_array[$key];
}
}
$logAction = new Actionlog();
$logAction->item_type = Asset::class;
$logAction->item_id = $assetId;
$logAction->created_at = date("Y-m-d H:i:s");
$logAction->user_id = Auth::id();
$logAction->log_meta = json_encode($changed);
$logAction->logaction('update');
DB::table('assets')
->where('id', $assetId)
->update($this->update_array);
} // endforeach
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.update.success'));
// no values given, nothing to update
}
return redirect()->route("hardware.index")->with('warning', trans('admin/hardware/message.update.nothing_updated'));
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.update.success'));
// no values given, nothing to update
}
return redirect()->route('hardware.index')->with('warning', trans('admin/hardware/message.update.nothing_updated'));
}
/**
* Array to store update data per item
* @var Array
* @var array
*/
private $update_array;
/**
* Adds parameter to update array for an item if it exists in request
* @param String $field field name
* @param string $field field name
* @return BulkAssetsController Model for Chaining
*/
protected function conditionallyAddItem($field)
{
if(request()->filled($field)) {
if (request()->filled($field)) {
$this->update_array[$field] = request()->input($field);
}
return $this;
}
@@ -175,10 +198,12 @@ class BulkAssetsController extends Controller
->where('id', $asset->id)
->update($update_array);
} // endforeach
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.delete.success'));
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.delete.success'));
// no values given, nothing to update
}
return redirect()->to("hardware")->with('info', trans('admin/hardware/message.delete.nothing_updated'));
return redirect()->to('hardware')->with('info', trans('admin/hardware/message.delete.nothing_updated'));
}
/**
@@ -204,21 +229,21 @@ class BulkAssetsController extends Controller
$target = $this->determineCheckoutTarget();
if (!is_array($request->get('selected_assets'))) {
if (! is_array($request->get('selected_assets'))) {
return redirect()->route('hardware/bulkcheckout')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
}
$asset_ids = array_filter($request->get('selected_assets'));
if(request('checkout_to_type') =='asset') {
if (request('checkout_to_type') == 'asset') {
foreach ($asset_ids as $asset_id) {
if ($target->id == $asset_id) {
if ($target->id == $asset_id) {
return redirect()->back()->with('error', 'You cannot check an asset out to itself.');
}
}
}
$checkout_at = date("Y-m-d H:i:s");
if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
$checkout_at = date('Y-m-d H:i:s');
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
$checkout_at = e($request->get('checkout_at'));
}
@@ -230,13 +255,12 @@ class BulkAssetsController extends Controller
$errors = [];
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, $errors, $asset_ids, $request) {
foreach ($asset_ids as $asset_id) {
$asset = Asset::findOrFail($asset_id);
$this->authorize('checkout', $asset);
$error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), null);
if ($target->location_id!='') {
if ($target->location_id != '') {
$asset->location_id = $target->location_id;
$asset->unsetEventDispatcher();
$asset->save();
@@ -248,14 +272,14 @@ class BulkAssetsController extends Controller
}
});
if (!$errors) {
// Redirect to the new asset page
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.checkout.success'));
if (! $errors) {
// Redirect to the new asset page
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.checkout.success'));
}
// Redirect to the asset management page with error
return redirect()->to("hardware/bulk-checkout")->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
return redirect()->to('hardware/bulk-checkout')->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
} catch (ModelNotFoundException $e) {
return redirect()->to("hardware/bulk-checkout")->with('error', $e->getErrors());
return redirect()->to('hardware/bulk-checkout')->with('error', $e->getErrors());
}
}
}

View File

@@ -42,8 +42,6 @@ class ForgotPasswordController extends Controller
return property_exists($this, 'subject') ? $this->subject : \Lang::get('mail.reset_link');
}
/**
* Send a reset link to the given user.
*
@@ -58,13 +56,10 @@ class ForgotPasswordController extends Controller
* buffer overflow issues with attackers sending very large
* payloads through.
*/
$request->validate([
'username' => ['required', 'max:255'],
]);
/**
* If we find a matching email with an activated user, we will
* send the password reset link to the user.
@@ -87,6 +82,8 @@ class ForgotPasswordController extends Controller
\Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
}
// Prevent timing attack to enumerate users.
usleep(500000 + random_int(0, 1500000));
if ($response === \Password::RESET_LINK_SENT) {
\Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');
@@ -94,7 +91,6 @@ class ForgotPasswordController extends Controller
\Log::info('Password reset attempt: User matching username '.$request->input('username').' NOT FOUND or user is inactive');
}
/**
* If an error was returned by the password broker, we will get this message
* translated so we can notify a user of the problem. We'll redirect back
@@ -110,8 +106,6 @@ class ForgotPasswordController extends Controller
// Regardless of response, we do not want to disclose the status of a user account,
// so we give them a generic "If this exists, we're TOTALLY gonna email you" response
return redirect()->route('login')->with('success',trans('passwords.sent'));
return redirect()->route('login')->with('success', trans('passwords.sent'));
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Setting;
use App\Models\User;
use App\Services\LdapAd;
use App\Models\Ldap;
use App\Services\Saml;
use Com\Tecnick\Barcode\Barcode;
use Google2FA;
@@ -27,7 +27,6 @@ use Redirect;
*/
class LoginController extends Controller
{
use ThrottlesLogins;
// This tells the auth controller to use username instead of email address
@@ -40,11 +39,6 @@ class LoginController extends Controller
*/
protected $redirectTo = '/';
/**
* @var LdapAd
*/
protected $ldap;
/**
* @var Saml
*/
@@ -53,21 +47,20 @@ class LoginController extends Controller
/**
* Create a new authentication controller instance.
*
* @param LdapAd $ldap
* @param Saml $saml
*
* @return void
*/
public function __construct(/*LdapAd $ldap, */ Saml $saml)
public function __construct(Saml $saml)
{
parent::__construct();
$this->middleware('guest', ['except' => ['logout','postTwoFactorAuth','getTwoFactorAuth','getTwoFactorEnroll']]);
$this->middleware('guest', ['except' => ['logout', 'postTwoFactorAuth', 'getTwoFactorAuth', 'getTwoFactorEnroll']]);
Session::put('backUrl', \URL::previous());
// $this->ldap = $ldap;
$this->saml = $saml;
}
function showLoginForm(Request $request)
public function showLoginForm(Request $request)
{
$this->loginViaRemoteUser($request);
$this->loginViaSaml($request);
@@ -75,11 +68,18 @@ class LoginController extends Controller
return redirect()->intended('/');
}
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == "1" && !($request->has('nosaml') || $request->session()->has('error'))) {
// If the environment is set to ALWAYS require SAML, go straight to the SAML route.
// We don't need to check other settings, as this should override those.
if (config('app.require_saml')) {
return redirect()->route('saml.login');
}
if (Setting::getSettings()->login_common_disabled == "1") {
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == '1' && ! ($request->has('nosaml') || $request->session()->has('error'))) {
return redirect()->route('saml.login');
}
if (Setting::getSettings()->login_common_disabled == '1') {
return view('errors.403');
}
@@ -88,26 +88,26 @@ class LoginController extends Controller
/**
* Log in a user by SAML
*
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return User
*
*
* @throws \Exception
*/
private function loginViaSaml(Request $request)
{
$saml = $this->saml;
$samlData = $request->session()->get('saml_login');
if ($saml->isEnabled() && !empty($samlData)) {
if ($saml->isEnabled() && ! empty($samlData)) {
try {
Log::debug("Attempting to log user in by SAML authentication.");
Log::debug('Attempting to log user in by SAML authentication.');
$user = $saml->samlLogin($samlData);
if(!is_null($user)) {
if (! is_null($user)) {
Auth::login($user);
} else {
$username = $saml->getUsername();
@@ -121,7 +121,7 @@ class LoginController extends Controller
$user->save();
}
} catch (\Exception $e) {
\Log::warning("There was an error authenticating the SAML user: " . $e->getMessage());
\Log::warning('There was an error authenticating the SAML user: '.$e->getMessage());
throw new \Exception($e->getMessage());
}
}
@@ -129,33 +129,70 @@ class LoginController extends Controller
/**
* Log in a user by LDAP
*
*
* @author Wes Hulette <jwhulette@gmail.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return User
*
*
* @throws \Exception
*/
private function loginViaLdap(Request $request): User
{
$ldap = \App::make( LdapAd::class);
try {
return $ldap->ldapLogin($request->input('username'), $request->input('password'));
} catch (\Exception $ex) {
LOG::debug("LDAP user login: " . $ex->getMessage());
throw new \Exception($ex->getMessage());
}
Log::debug("Binding user to LDAP.");
$ldap_user = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password'));
if (!$ldap_user) {
Log::debug("LDAP user ".$request->input('username')." not found in LDAP or could not bind");
throw new \Exception("Could not find user in LDAP directory");
} else {
Log::debug("LDAP user ".$request->input('username')." successfully bound to LDAP");
}
// Check if the user already exists in the database and was imported via LDAP
$user = User::where('username', '=', $request->input('username'))->whereNull('deleted_at')->where('ldap_import', '=', 1)->where('activated', '=', '1')->first(); // FIXME - if we get more than one we should fail. and we sure about this ldap_import thing?
Log::debug("Local auth lookup complete");
// The user does not exist in the database. Try to get them from LDAP.
// If user does not exist and authenticates successfully with LDAP we
// will create it on the fly and sign in with default permissions
if (!$user) {
Log::debug("Local user ".$request->input('username')." does not exist");
Log::debug("Creating local user ".$request->input('username'));
if ($user = Ldap::createUserFromLdap($ldap_user)) { //this handles passwords on its own
Log::debug("Local user created.");
} else {
Log::debug("Could not create local user.");
throw new \Exception("Could not create local user");
}
// If the user exists and they were imported from LDAP already
} else {
Log::debug("Local user ".$request->input('username')." exists in database. Updating existing user against LDAP.");
$ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user);
if (Setting::getSettings()->ldap_pw_sync=='1') {
$user->password = bcrypt($request->input('password'));
}
$user->email = $ldap_attr['email'];
$user->first_name = $ldap_attr['firstname'];
$user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc.
$user->save();
} // End if(!user)
return $user;
}
private function loginViaRemoteUser(Request $request)
{
$header_name = Setting::getSettings()->login_remote_user_header_name ?: 'REMOTE_USER';
$remote_user = $request->server($header_name);
if (Setting::getSettings()->login_remote_user_enabled == "1" && isset($remote_user) && !empty($remote_user)) {
if (!isset($remote_user)) {
$remote_user = $request->server('REDIRECT_'.$header_name);
}
if (Setting::getSettings()->login_remote_user_enabled == '1' && isset($remote_user) && ! empty($remote_user)) {
Log::debug("Authenticating via HTTP header $header_name.");
$strip_prefixes = [
@@ -170,7 +207,7 @@ class LoginController extends Controller
$pos = 0;
foreach ($strip_prefixes as $needle) {
if (($pos = strpos($remote_user, $needle)) !== FALSE) {
if (($pos = strpos($remote_user, $needle)) !== false) {
$pos += strlen($needle);
break;
}
@@ -178,14 +215,16 @@ class LoginController extends Controller
if ($pos > 0) {
$remote_user = substr($remote_user, $pos);
};
}
try {
$user = User::where('username', '=', $remote_user)->whereNull('deleted_at')->where('activated', '=', '1')->first();
Log::debug("Remote user auth lookup complete");
if(!is_null($user)) Auth::login($user, $request->input('remember'));
} catch(Exception $e) {
Log::debug("There was an error authenticating the Remote user: " . $e->getMessage());
Log::debug('Remote user auth lookup complete');
if (! is_null($user)) {
Auth::login($user, $request->input('remember'));
}
} catch (Exception $e) {
Log::debug('There was an error authenticating the Remote user: '.$e->getMessage());
}
}
}
@@ -197,7 +236,13 @@ class LoginController extends Controller
*/
public function login(Request $request)
{
if (Setting::getSettings()->login_common_disabled == "1") {
//If the environment is set to ALWAYS require SAML, return access denied
if (config('app.require_saml')) {
return view('errors.403');
}
if (Setting::getSettings()->login_common_disabled == '1') {
return view('errors.403');
}
@@ -212,6 +257,7 @@ class LoginController extends Controller
if ($lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
@@ -219,34 +265,33 @@ class LoginController extends Controller
// Should we even check for LDAP users?
if (Setting::getSettings()->ldap_enabled) { // avoid hitting the $this->ldap
LOG::debug("LDAP is enabled.");
LOG::debug('LDAP is enabled.');
try {
LOG::debug("Attempting to log user in by LDAP authentication.");
LOG::debug('Attempting to log user in by LDAP authentication.');
$user = $this->loginViaLdap($request);
Auth::login($user, $request->input('remember'));
// If the user was unable to login via LDAP, log the error and let them fall through to
// If the user was unable to login via LDAP, log the error and let them fall through to
// local authentication.
} catch (\Exception $e) {
Log::debug("There was an error authenticating the LDAP user: ".$e->getMessage());
Log::debug('There was an error authenticating the LDAP user: '.$e->getMessage());
}
}
// If the user wasn't authenticated via LDAP, skip to local auth
if (!$user) {
Log::debug("Authenticating user against database.");
// Try to log the user in
if (!Auth::attempt(['username' => $request->input('username'), 'password' => $request->input('password'), 'activated' => 1], $request->input('remember'))) {
if (!$lockedOut) {
if (! $user) {
Log::debug('Authenticating user against database.');
// Try to log the user in
if (! Auth::attempt(['username' => $request->input('username'), 'password' => $request->input('password'), 'activated' => 1], $request->input('remember'))) {
if (! $lockedOut) {
$this->incrementLoginAttempts($request);
}
Log::debug("Local authentication failed.");
Log::debug('Local authentication failed.');
return redirect()->back()->withInput()->with('error', trans('auth/message.account_not_found'));
} else {
$this->clearLoginAttempts($request);
$this->clearLoginAttempts($request);
}
}
@@ -269,11 +314,10 @@ class LoginController extends Controller
{
// Make sure the user is logged in
if (!Auth::check()) {
if (! Auth::check()) {
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
$settings = Setting::getSettings();
$user = Auth::user();
@@ -283,7 +327,7 @@ class LoginController extends Controller
// While you can access this page directly, enrolling a device when 2FA isn't enforced
// won't cause any harm.
if (($user->two_factor_secret!='') && ($user->two_factor_enrolled==1)) {
if (($user->two_factor_secret != '') && ($user->two_factor_enrolled == 1)) {
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.already_enrolled'));
}
@@ -310,7 +354,6 @@ class LoginController extends Controller
return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj);
}
/**
* Two factor code form page
*
@@ -319,7 +362,7 @@ class LoginController extends Controller
public function getTwoFactorAuth()
{
// Check that the user is logged in
if (!Auth::check()) {
if (! Auth::check()) {
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
@@ -328,7 +371,7 @@ class LoginController extends Controller
// Check whether there is a device enrolled.
// This *should* be handled via the \App\Http\Middleware\CheckForTwoFactor middleware
// but we're just making sure (in case someone edited the database directly, etc)
if (($user->two_factor_secret=='') || ($user->two_factor_enrolled!=1)) {
if (($user->two_factor_secret == '') || ($user->two_factor_enrolled != 1)) {
return redirect()->route('two-factor-enroll');
}
@@ -344,16 +387,15 @@ class LoginController extends Controller
*/
public function postTwoFactorAuth(Request $request)
{
if (!Auth::check()) {
if (! Auth::check()) {
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
if (!$request->filled('two_factor_secret')) {
if (! $request->filled('two_factor_secret')) {
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
}
if (!$request->has('two_factor_secret')) {
if (! $request->has('two_factor_secret')) {
return redirect()->route('two-factor')->with('error', 'Two-factor code is required.');
}
@@ -363,13 +405,12 @@ class LoginController extends Controller
if (Google2FA::verifyKey($user->two_factor_secret, $secret)) {
$user->two_factor_enrolled = 1;
$user->save();
$request->session()->put('2fa_authed', 'true');
$request->session()->put('2fa_authed', $user->id);
return redirect()->route('home')->with('success', 'You are logged in!');
}
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
}
@@ -390,15 +431,15 @@ class LoginController extends Controller
if ($saml->isEnabled()) {
$auth = $saml->getAuth();
$sloRedirectUrl = $request->session()->get('saml_slo_redirect_url');
if (!empty($auth->getSLOurl()) && $settings->saml_slo == '1' && $saml->isAuthenticated() && empty($sloRedirectUrl)) {
$sloRequestUrl = $auth->logout(null, array(), $saml->getNameId(), $saml->getSessionIndex(), true, $saml->getNameIdFormat(), $saml->getNameIdNameQualifier(), $saml->getNameIdSPNameQualifier());
if (! empty($auth->getSLOurl()) && $settings->saml_slo == '1' && $saml->isAuthenticated() && empty($sloRedirectUrl)) {
$sloRequestUrl = $auth->logout(null, [], $saml->getNameId(), $saml->getSessionIndex(), true, $saml->getNameIdFormat(), $saml->getNameIdNameQualifier(), $saml->getNameIdSPNameQualifier());
}
$saml->clearData();
}
if (!empty($sloRequestUrl)) {
if (! empty($sloRequestUrl)) {
return redirect()->away($sloRequestUrl);
}
@@ -407,11 +448,11 @@ class LoginController extends Controller
$request->session()->regenerate(true);
Auth::logout();
if (!empty($sloRedirectUrl)) {
if (! empty($sloRedirectUrl)) {
return redirect()->away($sloRedirectUrl);
}
$customLogoutUrl = $settings->login_remote_user_custom_logout_url ;
$customLogoutUrl = $settings->login_remote_user_custom_logout_url;
if ($settings->login_remote_user_enabled == '1' && $customLogoutUrl != '') {
return redirect()->away($customLogoutUrl);
}
@@ -434,7 +475,6 @@ class LoginController extends Controller
]);
}
public function username()
{
return 'username';
@@ -461,7 +501,6 @@ class LoginController extends Controller
->withErrors([$this->username() => $message]);
}
/**
* Override the lockout time and duration
*
@@ -480,13 +519,13 @@ class LoginController extends Controller
);
}
public function legacyAuthRedirect() {
public function legacyAuthRedirect()
{
return redirect()->route('login');
}
public function redirectTo()
{
return Session::get('backUrl') ? Session::get('backUrl') : $this->redirectTo;
return Session::get('backUrl') ? Session::get('backUrl') : $this->redirectTo;
}
}

View File

@@ -6,17 +6,18 @@ use App\Http\Controllers\Controller;
class RegisterController extends Controller
{
public function __construct()
{
$this->middleware('guest');
}
public function showRegistrationForm() {
abort(404,'Page not found');
public function showRegistrationForm()
{
abort(404, 'Page not found');
}
public function register() {
abort(404,'Page not found');
public function register()
{
abort(404, 'Page not found');
}
}

View File

@@ -54,29 +54,25 @@ class ResetPasswordController extends Controller
];
}
protected function credentials(Request $request)
{
return $request->only(
'username', 'password', 'password_confirmation', 'token'
);
}
public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(
[
'token' => $token,
'username' => $request->input('username')
'username' => $request->input('username'),
]
);
}
public function reset(Request $request)
{
$messages = [
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
];
@@ -87,15 +83,13 @@ class ResetPasswordController extends Controller
$user = User::where('username', '=', $request->input('username'))->first();
$broker = $this->broker();
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== FALSE) {
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== false) {
$request->validate(
[
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"'
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"',
], $messages);
}
$response = $broker->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
@@ -107,14 +101,10 @@ class ResetPasswordController extends Controller
: $this->sendResetFailedResponse($request, $response);
}
protected function sendResetFailedResponse(Request $request, $response)
{
return redirect()->back()
->withInput(['username'=> $request->input('username')])
->withErrors(['username' => trans($response), 'password' => trans($response)]);
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Services\Saml;
use Illuminate\Http\Request;
use Log;
/**
@@ -30,20 +30,20 @@ class SamlController extends Controller
{
$this->saml = $saml;
$this->middleware('guest', ['except' => ['metadata','sls']]);
$this->middleware('guest', ['except' => ['metadata', 'sls']]);
}
/**
* Return SAML SP metadata for Snipe-IT
*
*
* /saml/metadata
*
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return Response
*/
public function metadata(Request $request)
@@ -53,7 +53,7 @@ class SamlController extends Controller
if (empty($metadata)) {
return response()->view('errors.403', [], 403);
}
return response()->streamDownload(function () use ($metadata) {
echo $metadata;
}, 'snipe-it-metadata.xml', ['Content-Type' => 'text/xml']);
@@ -61,36 +61,37 @@ class SamlController extends Controller
/**
* Begin the SP-Initiated SSO by sending AuthN to the IdP.
*
*
* /login/saml
*
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return Redirect
*/
public function login(Request $request)
{
$auth = $this->saml->getAuth();
$ssoUrl = $auth->login(null, array(), false, false, false, false);
$ssoUrl = $auth->login(null, [], false, false, false, false);
return redirect()->away($ssoUrl);
}
/**
* Receives, parses the assertion from IdP and flashes SAML data
* back to the LoginController for authentication.
*
*
* /saml/acs
*
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return Redirect
*/
public function acs(Request $request)
@@ -100,9 +101,10 @@ class SamlController extends Controller
$auth->processResponse();
$errors = $auth->getErrors();
if (!empty($errors)) {
Log::error("There was an error with SAML ACS: " . implode(', ', $errors));
Log::error("Reason: " . $auth->getLastErrorReason());
if (! empty($errors)) {
Log::error('There was an error with SAML ACS: '.implode(', ', $errors));
Log::error('Reason: '.$auth->getLastErrorReason());
return redirect()->route('login')->with('error', trans('auth/message.signin.error'));
}
@@ -114,15 +116,15 @@ class SamlController extends Controller
/**
* Receives LogoutRequest/LogoutResponse from IdP and flashes
* back to the LoginController for logging out.
*
*
* /saml/sls
*
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
*
* @since 5.0.0
*
* @param Request $request
*
*
* @return Redirect
*/
public function sls(Request $request)
@@ -131,10 +133,11 @@ class SamlController extends Controller
$retrieveParametersFromServer = $this->saml->getSetting('retrieveParametersFromServer', false);
$sloUrl = $auth->processSLO(true, null, $retrieveParametersFromServer, null, true);
$errors = $auth->getErrors();
if (!empty($errors)) {
Log::error("There was an error with SAML SLS: " . implode(', ', $errors));
Log::error("Reason: " . $auth->getLastErrorReason());
if (! empty($errors)) {
Log::error('There was an error with SAML SLS: '.implode(', ', $errors));
Log::error('Reason: '.$auth->getLastErrorReason());
return view('errors.403');
}

View File

@@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Redirect;
class BulkAssetModelsController extends Controller
{
/**
/**
* Returns a view that allows the user to bulk edit model attrbutes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
@@ -24,26 +24,28 @@ class BulkAssetModelsController extends Controller
// Make sure some IDs have been selected
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)
->withCount('assets as assets_count')
->orderBy('assets_count', 'ASC')
->get();
// If deleting....
if ($request->input('bulk_actions')=='delete') {
if ($request->input('bulk_actions') == 'delete') {
$this->authorize('delete', AssetModel::class);
$valid_count = 0;
foreach ($models as $model) {
if ($model->assets_count == 0) {
$valid_count++;
}
}
return view('models/bulk-delete', compact('models'))->with('valid_count', $valid_count);
// Otherwise display the bulk edit screen
// Otherwise display the bulk edit screen
}
$this->authorize('update', AssetModel::class);
$nochange = ['NC' => 'No Change'];
return view('models/bulk-edit', compact('models'))
->with('fieldset_list', $nochange + Helper::customFieldsetList())
->with('depreciation_list', $nochange + Helper::depreciationList());
@@ -63,34 +65,38 @@ class BulkAssetModelsController extends Controller
*/
public function update(Request $request)
{
$this->authorize('update', AssetModel::class);
$models_raw_array = $request->input('ids');
$update_array = array();
$update_array = [];
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) {
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id') != 'NC'))) {
$update_array['manufacturer_id'] = $request->input('manufacturer_id');
}
if (($request->filled('category_id') && ($request->input('category_id')!='NC'))) {
if (($request->filled('category_id') && ($request->input('category_id') != 'NC'))) {
$update_array['category_id'] = $request->input('category_id');
}
if ($request->input('fieldset_id')!='NC') {
if ($request->input('fieldset_id') != 'NC') {
$update_array['fieldset_id'] = $request->input('fieldset_id');
}
if ($request->input('depreciation_id')!='NC') {
if ($request->input('depreciation_id') != 'NC') {
$update_array['depreciation_id'] = $request->input('depreciation_id');
}
if ($request->filled('requestable') != '') {
$update_array['requestable'] = $request->input('requestable');
}
if (count($update_array) > 0) {
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
return redirect()->route('models.index')
->with('success', trans('admin/models/message.bulkedit.success'));
}
return redirect()->route('models.index')
->with('warning', trans('admin/models/message.bulkedit.error'));
}
/**
@@ -103,10 +109,11 @@ class BulkAssetModelsController extends Controller
*/
public function destroy(Request $request)
{
$this->authorize('delete', AssetModel::class);
$models_raw_array = $request->input('ids');
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->get();
$del_error_count = 0;
@@ -123,7 +130,7 @@ class BulkAssetModelsController extends Controller
if ($del_error_count == 0) {
return redirect()->route('models.index')
->with('success', trans('admin/models/message.bulkdelete.success',['success_count'=> $del_count] ));
->with('success', trans('admin/models/message.bulkdelete.success', ['success_count'=> $del_count]));
}
return redirect()->route('models.index')
@@ -132,7 +139,5 @@ class BulkAssetModelsController extends Controller
return redirect()->route('models.index')
->with('error', trans('admin/models/message.bulkdelete.error'));
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
@@ -17,7 +18,6 @@ use Str;
*/
class CategoriesController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the categories listing, which is generated in getDatatable.
@@ -32,10 +32,10 @@ class CategoriesController extends Controller
{
// Show the page
$this->authorize('view', Category::class);
return view('categories/index');
}
/**
* Returns a form view to create a new category.
*
@@ -49,11 +49,11 @@ class CategoriesController extends Controller
{
// Show the page
$this->authorize('create', Category::class);
return view('categories/edit')->with('item', new Category)
->with('category_types', Helper::categoryTypeList());
}
/**
* Validates and stores the new category data.
*
@@ -68,13 +68,13 @@ class CategoriesController extends Controller
{
$this->authorize('create', Category::class);
$category = new Category();
$category->name = $request->input('name');
$category->category_type = $request->input('category_type');
$category->eula_text = $request->input('eula_text');
$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->user_id = Auth::id();
$category->name = $request->input('name');
$category->category_type = $request->input('category_type');
$category->eula_text = $request->input('eula_text');
$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->user_id = Auth::id();
$category = $request->handleImages($category);
if ($category->save()) {
@@ -100,11 +100,11 @@ class CategoriesController extends Controller
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'))
->with('category_types', Helper::categoryTypeList());
}
/**
* Validates and stores the updated category data.
*
@@ -125,15 +125,14 @@ class CategoriesController extends Controller
}
// Update the category data
$category->name = $request->input('name');
$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.
$category->category_type = $request->input('category_type', $category->category_type);
$category->eula_text = $request->input('eula_text');
$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->category_type = $request->input('category_type', $category->category_type);
$category->eula_text = $request->input('eula_text');
$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 = $request->handleImages($category);
@@ -162,8 +161,8 @@ class CategoriesController extends Controller
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
}
if (!$category->isDeletable()) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=> $category->category_type ]));
if (! $category->isDeletable()) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=> $category->category_type]));
}
Storage::disk('public')->delete('categories'.'/'.$category->image);
@@ -172,7 +171,6 @@ class CategoriesController extends Controller
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success'));
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the categories detail view, which is generated in getDataView.
@@ -188,20 +186,20 @@ class CategoriesController extends Controller
{
$this->authorize('view', Category::class);
if ($category = Category::find($id)) {
if ($category->category_type=='asset') {
if ($category->category_type == 'asset') {
$category_type = 'hardware';
$category_type_route = 'assets';
} elseif ($category->category_type=='accessory') {
} elseif ($category->category_type == 'accessory') {
$category_type = 'accessories';
$category_type_route = 'accessories';
} else {
$category_type = $category->category_type;
$category_type_route = $category->category_type.'s';
}
return view('categories/view', compact('category'))
->with('category_type',$category_type)
->with('category_type_route',$category_type_route);
->with('category_type', $category_type)
->with('category_type_route', $category_type_route);
}
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers;
use App\Models\Asset;
@@ -14,9 +15,8 @@ trait CheckInOutRequest
*/
protected function determineCheckoutTarget()
{
// This item is checked out to a location
switch(request('checkout_to_type'))
{
// This item is checked out to a location
switch (request('checkout_to_type')) {
case 'location':
return Location::findOrFail(request('assigned_location'));
case 'asset':
@@ -24,6 +24,7 @@ trait CheckInOutRequest
case 'user':
return User::findOrFail(request('assigned_user'));
}
return null;
}
@@ -35,15 +36,16 @@ trait CheckInOutRequest
*/
protected function updateAssetLocation($asset, $target)
{
switch(request('checkout_to_type'))
{
switch (request('checkout_to_type')) {
case 'location':
$asset->location_id = $target->id;
Asset::where('assigned_type', 'App\Models\Asset')->where('assigned_to', $asset->id)
->update(['location_id' => $asset->location_id]);
break;
case 'asset':
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
if ($target->location_id!='') {
if ($target->location_id != '') {
$asset->location_id = $target->location_id;
}
break;
@@ -51,6 +53,7 @@ trait CheckInOutRequest
$asset->location_id = $target->location_id;
break;
}
return $asset;
}
}

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ImageUploadRequest;
@@ -12,10 +13,8 @@ use Illuminate\Support\Facades\Storage;
*
* @version v1.0
*/
final class CompaniesController extends Controller
{
/**
* Returns view to display listing of companies.
*
@@ -68,10 +67,10 @@ final class CompaniesController extends Controller
return redirect()->route('companies.index')
->with('success', trans('admin/companies/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($company->getErrors());
}
/**
* Return form to edit existing company.
*
@@ -113,14 +112,13 @@ final class CompaniesController extends Controller
$company->name = $request->input('name');
$company = $request->handleImages($company);
if ($company->save()) {
return redirect()->route('companies.index')
->with('success', trans('admin/companies/message.update.success'));
}
return redirect()->route('companies.edit', ['company' => $companyId])
->with('error', trans('admin/companies/message.update.error'));
}
@@ -142,13 +140,13 @@ final class CompaniesController extends Controller
}
$this->authorize('delete', $company);
if(!$company->isDeletable()) {
if (! $company->isDeletable()) {
return redirect()->route('companies.index')
->with('error', trans('admin/companies/message.assoc_users'));
}
if ($company->image) {
try {
try {
Storage::disk('public')->delete('companies'.'/'.$company->image);
} catch (\Exception $e) {
\Log::debug($e);
@@ -156,11 +154,13 @@ final class CompaniesController extends Controller
}
$company->delete();
return redirect()->route('companies.index')
->with('success', trans('admin/companies/message.delete.success'));
}
public function show($id) {
public function show($id)
{
$this->authorize('view', Company::class);
if (is_null($company = Company::find($id))) {
@@ -168,6 +168,6 @@ final class CompaniesController extends Controller
->with('error', trans('admin/companies/message.not_found'));
}
return view('companies/view')->with('company',$company);
return view('companies/view')->with('company', $company);
}
}

View File

@@ -15,7 +15,6 @@ use Illuminate\Support\Facades\Validator;
class ComponentCheckinController extends Controller
{
/**
* Returns a view that allows the checkin of a component from an asset.
*
@@ -39,14 +38,13 @@ class ComponentCheckinController extends Controller
trans('admin/components/message.not_found'));
}
$this->authorize('checkin', $component);
return view('components/checkin', compact('component_assets','component','asset'));
return view('components/checkin', compact('component_assets', 'component', 'asset'));
}
return redirect()->route('components.index')->with('error', trans('admin/components/messages.not_found'));
}
/**
* Validate and store checkin data.
*
@@ -66,12 +64,11 @@ class ComponentCheckinController extends Controller
trans('admin/components/message.not_found'));
}
$this->authorize('checkin', $component);
$max_to_checkin = $component_assets->assigned_qty;
$validator = Validator::make($request->all(), [
"checkin_qty" => "required|numeric|between:1,$max_to_checkin"
'checkin_qty' => "required|numeric|between:1,$max_to_checkin",
]);
if ($validator->fails()) {
@@ -81,7 +78,7 @@ class ComponentCheckinController extends Controller
}
// Validation passed, so let's figure out what we have to do here.
$qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty'));
$qty_remaining_in_checkout = ($component_assets->assigned_qty - (int) $request->input('checkin_qty'));
// We have to modify the record to reflect the new qty that's
// actually checked out.
@@ -102,7 +99,7 @@ class ComponentCheckinController extends Controller
return redirect()->route('components.index')->with('success',
trans('admin/components/message.checkin.success'));
}
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
}
}

View File

@@ -32,6 +32,7 @@ class ComponentCheckoutController extends Controller
return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found'));
}
$this->authorize('checkout', $component);
return view('components/checkout', compact('component'));
}
@@ -58,8 +59,8 @@ class ComponentCheckoutController extends Controller
$max_to_checkout = $component->numRemaining();
$validator = Validator::make($request->all(), [
"asset_id" => "required",
"assigned_qty" => "required|numeric|between:1,$max_to_checkout"
'asset_id' => 'required',
'assigned_qty' => "required|numeric|between:1,$max_to_checkout",
]);
if ($validator->fails()) {
@@ -78,14 +79,14 @@ class ComponentCheckoutController extends Controller
}
// Update the component data
$component->asset_id = $asset_id;
$component->asset_id = $asset_id;
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'user_id' => $admin_user->id,
'created_at' => date('Y-m-d H:i:s'),
'assigned_qty' => $request->input('assigned_qty'),
'asset_id' => $asset_id
'asset_id' => $asset_id,
]);
event(new CheckoutableCheckedOut($component, $asset, Auth::user(), $request->input('note')));

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Http\Controllers\Components;
use App\Http\Controllers\Controller;
@@ -32,6 +33,7 @@ class ComponentsController extends Controller
public function index()
{
$this->authorize('view', Component::class);
return view('components/index');
}
@@ -48,11 +50,11 @@ class ComponentsController extends Controller
public function create()
{
$this->authorize('create', Component::class);
return view('components/edit')->with('category_type', 'component')
->with('item', new Component);
}
/**
* Validate and store data for new component.
*
@@ -78,12 +80,14 @@ class ComponentsController extends Controller
$component->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
$component->notes = $request->input('notes');
$component = $request->handleImages($component);
if ($component->save()) {
return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($component->getErrors());
}
@@ -101,8 +105,10 @@ class ComponentsController extends Controller
{
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'));
}
@@ -125,7 +131,7 @@ class ComponentsController extends Controller
}
$min = $component->numCHeckedOut();
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$min"
'qty' => "required|numeric|min:$min",
]);
if ($validator->fails()) {
@@ -147,12 +153,14 @@ class ComponentsController extends Controller
$component->purchase_date = $request->input('purchase_date');
$component->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$component->qty = $request->input('qty');
$component->notes = $request->input('notes');
$component = $request->handleImages($component);
if ($component->save()) {
return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($component->getErrors());
}
@@ -175,7 +183,7 @@ class ComponentsController extends Controller
// Remove the image if one exists
if (Storage::disk('public')->exists('components/'.$component->image)) {
try {
try {
Storage::disk('public')->delete('components/'.$component->image);
} catch (\Exception $e) {
\Log::debug($e);
@@ -183,6 +191,7 @@ class ComponentsController extends Controller
}
$component->delete();
return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success'));
}
@@ -202,6 +211,7 @@ class ComponentsController extends Controller
if (isset($component->id)) {
$this->authorize('view', $component);
return view('components/view', compact('component'));
}
// Redirect to the user management page

View File

@@ -12,7 +12,6 @@ use Illuminate\Support\Facades\Input;
class ConsumableCheckoutController extends Controller
{
/**
* Return a view to checkout a consumable to a user.
*
@@ -29,6 +28,7 @@ class ConsumableCheckoutController extends Controller
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
$this->authorize('checkout', $consumable);
return view('consumables/checkout', compact('consumable'));
}
@@ -65,13 +65,12 @@ class ConsumableCheckoutController extends Controller
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'user_id' => $admin_user->id,
'assigned_to' => e($request->input('assigned_to'))
'assigned_to' => e($request->input('assigned_to')),
]);
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
// Redirect to the new consumable page
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success'));
}
}

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