Compare commits

...

803 Commits

Author SHA1 Message Date
snipe
53330514ac Updated field name
Signed-off-by: snipe <snipe@snipe.net>
2024-11-02 15:09:03 +00:00
snipe
ba226d9ba3 Added undeployable?
Signed-off-by: snipe <snipe@snipe.net>
2024-10-31 11:04:43 +00:00
snipe
95d136284d Few more fixes
Signed-off-by: snipe <snipe@snipe.net>
2024-10-28 22:02:48 +00:00
snipe
f5aea7b0d5 Changed status label to use status_type instead of booleans
Signed-off-by: snipe <snipe@snipe.net>
2024-10-28 11:37:17 +00:00
snipe
dfc63641dc Merge pull request #15550 from uberbrady/fix_multi_create_partial_failure
Fix multi create partial failure (fixes: [RB-18591])
2024-10-24 11:40:50 +01:00
snipe
07a51ec8b1 Merge pull request #15712 from Godmartinz/fix_import-progress-bar
Upgraded `livewire v3.5.9 => v3.5.12`
2024-10-24 10:03:10 +01:00
snipe
e0ec6795b5 Use crucial for seeded data
Signed-off-by: snipe <snipe@snipe.net>
2024-10-24 01:27:50 +01:00
snipe
5509d756b7 Merge pull request #15722 from Godmartinz/fix_component_factory
Fixed Component Factory: use manufacturer factory for `manufactuer_id`
2024-10-24 01:12:11 +01:00
Godfrey M
b16a978f1b uses manufacturer factory for manufactuer_id 2024-10-23 16:25:51 -07:00
snipe
55ba6279a4 Use trans_choice on alert menu
Signed-off-by: snipe <snipe@snipe.net>
2024-10-23 19:14:17 +01:00
snipe
a9eea830e3 Added manufacturer and model number to component seeders
Signed-off-by: snipe <snipe@snipe.net>
2024-10-23 19:05:34 +01:00
snipe
af564935d5 Merge pull request #15720 from snipe/15695_adds_manufacturer_and_model_number_to_components
Fixed #15695 - Added manufacturer and model_number to components
2024-10-23 17:56:04 +01:00
snipe
3ee76be7e3 Added manufacturer and model_number to components
Signed-off-by: snipe <snipe@snipe.net>
2024-10-23 17:50:22 +01:00
snipe
d58f87862c Merge pull request #15719 from snipe/#15717_adds_qty_to_consumable
Fixed #15717 - Added ability to checkout consumables in variable qty via API
2024-10-23 15:09:50 +01:00
snipe
0b6859c491 Added ability to checkout consumables in variable qty
Signed-off-by: snipe <snipe@snipe.net>
2024-10-23 15:05:35 +01:00
Godfrey M
727c0e458c remove translation 2024-10-22 14:34:39 -07:00
Godfrey M
870dc747db oops 2024-10-22 14:27:32 -07:00
Godfrey M
0fb3d83fac revert controller change 2024-10-22 14:26:54 -07:00
Godfrey M
0d59ccd6a6 upgraded livewire v3.5.9 => v3.5.12 2024-10-22 14:23:26 -07:00
snipe
5da3ce3564 Merge pull request #15711 from marcusmoore/fixes/custom-fieldset-checkboxes
Fixed custom field checkboxes on asset edit page
2024-10-22 22:10:20 +01:00
snipe
c3bbca30ad Merge pull request #15710 from snipe/fixes_lightbox_for_avif
Fixes #15701 - load avif files properly in lightbox
2024-10-22 22:07:50 +01:00
snipe
37f14fff3b Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2024-10-22 22:07:28 +01:00
snipe
eb6c51fabd Fixes #15701 - load avif files properly in lightbox
Signed-off-by: snipe <snipe@snipe.net>
2024-10-22 22:04:57 +01:00
Marcus Moore
5ecd2b6293 Default checkbox elements to an empty array 2024-10-22 14:04:05 -07:00
snipe
dccb788a88 Merge pull request #15691 from marcusmoore/fixes/get-id-for-current-user
Updated `Company::getIdForCurrentUser()` to return null in certain scenarios
2024-10-22 17:44:30 +01:00
Marcus Moore
d10fe77ee7 Merge branch 'develop' into fixes/get-id-for-current-user 2024-10-22 09:38:31 -07:00
snipe
5e1d792bba Merge pull request #15687 from NebelKreis/fix/dashboard-title-casing
Fixed #15686: Corrected capitalization for dashboard section titles by removing strtolower()
2024-10-22 16:52:28 +01:00
snipe
9cf71976f6 Fixed #15706 - Removed purchase order number from asset import
Signed-off-by: snipe <snipe@snipe.net>
2024-10-22 16:51:42 +01:00
snipe
15745d9737 Merge pull request #15566 from Godmartinz/status-label-error-message
Fixed Status Labels Error Message
2024-10-22 16:39:44 +01:00
snipe
bd97955b9e Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2024-10-22 16:38:46 +01:00
snipe
252d99421c Merge pull request #15689 from snipe/better_handle_inline_files
Better handle inline files in file listing
2024-10-22 16:26:48 +01:00
snipe
5767a98ad8 Merge pull request #15649 from bryanlopezinc/ImproveImporting
Improve import performance
2024-10-22 16:26:23 +01:00
snipe
0c820cbc0d Merge pull request #15598 from spencerrlongg/bug/custom_field_validation_issue
Custom Field Existence Validation Issue
2024-10-22 15:56:12 +01:00
snipe
db81701621 Merge branch 'develop' into better_handle_inline_files 2024-10-22 15:44:24 +01:00
snipe
a05c33febf Squashed commit of the following:
commit 147fcfb8eb
Merge: 58a3d09b5 fdcc17ca2
Author: snipe <snipe@snipe.net>
Date:   Tue Oct 22 15:12:55 2024 +0100

    Merge pull request #15676 from Toreg87/fixes/api_create_user_fmcs

    Fix user creation with FullMultipleCompanySupport enabled over API

commit 58a3d09b5f
Merge: 30a06a594 867fa2f36
Author: snipe <snipe@snipe.net>
Date:   Tue Oct 22 14:55:42 2024 +0100

    Merge pull request #15703 from marcusmoore/bug/sc-27188

    Linked accessory files in activity report

commit 30a06a5942
Merge: 6c6af78e0 ce3086317
Author: snipe <snipe@snipe.net>
Date:   Tue Oct 22 11:47:06 2024 +0100

    Merge pull request #15693 from marcusmoore/chore/remove-parallel-testing

    Removed brianium/paratest

commit 6c6af78e08
Merge: 9b06bbb6c 3f79fd7ea
Author: snipe <snipe@snipe.net>
Date:   Tue Oct 22 11:46:04 2024 +0100

    Merge pull request #15705 from marcusmoore/tests/icon-component-test

    Added test to ensure icon component does not end in newline

commit 3f79fd7ea7
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Oct 21 17:07:40 2024 -0700

    Add test to ensure icon component does not end in newline

commit 9b06bbb6c3
Merge: 46ad1d072 d7f70146f
Author: snipe <snipe@snipe.net>
Date:   Mon Oct 21 22:38:26 2024 +0100

    Merge pull request #15704 from marcusmoore/bug/remove-extra-icon

    Removed second icon in accessory file list

commit ce30863177
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Oct 21 13:57:04 2024 -0700

    Remove brianium/paratest dependency

commit d7f70146f4
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Oct 21 13:48:25 2024 -0700

    Remove extra icon in accessory file upload list

commit 867fa2f36e
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Oct 21 12:40:24 2024 -0700

    Display file in activity report for accessories

commit 0933a2d4ea
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Oct 17 18:01:48 2024 -0700

    Remove --parallel flag

commit 46ad1d072f
Merge: bcb4bd9eb 3cf746d7d
Author: snipe <snipe@snipe.net>
Date:   Thu Oct 17 15:29:47 2024 +0100

    Merge pull request #15680 from uberbrady/bulk_checkout_to_bulk_actions

    Bulk checkout to bulk actions

commit bcb4bd9eb4
Merge: 250037540 f50ccbcc4
Author: snipe <snipe@snipe.net>
Date:   Thu Oct 17 10:20:13 2024 +0100

    Merge pull request #15683 from Toreg87/fixes/outdated_comment

    Fix outdated comment in CompanyableTrait

commit f50ccbcc49
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Thu Oct 17 11:07:28 2024 +0200

    Fix outdated comment in CompanyableTrait

    As of commit 5800e8d the user model uses CompanyableTrait so remove this clearly outdated comment

commit 3cf746d7df
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Wed Oct 16 23:13:32 2024 +0100

    Rework the bulk checkout to not change how all checkouts work

commit 6b7af802af
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Thu Oct 10 13:28:23 2024 +0100

    Add 'bulk checkout' as one of the bulk actions in the bulk actions toolbar

commit fdcc17ca2c
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Wed Oct 16 11:18:24 2024 +0200

    Fix user creation with FullMultipleCompanySupport enabled over API

    It is currently possible as a non-superuser to create a new user or patch an existing user with arbitrary company over the API if FullMultipleCompanySupport is enabled.
    Altough a highly unlikely scenario as the user needs permission to create API keys and new users, it is a bug that should get fixed.

    Add a call to getIdForCurrentUser() to normalize the company_id if FullMultipleCompanySupport is enabled.

Signed-off-by: snipe <snipe@snipe.net>
2024-10-22 15:43:19 +01:00
snipe
147fcfb8eb Merge pull request #15676 from Toreg87/fixes/api_create_user_fmcs
Fix user creation with FullMultipleCompanySupport enabled over API
2024-10-22 15:12:55 +01:00
snipe
58a3d09b5f Merge pull request #15703 from marcusmoore/bug/sc-27188
Linked accessory files in activity report
2024-10-22 14:55:42 +01:00
snipe
30a06a5942 Merge pull request #15693 from marcusmoore/chore/remove-parallel-testing
Removed brianium/paratest
2024-10-22 11:47:06 +01:00
snipe
6c6af78e08 Merge pull request #15705 from marcusmoore/tests/icon-component-test
Added test to ensure icon component does not end in newline
2024-10-22 11:46:04 +01:00
Marcus Moore
3f79fd7ea7 Add test to ensure icon component does not end in newline 2024-10-21 17:07:40 -07:00
snipe
9b06bbb6c3 Merge pull request #15704 from marcusmoore/bug/remove-extra-icon
Removed second icon in accessory file list
2024-10-21 22:38:26 +01:00
Marcus Moore
ce30863177 Remove brianium/paratest dependency 2024-10-21 13:57:04 -07:00
Marcus Moore
d7f70146f4 Remove extra icon in accessory file upload list 2024-10-21 13:48:25 -07:00
Marcus Moore
867fa2f36e Display file in activity report for accessories 2024-10-21 12:40:24 -07:00
Marcus Moore
e1882ee6d2 Add comment 2024-10-21 12:21:45 -07:00
Marcus Moore
7eee239378 use is_numeric instead of is_int 2024-10-21 12:20:28 -07:00
Marcus Moore
4188849ae1 Add failing test case 2024-10-21 12:19:48 -07:00
snipe
787e651778 Fixed todos with log message
Signed-off-by: snipe <snipe@snipe.net>
2024-10-21 16:52:21 +01:00
snipe
ef9b6e3b07 Code cleanup
Signed-off-by: snipe <snipe@snipe.net>
2024-10-21 16:34:54 +01:00
snipe
06c599cc17 Added method to show or download file
Signed-off-by: snipe <snipe@snipe.net>
2024-10-21 16:34:03 +01:00
snipe
6105323877 Use plural class name for src
Signed-off-by: snipe <snipe@snipe.net>
2024-10-21 14:11:20 +01:00
Marcus Moore
0933a2d4ea Remove --parallel flag 2024-10-17 18:01:48 -07:00
Marcus Moore
a8d853c44a Remove focus group tags 2024-10-17 15:26:27 -07:00
Marcus Moore
7e1b47708e Fix failing test ensuring company id is an integer 2024-10-17 15:18:41 -07:00
Marcus Moore
979e4502ff Have getIdForCurrentUser method return null if FMCS enabled, user is not super admin, and does not have company 2024-10-17 15:14:39 -07:00
Marcus Moore
99dd51a965 Improve name 2024-10-17 14:53:18 -07:00
Marcus Moore
15c2169477 Scaffold additional tests 2024-10-17 14:31:05 -07:00
Marcus Moore
50fa6ce335 Scaffold tests 2024-10-17 14:12:22 -07:00
Marcus Moore
159a1d3f43 Be more explicit 2024-10-17 11:48:55 -07:00
snipe
d1149730be Apply blade component to files views
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 16:31:17 +01:00
snipe
46ad1d072f Merge pull request #15680 from uberbrady/bulk_checkout_to_bulk_actions
Bulk checkout to bulk actions
2024-10-17 15:29:47 +01:00
NebelKreis
780ed91a10 Fix: Removed strtolower() from dashboard titles
This fix ensures the correct capitalization in different languages.
2024-10-17 16:09:25 +02:00
snipe
bcb4bd9eb4 Merge pull request #15683 from Toreg87/fixes/outdated_comment
Fix outdated comment in CompanyableTrait
2024-10-17 10:20:13 +01:00
Tobias Regnery
f50ccbcc49 Fix outdated comment in CompanyableTrait
As of commit 5800e8d the user model uses CompanyableTrait so remove this clearly outdated comment
2024-10-17 11:07:28 +02:00
snipe
0e9b3c9119 Check for existence before trying to get the icon
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:27:39 +01:00
snipe
4933aa5784 Add StorageHelper to app config
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:27:04 +01:00
snipe
d67addc69e Removed filetype column - it’s dumb
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:21:43 +01:00
snipe
02c80ff18a Added comment
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:18:40 +01:00
snipe
c01190fac2 Conditionally add content-type
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:18:34 +01:00
snipe
017884f843 Added checks and filetype display
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:09:09 +01:00
snipe
c49921f50f Removed unused (maybe?) API endpoint
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:08:54 +01:00
snipe
c49abb6aea Refactor the UserFilesController show method for simpler inlining
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:08:38 +01:00
snipe
ccd2019448 Removed unusded use statements
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:08:04 +01:00
snipe
96191a5e93 Added method to decide if the file should be inlinable
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:07:54 +01:00
snipe
c56affd663 Added SVG icon
Signed-off-by: snipe <snipe@snipe.net>
2024-10-17 00:07:37 +01:00
Brady Wetherington
3cf746d7df Rework the bulk checkout to not change how all checkouts work 2024-10-16 23:13:32 +01:00
Brady Wetherington
6b7af802af Add 'bulk checkout' as one of the bulk actions in the bulk actions toolbar 2024-10-16 22:02:45 +01:00
Marcus Moore
604a964462 Improve scenario descriptions 2024-10-16 11:52:24 -07:00
Marcus Moore
2f72c66614 Add additional case 2024-10-16 11:30:06 -07:00
Tobias Regnery
fdcc17ca2c Fix user creation with FullMultipleCompanySupport enabled over API
It is currently possible as a non-superuser to create a new user or patch an existing user with arbitrary company over the API if FullMultipleCompanySupport is enabled.
Altough a highly unlikely scenario as the user needs permission to create API keys and new users, it is a bug that should get fixed.

Add a call to getIdForCurrentUser() to normalize the company_id if FullMultipleCompanySupport is enabled.
2024-10-16 11:47:18 +02:00
Marcus Moore
cba1a56040 Improve readability? 2024-10-15 17:38:11 -07:00
Marcus Moore
d9afde4610 Write failing test 2024-10-15 17:00:22 -07:00
Marcus Moore
42095c0167 Add reference link 2024-10-15 13:02:22 -07:00
snipe
2500375400 Merge pull request #15672 from uberbrady/ldap_location_fixes
Clean up how we use the '$location' in LDAP sync command
2024-10-15 17:34:35 +01:00
Brady Wetherington
e4e1d0d50a Clean up how we use the '$location' in LDAP sync command 2024-10-15 17:26:31 +01:00
snipe
16c8264e76 Merge pull request #15671 from snipe/bug/sc-27147
Bug/sc 27147
2024-10-15 16:42:34 +01:00
snipe
0ae9ce0aa9 Cannot sort by updated at on Users [sc-27147]
Signed-off-by: snipe <snipe@snipe.net>
2024-10-15 16:41:45 +01:00
snipe
50b8f180b3 More logical grouping in allow_columns
Signed-off-by: snipe <snipe@snipe.net>
2024-10-15 16:41:39 +01:00
snipe
914a647204 Merge pull request #15669 from snipe/remlove_ou_requirenedess
Fixed #15663 - remove requiredness for OU
2024-10-15 12:47:15 +01:00
snipe
e9225ff3ea Switch to regular HTML for input form field
Signed-off-by: snipe <snipe@snipe.net>
2024-10-15 12:43:10 +01:00
snipe
d0d4159088 Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2024-10-15 12:42:09 +01:00
snipe
69b6080bd8 Merge pull request #15666 from snipe/updated_readme_llm
Added LLM note
2024-10-15 10:31:29 +01:00
snipe
b997d728fb Added LLM note
Signed-off-by: snipe <snipe@snipe.net>
2024-10-15 10:30:34 +01:00
snipe
ddead359d0 Merge pull request #15660 from Toreg87/fixes/api_asset_create_fmcs2
Refactor asset creation with API
2024-10-14 14:29:34 +01:00
Tobias Regnery
f3c4e55667 Refactor asset creation with API
Commit fb4fe3004 restored the previous behaviour to check the company_id in case of FullMultipleCompanySupport.
But after rereading the code and the laravel documentation, the check is already there where it belongs in AssetStoreRequest::prepareForValidation()
The bug is the is_int-check of the request input in prepareForValidation(). Is is of type string even if it is a numeric value, so the call to getIdForCurrentUser() never happend.
Fix this by removing the check and the now redundant call to getIdForCurrentUser().
Wrong values will get caught by the model-level validation rules.
2024-10-14 15:14:41 +02:00
snipe
0d35335da7 Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2024-10-11 16:06:17 +01:00
snipe
feaa714304 Nicer disabled button
Signed-off-by: snipe <snipe@snipe.net>
2024-10-11 14:23:57 +01:00
snipe
e1a70023b1 Merge pull request #15655 from Toreg87/fixes/api_asset_create_fmcs
Fixes #15654 Fix asset creation with API and FullMultipleCompanySupport
2024-10-11 11:45:48 +01:00
snipe
de62359c67 Merge pull request #15533 from marcusmoore/testing/fmcs-accessories
Added tests for accessory api controller
2024-10-11 11:29:34 +01:00
snipe
12bda8fc7b Merge pull request #15653 from snipe/15651_admin_user_on_maintenances
Fixed #15651 - admin user now displaying on maintenances page
2024-10-11 11:27:18 +01:00
Tobias Regnery
fb4fe30049 Fix asset creation with API and FullMultipleCompanySupport
It is currently possible to create an asset with arbitrary company without being superuser and FullMultipleCompanySupport enabled.
This bug goes back to 75ac7f80b9 which is part of version 6.3.0.
Fix this by restoring the previous behaviour to check the company_id with getIdForCurrentUser().
2024-10-11 12:19:20 +02:00
snipe
b054017c9f Fixed #15651 - admin user now displaying on maintenances page
Signed-off-by: snipe <snipe@snipe.net>
2024-10-11 11:16:24 +01:00
bryanlopezinc
524a442724 Improved import performance 2024-10-10 23:32:07 +01:00
snipe
8aa298f6b0 Merge pull request #15644 from snipe/form_requests_for_settings
Form requests for settings
2024-10-10 12:30:53 +01:00
snipe
1f34657734 Fixed test
Signed-off-by: snipe <snipe@snipe.net>
2024-10-10 12:30:35 +01:00
snipe
0856ee648e Merge pull request #15648 from snipe/update_packages
Updated livewire to 3.5.2
2024-10-10 12:23:14 +01:00
snipe
1dafc970df Updated livewire to 3.5.2
Signed-off-by: snipe <snipe@snipe.net>
2024-10-10 12:19:57 +01:00
snipe
94a074a193 Merge pull request #15601 from snipe/check_db_on_healthcheck
Fixed #15439 - check database on healthcheck
2024-10-10 01:11:10 +01:00
snipe
2d49e1eff2 Merge pull request #15637 from akemidx/bug/sc-26614
FIXED: Badge counter showing deleted assets on User page
2024-10-10 01:09:11 +01:00
snipe
705bc6f0c0 Merge pull request #15642 from uberbrady/fix_bulk_checkout
Fix bulk checkout to users, assets, and locations
2024-10-10 01:08:25 +01:00
snipe
b5b93fdd3a Make ldap username required
Signed-off-by: snipe <snipe@snipe.net>
2024-10-10 00:27:00 +01:00
snipe
d9432baf7a Mlore ldap style improvements
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 23:51:20 +01:00
snipe
90be2a4498 Use newer naming convention for errors
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:26:30 +01:00
snipe
3886da8941 Remove form request from get LDAP method
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:15:49 +01:00
snipe
130e0c6242 More validation
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:15:37 +01:00
snipe
4361a10818 Added string
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:15:30 +01:00
snipe
aa8048ac15 Blade changes for ldap
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:15:25 +01:00
snipe
710e738e8e Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 22:15:16 +01:00
snipe
3705b91439 Added more validation
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 20:51:34 +01:00
snipe
707bdad192 Updated test
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 20:33:56 +01:00
snipe
242fe33f97 Switch to regular HTML input
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 20:33:42 +01:00
snipe
ded79469c1 Remove unused controller method
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 20:33:29 +01:00
snipe
d9fbf330e5 Fixed translations
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 20:33:15 +01:00
snipe
2cb9ac26cd Renamed test
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:57:04 +01:00
snipe
185bc966e6 Cleaned up use statements in tests
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:46:47 +01:00
snipe
a7f7e4938f Added form action
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:31:56 +01:00
snipe
2883e79193 Removed unecessary assets creation
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:30:55 +01:00
snipe
9c4191ae0a Basic tests
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:30:42 +01:00
snipe
3a77b83e9c Added space
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:30:34 +01:00
snipe
d9be2b5a5e Trying to use the email_array translation
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:30:25 +01:00
snipe
69c43c610c Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 19:30:00 +01:00
snipe
4f957bcf71 Required flag
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 18:34:53 +01:00
snipe
5cda7cce48 Only accept a positive number for thresholds
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 18:21:40 +01:00
snipe
41b94e7128 Fixed form input group
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 18:19:26 +01:00
snipe
aa55fa6ff4 Switch to form requests for settings
Signed-off-by: snipe <snipe@snipe.net>
2024-10-09 18:16:34 +01:00
Brady Wetherington
67a605c9a5 Fix bulk checkout to users, assets, and locations 2024-10-09 17:01:26 +01:00
akemidx
c2663ea1e0 withouttrashed 2024-10-08 16:38:33 -04:00
snipe
3ee5713740 Merge pull request #15631 from snipe/test/importer-tests
Add importer tests
2024-10-07 23:13:15 +01:00
snipe
ab8a22f77e Merge pull request #15630 from marcusmoore/bug/sc-27028
Only show EULA when available on print users page
2024-10-07 22:56:23 +01:00
snipe
56e7ea6677 Merge pull request #15616 from marcusmoore/test/importer-test-updates
Improve importer tests
2024-10-07 22:29:35 +01:00
snipe
26d7572bcc Merge pull request #15603 from marcusmoore/fixes/add-reguard
Added `Model::reguard()` to importer
2024-10-07 22:28:53 +01:00
Marcus Moore
8c9132aff9 Hide EULA text and button when nothing will be displayed 2024-10-07 14:22:49 -07:00
snipe
382ebef8ca Merge pull request #15621 from sniff122/develop
Docker Env: Change trusted proxies to RFC1918
2024-10-07 21:26:21 +01:00
snipe
2be88cb955 Merge pull request #15624 from snipe/fixed_line_break_on_print_all_for_users
Removed duplicate JS and removed line break before user section
2024-10-07 11:14:24 +01:00
snipe
3f36d5f9b3 Removed duplicate CSS and removed line break before user section
Signed-off-by: snipe <snipe@snipe.net>
2024-10-07 11:08:02 +01:00
Lewis Foster
f76da48448 Docker Env: Change trusted proxies to RFC1918 2024-10-05 18:27:42 +01:00
Marcus Moore
8035326675 Add test 2024-10-03 16:53:19 -07:00
Marcus Moore
dfdd85abb1 Remove unused imports 2024-10-03 15:14:07 -07:00
Marcus Moore
063ea1892b Add trait to clean up files after test runs 2024-10-03 15:02:03 -07:00
Marcus Moore
e213053775 Swap factory syntax 2024-10-03 13:59:58 -07:00
Marcus Moore
88d549e7c5 Remove unused data provider method 2024-10-03 13:40:37 -07:00
Marcus Moore
983a25aa5f Simplify permission tests 2024-10-03 13:39:54 -07:00
Marcus Moore
bde05d6ed9 Use new() instead of times() 2024-10-03 13:15:49 -07:00
Marcus Moore
b5ffe54bd0 Swap assertEquals parameter order 2024-10-03 13:15:02 -07:00
Marcus Moore
863c0a8b60 Fix import_type for accessory state 2024-10-03 11:43:02 -07:00
Marcus Moore
32551d55d7 Merge pull request #15579 from bryanlopezinc/ImportTests
Add Import data tests
2024-10-03 11:39:21 -07:00
snipe
7fc498a597 Merge pull request #15613 from snipe/css_fixes_for_long_values
Smarter word-wrapping on long text
2024-10-03 17:39:18 +01:00
snipe
cb281c6408 Tweaked line height
Signed-off-by: snipe <snipe@snipe.net>
2024-10-03 17:33:46 +01:00
snipe
f483cd448f Smarter work-wrapping on long text
Signed-off-by: snipe <snipe@snipe.net>
2024-10-03 17:27:37 +01:00
snipe
78ca1026fd Merge pull request #15612 from snipe/fixes_print_assigned_in_profile
Fixes print assigned in profile
2024-10-03 16:24:32 +01:00
snipe
722d5a58e7 Added isset on users
Signed-off-by: snipe <snipe@snipe.net>
2024-10-03 16:19:38 +01:00
snipe
7461c3e0ca Change controller to assume a collection. (This is dumb, but whatever)
Signed-off-by: snipe <snipe@snipe.net>
2024-10-03 16:19:27 +01:00
snipe
3c0f4181ae Use the newer button style
Signed-off-by: snipe <snipe@snipe.net>
2024-10-03 16:19:06 +01:00
snipe
3699d79363 Merge pull request #15610 from uberbrady/fix_numeric_sort_bug
Fix numeric sort 'ambiguous order clause' error
2024-10-03 14:34:00 +01:00
Brady Wetherington
350b627ce1 Fix numeric sort 'ambiguous order clause' error 2024-10-03 14:23:40 +01:00
Marcus Moore
ee046a8688 Add matching Model::reguard() 2024-10-02 10:50:40 -07:00
snipe
b34a7c8aad Removed die()
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 15:48:35 +01:00
snipe
f92bf5dc20 Updated language for failure
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 15:39:27 +01:00
snipe
4d9e85026a Fixed #15439 - check database on healthcheck
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 15:36:01 +01:00
snipe
54fbd0540d Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2024-10-02 12:40:49 +01:00
snipe
b483bb1633 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 12:40:45 +01:00
snipe
4db7358086 Merge pull request #15593 from Godmartinz/Fixed-divide-by-zero-bug
Fixed divide by zero bug in depreciation transformer
2024-10-02 12:38:46 +01:00
snipe
0dd6f41f66 Simplified 2fa if/else
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 11:04:55 +01:00
snipe
684c20ae39 Fixed parenthasis
Signed-off-by: snipe <snipe@snipe.net>
2024-10-02 11:00:49 +01:00
spencerrlongg
3153bbb13f dumb fix 2024-10-01 17:04:18 -05:00
Marcus Moore
3dc64cc5e0 Reference accessory checkout and not the accessory 2024-10-01 13:35:39 -07:00
snipe
c32f4e34b4 Minor formatting fix
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 20:35:49 +01:00
snipe
ca1886cebc Merge pull request #15594 from snipe/localizations/update-2024-10-01
Updated strings
2024-10-01 20:31:38 +01:00
snipe
a79dfea40a Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 20:30:58 +01:00
snipe
45ab49eeab Merge pull request #15592 from spencerrlongg/bug/catch_request_notify_errors
Catch Errors Around Request Notifications
2024-10-01 20:26:42 +01:00
spencerrlongg
8232618a9f change the other one too 2024-10-01 14:26:32 -05:00
spencerrlongg
9a651b567d change error to warning 2024-10-01 14:24:03 -05:00
snipe
97d00e5aa8 Fixed erroneous form tag on anchor
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 20:08:54 +01:00
Marcus Moore
5b90d79494 Use created_by 2024-10-01 11:50:48 -07:00
Godfrey M
b9cfdf2e54 reworked monthly depreciation variable value 2024-10-01 11:41:59 -07:00
spencerrlongg
1139acd9f3 catch errors around request notifications 2024-10-01 13:36:47 -05:00
Godfrey M
b7ad80bd31 fix monthly depreciation value 2024-10-01 11:24:24 -07:00
Godfrey M
5ffd1b8daa fixes if statement in transformer 2024-10-01 11:02:39 -07:00
snipe
9a2117466e Removed placeholder
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 18:23:40 +01:00
snipe
7e3a062984 Use <th> for table header in bulk interstitial
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 18:23:07 +01:00
snipe
d274fb6963 Merge pull request #15589 from snipe/adds_checkin_action_on_asset_delete
Adds checkin action on asset delete via View UI
2024-10-01 14:32:48 +01:00
snipe
27ba641aa5 Added checkin on delete to API
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 14:30:34 +01:00
snipe
5823197e6f Added checkin action on delete for checked out assets
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 14:29:02 +01:00
snipe
cfc04a1d12 Merge pull request #15588 from snipe/added_more_maxlengths
Added maxlengths to additional fields
2024-10-01 14:08:58 +01:00
snipe
cae8aa7840 Added maxlengths to additional fields
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 14:02:54 +01:00
snipe
12da43303f Fixed #15584 - regression with required css change
Signed-off-by: snipe <snipe@snipe.net>
2024-10-01 01:44:05 +01:00
Marcus Moore
fdfea390fb Merge branch 'develop' into testing/fmcs-accessories 2024-09-30 12:59:27 -07:00
snipe
b04afbbc85 Merge pull request #15564 from uberbrady/improve_autoclose
Get us better debugging output for new Github Stale Action
2024-09-30 19:26:08 +01:00
snipe
b964ce1025 Merge pull request #15583 from Godmartinz/remove-sortable-from-depreciations
Removed sortablity for current value column in depreciations report
2024-09-30 19:25:05 +01:00
snipe
6217cba201 Merge pull request #15524 from Godmartinz/double-notif-bug
Fixed double webhook notifications // Separated email and webhook notifications.
2024-09-30 19:24:19 +01:00
Godfrey M
68e3f375fc removes sortablity from current value column 2024-09-30 11:15:49 -07:00
snipe
5689e940b8 Fixed #15581 - missing bracker
Signed-off-by: snipe <snipe@snipe.net>
2024-09-30 18:23:12 +01:00
bryanlopezinc
e807cfab86 Merge branch 'develop' into importTests 2024-09-30 12:47:52 +01:00
bryanlopezinc
0b3f458561 Added tests for Import feature 2024-09-30 12:42:41 +01:00
snipe
001348c638 Unset required on checkout select :(
Related to the discussion at #15552

Signed-off-by: snipe <snipe@snipe.net>
2024-09-29 14:33:42 +01:00
snipe
1b041af862 Merge remote-tracking branch 'origin/master' into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-09-29 11:25:01 +01:00
snipe
260b153689 Merge pull request #15573 from snipe/fixed_requiredness_indicator
Fixes for requiredness indicator in UI
2024-09-28 16:09:51 +01:00
snipe
05d74f7a92 Covered setup pages too
Signed-off-by: snipe <snipe@snipe.net>
2024-09-28 15:42:03 +01:00
snipe
dc85588d7f Don’t show password as required if editing
Signed-off-by: snipe <snipe@snipe.net>
2024-09-28 15:31:44 +01:00
snipe
585f998cae Fixes for requiredness display
Signed-off-by: snipe <snipe@snipe.net>
2024-09-28 15:28:06 +01:00
snipe
d120585f94 Check for valid eula for license, consumable
Signed-off-by: snipe <snipe@snipe.net>
2024-09-27 14:07:30 +01:00
snipe
166a700342 Merge remote-tracking branch 'origin/develop' 2024-09-27 13:37:28 +01:00
snipe
36b27fcda3 Check for valid category before getting the eula
Signed-off-by: snipe <snipe@snipe.net>
2024-09-27 13:37:14 +01:00
snipe
a44490e448 Nowrap on files column
Signed-off-by: snipe <snipe@snipe.net>
2024-09-27 13:07:24 +01:00
snipe
9aada2ec70 Merge pull request #15498 from Godmartinz/Modal_fix
Refactoring modals with partials and fixing misalignments
2024-09-26 09:09:35 +01:00
Godfrey M
3f74ff25d2 fixed error message 2024-09-25 16:19:09 -07:00
Godfrey M
ef82f954e5 fixed required css, and user input lengths 2024-09-25 15:47:57 -07:00
Brady Wetherington
3f311ba2fb Get us better debugging output for new Github Stale Action 2024-09-25 21:27:45 +01:00
Godfrey Martinez
96953aa2ed Merge pull request #23 from Godmartinz/Modal_fix_p3
replace duplicate code with partials
2024-09-25 12:50:01 -07:00
Godfrey M
b797c37acb replace duplicate code with partials 2024-09-25 12:48:05 -07:00
snipe
6c85ba3495 Merge remote-tracking branch 'origin/develop' 2024-09-25 20:45:02 +01:00
snipe
ac6411743b Merge pull request #15563 from snipe/refined_gates_on_user_bulk
Update for #15534 - Refined gates on user bulk
2024-09-25 20:35:58 +01:00
snipe
3f0245f88f Make controller gate match dropdown gate
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 20:33:00 +01:00
snipe
c02647a0fa Moved merge into delete gate, since they do technically delete
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 20:32:03 +01:00
snipe
edca3f432c Removed gate for delete
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 20:30:58 +01:00
snipe
2218c94aa3 Gates the dropdown based on user permissions
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 20:29:23 +01:00
Godfrey Martinez
e609b39760 Merge pull request #22 from Godmartinz/Modal_fix_p2
Modal fix p2
2024-09-25 12:09:26 -07:00
Godfrey M
12522a3791 fix spacing issues 2024-09-25 12:07:15 -07:00
snipe
f6d7ea19e4 Set view as base permission, drill down for more intrusive actions
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 19:44:39 +01:00
Godfrey M
18ddffe8f9 fix partial variable intialization, fix width of input fields 2024-09-25 11:42:16 -07:00
snipe
9b03f46490 Merge pull request #15534 from marcusmoore/bulk-print-users
Added the ability to bulk print users
2024-09-25 19:32:01 +01:00
Godfrey M
926a319552 Merge branch 'develop' into Modal_fix_p2 2024-09-25 11:10:24 -07:00
snipe
9f8473e254 Merge remote-tracking branch 'origin/develop' 2024-09-25 18:36:40 +01:00
snipe
cb6e5042d9 Merge pull request #15547 from snipe/disallow_checkout_with_nondeployable_status
Fixed #13396 - do not allow checkout to undeployable status types
2024-09-25 18:32:59 +01:00
snipe
c1a887b48b Merge pull request #15561 from snipe/fixes/adds_action_date_to_sorting
Changed `action_date` to `created_at` in activity report
2024-09-25 18:32:21 +01:00
snipe
658c94ad8b Changed action_date to created_at
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 17:25:15 +01:00
snipe
0e61d0b195 Merge remote-tracking branch 'origin/develop' 2024-09-25 15:51:38 +01:00
snipe
ba12204842 Merge pull request #15555 from snipe/fixes/user_file_upload
Fixed case on `$logAction` for user file upload
2024-09-25 15:51:14 +01:00
snipe
1c3babacaf Fixed case on logAction for usewr file upload
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 15:46:57 +01:00
snipe
abdddbec44 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-09-25 11:58:25 +01:00
snipe
eeabc8dc9d Dev assets
Signed-off-by: snipe <snipe@snipe.net>
2024-09-25 11:33:45 +01:00
snipe
21f8ac8e52 Merge pull request #15552 from Godmartinz/ragged-form-inputs
Fixed input field misalignments
2024-09-25 11:31:23 +01:00
snipe
a425c2b765 Merge remote-tracking branch 'origin/develop' 2024-09-25 10:52:19 +01:00
Godfrey M
2a2666be0b makes required a pseudo field 2024-09-24 13:24:50 -07:00
snipe
c38222e956 Merge pull request #15549 from snipe/fixes/#15548_unify_audit_api_endpoints
Fixes #15548 - unify audit api endpoints
2024-09-24 18:10:53 +01:00
snipe
0ce5832b6c Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 17:29:40 +01:00
Brady Wetherington
b6340532d7 Improve the error and success messages and linking 2024-09-24 17:15:39 +01:00
snipe
5fb43dd159 Handle audit *and* audits for urls
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 16:55:56 +01:00
snipe
de57d71bf1 Fixed #15548 - unify audit due/overdue APIs
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 16:30:24 +01:00
snipe
ba69259f2d Fixed #13396 - do not allow checkout to undeployable status types
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 15:35:00 +01:00
Brady Wetherington
c71411465a First pass at better-handling those annoying Rollbars we keep getting 2024-09-24 15:17:35 +01:00
snipe
8cf1e4dceb Merge pull request #15544 from snipe/bug/sc-26855
Fixed app settings view on mobile
2024-09-24 11:10:20 +01:00
snipe
66249a37ed Tweaked styles
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 11:08:31 +01:00
snipe
96712cb398 Fixed app settings view on mobile
Signed-off-by: snipe <snipe@snipe.net>
2024-09-24 10:55:26 +01:00
Marcus Moore
fac4833b58 Remove unused import 2024-09-23 17:15:16 -07:00
Marcus Moore
a12c9d053f Hide label when printing 2024-09-23 16:44:25 -07:00
Marcus Moore
8b3b68b308 Show or hide all eulas at once when printing multiple users 2024-09-23 16:43:14 -07:00
Marcus Moore
4b02db5031 Add authorization check in bulk users controller 2024-09-23 16:26:22 -07:00
Marcus Moore
ab90c0cf05 Add missing eager load in bulk users controller 2024-09-23 16:10:40 -07:00
Marcus Moore
cef7ddc719 Add eager loads to userscontroller 2024-09-23 16:10:21 -07:00
Marcus Moore
3870095a28 Fix Cannot read properties of undefined error by removing snipe-table class from eula table 2024-09-23 15:50:24 -07:00
Marcus Moore
a02e250b22 Add page breaks for each user 2024-09-23 15:26:15 -07:00
Marcus Moore
8ac5c0e471 Re-combine layout and view 2024-09-23 14:05:47 -07:00
Marcus Moore
a2d4dcf6e8 Use bulk actions menu 2024-09-23 12:49:36 -07:00
Marcus Moore
54044bfa5e Add eager loads 2024-09-23 10:57:57 -07:00
Marcus Moore
e493cc964d Remove AssetCountForSidebar middleware from print view 2024-09-23 10:48:07 -07:00
Marcus Moore
29af210f4f Merge branch 'develop' into bulk-print-users 2024-09-23 10:26:20 -07:00
snipe
34eb10ff73 Merge remote-tracking branch 'origin/develop' 2024-09-20 19:45:20 +01:00
snipe
ab0c009c0d Fixed seeder
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 19:45:10 +01:00
snipe
7d7d58769c Merge remote-tracking branch 'origin/develop' 2024-09-20 19:13:00 +01:00
snipe
b68805cf83 Small fix for notifications checkout
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 19:11:52 +01:00
snipe
245d5dc469 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2024-09-20 17:28:15 +01:00
snipe
7d858129d9 Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:44:19 +01:00
snipe
65ce63bc9b Merge pull request #15537 from snipe/snyk/updated_jspdf_autotable
Updated jspdf autotable
2024-09-20 14:42:07 +01:00
snipe
54fba2f547 Update jspdf autotable
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:40:41 +01:00
snipe
5eea9d1950 Corrected text warning translation
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:33:56 +01:00
snipe
b84a634ec7 Corrected comment
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:33:35 +01:00
snipe
2fc88a0e08 Eager load adminuser
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:33:26 +01:00
snipe
bc540b6564 Requestable status not saving with manual [sc-26848]
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 14:02:28 +01:00
snipe
f53b852dff Make created_by equal one in the seeder
Signed-off-by: snipe <snipe@snipe.net>
2024-09-20 13:53:52 +01:00
snipe
b83d1a043f Merge pull request #15519 from snipe/features/add_created_at_created_by
Change `user_id` to `created_by`
2024-09-20 13:47:31 +01:00
snipe
4ab478bb97 Merge remote-tracking branch 'origin/develop' 2024-09-20 13:44:45 +01:00
snipe
b21c303e56 Merge remote-tracking branch 'origin/develop' into features/add_created_at_created_by 2024-09-20 13:43:50 +01:00
Marcus Moore
5128fd49e6 Allow printing all users 2024-09-19 17:27:25 -07:00
Marcus Moore
2d2d5bdc7e Pass user in array 2024-09-19 17:23:47 -07:00
Marcus Moore
8364d26c9b Extract parent layout 2024-09-19 17:18:26 -07:00
Marcus Moore
efd6d7625f Remove bad closing tag 2024-09-19 17:16:05 -07:00
Marcus Moore
bdf5708bfc Remove accidental line 2024-09-19 17:10:43 -07:00
Marcus Moore
e95703cb18 Use eager load 2024-09-19 17:10:07 -07:00
Marcus Moore
7ad4a29970 Add eager loading 2024-09-19 16:54:39 -07:00
snipe
cdb7ccb8f3 Merge pull request #15532 from spencerrlongg/bug/15253
Catch Exceptions on Checkout Notification
2024-09-19 21:54:03 +01:00
snipe
8270947ed2 Merge pull request #13291 from akemidx/eol_date_range_for_reports
Added date range for EOL in custom reports
2024-09-19 21:49:27 +01:00
snipe
4f7c8e0c3d Merge pull request #14671 from Robert-Azelis/patch-6
[FIX] Update EOL date when used bulk update of purchase date
2024-09-19 21:36:09 +01:00
Marcus Moore
d609ed50a4 Merge branch 'develop' into testing/fmcs-accessories 2024-09-19 13:20:55 -07:00
snipe
b88f2054dd Refactor isDeletable on companies
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 20:38:34 +01:00
snipe
d7914e238d Added created by to company on save
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 20:34:54 +01:00
snipe
d7bde37842 Merge pull request #15507 from setpill/setpill/feat/use_explicit_attributes_in_ldap_sync
Added #15506: Explicitly request used LDAP attributes
2024-09-19 20:33:10 +01:00
snipe
454796e52a Merge pull request #15518 from snipe/sort_by_numeric_custom_fields
Fixed #11634 - Sort by numeric columns for numeric custom fields
2024-09-19 20:32:03 +01:00
snipe
eef487d61b Merge pull request #15531 from Godmartinz/status-doesnt-update-in-email
Fixed mail notification field `status label` not updating
2024-09-19 20:31:02 +01:00
Godfrey M
71dbc7abb0 refreshed the assetstatus relationship 2024-09-19 12:23:07 -07:00
Marcus Moore
d639d6fbc1 Add tests for accessory select list endpoint 2024-09-19 12:21:54 -07:00
snipe
74088ea581 Optimize isDeletable counts
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 20:13:38 +01:00
Marcus Moore
fff069824b Add tests for update accessory endpoint 2024-09-19 12:11:03 -07:00
spencerrlongg
d446773fdd catch exceptions on notification 2024-09-19 14:05:48 -05:00
snipe
f283b5fbe8 Eager load adminuser
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 19:56:39 +01:00
Marcus Moore
a5be18bb14 Add test for limit and offset 2024-09-19 11:55:15 -07:00
snipe
eb6f05faf7 Eager load adminuser
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 19:41:46 +01:00
snipe
118183ff58 Removed footer
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 19:41:39 +01:00
Marcus Moore
2137890496 Remove dead code 2024-09-19 11:33:20 -07:00
snipe
ebf6ce6980 Refactor for fewer queries
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 19:27:10 +01:00
Marcus Moore
9b22d6d493 Add tests for accessory checkouts endpoint 2024-09-19 11:24:01 -07:00
snipe
5ebf0ed2b2 Updated variable
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 19:19:14 +01:00
snipe
836893cba5 Added id to report
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 18:35:00 +01:00
snipe
cd98b3817d Removed duplicate line
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 18:26:08 +01:00
snipe
727806372c Added created_by to status label
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 18:22:11 +01:00
snipe
5e1c736d49 Added created_by for manufacturers
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 18:04:50 +01:00
snipe
6579fa72da Added scoping for categories and companies
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:56:05 +01:00
snipe
82d6e1510f Order by created_by for depreciations
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:41:05 +01:00
snipe
822ea96dfd Use auth()->id() instead of Auth::id()
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:31:46 +01:00
snipe
b247fc33b9 Added legacy comment
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:28:01 +01:00
snipe
2dcae780c0 Reapply deleted code
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:26:21 +01:00
snipe
5c3180ffa0 Removed duplicate code
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:25:09 +01:00
snipe
65eba30038 Fixed markdown in acceptance reminder
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:23:34 +01:00
snipe
bbce7b40ca Additional consistencies
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:20:56 +01:00
snipe
02a29c71ef Added created_by
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:01:48 +01:00
snipe
6699995972 Added created_by to components
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:01:36 +01:00
snipe
951f03094a Added created_by to kits
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 17:01:17 +01:00
snipe
354b00ef15 Made method name consistent
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:45:51 +01:00
snipe
c93229179b Added order by created_by to accessories
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:45:39 +01:00
snipe
a77a7065d7 Added order by admin to assets
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:34:10 +01:00
snipe
4363e8b34c Updated importer
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:20:42 +01:00
snipe
9adb2c24f3 Squashed commit of the following:
commit dddbf27d78
Author: snipe <snipe@snipe.net>
Date:   Wed Sep 18 14:18:52 2024 +0100

    Updated language strings

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

commit fcefcc8184
Merge: 04bb3eec8 3519a82dd
Author: snipe <snipe@snipe.net>
Date:   Wed Sep 18 13:44:44 2024 +0100

    Merge pull request #15512 from marcusmoore/testing/fmcs

    Added tests for delete methods in api

commit 04bb3eec83
Merge: 154d5d8d9 f963b9a19
Author: snipe <snipe@snipe.net>
Date:   Wed Sep 18 13:41:37 2024 +0100

    Merge pull request #15521 from uberbrady/improve_country_selector

    Fix selected-index of Countries drop-down [fd-44144]

commit f963b9a19f
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Wed Sep 18 13:24:26 2024 +0100

    Fix selected-index of Countries drop-down

commit 154d5d8d91
Merge: 6c996b775 9e5f6d656
Author: snipe <snipe@snipe.net>
Date:   Tue Sep 17 23:40:25 2024 +0100

    Merge pull request #15491 from uberbrady/numeric_prefixes_add_multiple_assets

    [Fixes fd-43940] Improve multi-asset create when using numeric prefixes to asset_tags

commit 3519a82ddd
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 16:55:20 2024 -0700

    Fix name: TestsFullMultipleCompaniesSupport

commit a629df07bf
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:49:08 2024 -0700

    Implement interfaces on existing test classes

commit 9a13fcab23
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:38:38 2024 -0700

    Pluralize

commit f5705a1dde
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:34:55 2024 -0700

    More unification

commit f325c4afdb
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:32:38 2024 -0700

    Unify assertion method

commit 1fddacd7d0
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:25:11 2024 -0700

    Re-order test methods

commit 4af893df61
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 14:20:24 2024 -0700

    Improve assertions

commit b8b3f91ce4
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 13:55:18 2024 -0700

    Formatting

commit 7f40f55343
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 13:52:02 2024 -0700

    Add tests for delete supplier endpoint

commit b06e8d442d
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 13:37:08 2024 -0700

    Add tests for delete status label endpoint

commit c269184c60
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 13:29:41 2024 -0700

    Add tests for delete predefined kit endpoint

commit 53c673dee2
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 13:13:12 2024 -0700

    Add tests for delete manufacturer endpoint

commit 50730fc4fb
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 12:37:18 2024 -0700

    Add tests for delete location endpoint

commit 60a54cee79
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 12:33:30 2024 -0700

    Add tests for delete license endpoint

commit 446e962a50
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 10:38:51 2024 -0700

    Add tests for delete group endpoint

commit 79a4bb7316
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 10:35:44 2024 -0700

    Add tests for delete depreciation endpoint

commit 2f76c1bc5b
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 10:33:21 2024 -0700

    Add assertion

commit 38b9f4a438
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Mon Sep 16 10:29:20 2024 -0700

    Add tests for delete departments endpoint

commit 3105f53aff
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 16:54:29 2024 -0700

    Add tests for delete custom fieldsets endpoint

commit 2047cfed09
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 16:20:32 2024 -0700

    Add tests for delete custom fields endpoint

commit e3268d32df
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 16:00:02 2024 -0700

    Add tests for delete consumable endpoint

commit 6df8b0ac0e
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 15:52:07 2024 -0700

    Add tests for delete component endpoint

commit 910f13c1f7
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 15:38:30 2024 -0700

    Add tests for delete companies endpoint

commit 8ce2512f55
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:54:44 2024 -0700

    Add tests for delete category endpoint

commit 0ec415d4d0
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:46:22 2024 -0700

    Clean up

commit 2044570e95
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:39:36 2024 -0700

    Add tests for delete asset model endpoint

commit b336c6273d
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:32:42 2024 -0700

    Pluralize test classes

commit 5299b3e9f0
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:29:44 2024 -0700

    Remove code handled by CompanyableChildTrait

commit 872b76b45f
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:29:10 2024 -0700

    Add tests for delete asset maintenance endpoint

commit 275cf4630e
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:16:37 2024 -0700

    Add tests for delete asset endpoint

commit 5c2660bd34
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 13:02:32 2024 -0700

    Introduce interface

commit c7ae9d9dfa
Author: Marcus Moore <contact@marcusmoore.io>
Date:   Thu Sep 12 12:58:47 2024 -0700

    Add tests for delete accessory endpoint

commit 9e5f6d656a
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Wed Sep 11 15:45:01 2024 +0100

    Improve multi-asset create when using numeric prefixes to asset_tags

Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:06:36 +01:00
snipe
634a4afa75 Fixed 1001 query on license
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:04:54 +01:00
snipe
7650628d30 Removed free seat count from fillable
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 16:00:59 +01:00
snipe
7f690a6238 Fixed variable name
Signed-off-by: snipe <snipe@snipe.net>
2024-09-19 15:58:32 +01:00
Godfrey M
b32ab6a06c import User model 2024-09-18 16:36:24 -07:00
Godfrey M
4ff5fc1ff9 clean up variables 2024-09-18 16:19:35 -07:00
Marcus Moore
86f13a9735 Add index test 2024-09-18 16:13:34 -07:00
Godfrey M
c40209f500 seperates emails and webhook notifications 2024-09-18 15:23:44 -07:00
Marcus Moore
a071fff954 Implement tests 2024-09-18 12:32:14 -07:00
Marcus Moore
8b50ef077d Implement test 2024-09-18 11:58:33 -07:00
Marcus Moore
607f29030f Stub out test 2024-09-18 11:53:27 -07:00
Marcus Moore
a6bcd3c0c2 Add validation test 2024-09-18 11:47:59 -07:00
Marcus Moore
9b293afaac Remove more dead code 2024-09-18 11:28:29 -07:00
Marcus Moore
636c776620 Remove dead code 2024-09-18 11:27:37 -07:00
Marcus Moore
d5f659024c Add test for logging 2024-09-18 11:27:09 -07:00
Marcus Moore
832e50a71e Implement test 2024-09-18 11:19:41 -07:00
Marcus Moore
fa19686248 Implement test 2024-09-18 11:18:21 -07:00
Marcus Moore
c021609c13 Merge branch 'develop' into testing/fmcs-accessories 2024-09-18 10:42:58 -07:00
snipe
655abe8be5 Fixed requestable user_id
Signed-off-by: snipe <snipe@snipe.net>
2024-09-18 14:32:59 +01:00
snipe
d96c5e1ba4 Merge remote-tracking branch 'origin/develop' 2024-09-18 14:20:55 +01:00
snipe
dddbf27d78 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2024-09-18 14:18:52 +01:00
snipe
bae9982833 Updated request methods
Signed-off-by: snipe <snipe@snipe.net>
2024-09-18 14:18:14 +01:00
snipe
a807646d39 Merge remote-tracking branch 'origin/develop' 2024-09-18 13:48:09 +01:00
snipe
abe79df6dc Added translation
Signed-off-by: snipe <snipe@snipe.net>
2024-09-18 13:47:30 +01:00
snipe
fcefcc8184 Merge pull request #15512 from marcusmoore/testing/fmcs
Added tests for delete methods in api
2024-09-18 13:44:44 +01:00
snipe
04bb3eec83 Merge pull request #15521 from uberbrady/improve_country_selector
Fix selected-index of Countries drop-down [fd-44144]
2024-09-18 13:41:37 +01:00
Brady Wetherington
f963b9a19f Fix selected-index of Countries drop-down 2024-09-18 13:24:26 +01:00
snipe
154d5d8d91 Merge pull request #15491 from uberbrady/numeric_prefixes_add_multiple_assets
[Fixes fd-43940] Improve multi-asset create when using numeric prefixes to asset_tags
2024-09-17 23:40:25 +01:00
snipe
1582d81e5b Change user_id to created_by
Signed-off-by: snipe <snipe@snipe.net>
2024-09-17 22:16:41 +01:00
snipe
7c85ad54eb Sort by numeric columns for numeric custom fields
Signed-off-by: snipe <snipe@snipe.net>
2024-09-17 19:44:03 +01:00
Marcus Moore
7b31df7c14 Begin additional test case 2024-09-17 09:11:58 -07:00
snipe
83b4bf9cf8 Merge remote-tracking branch 'origin/develop' 2024-09-17 15:54:53 +01:00
snipe
6c996b7759 Merge pull request #15516 from snipe/fixes/fmcs_edit_user
Fixed check for outside assets on user update validation
2024-09-17 15:54:11 +01:00
snipe
9e957baeb5 Fixed check for outside assets on user update validation
Signed-off-by: snipe <snipe@snipe.net>
2024-09-17 15:46:45 +01:00
Marcus Moore
12fd9cd97a Update interface name 2024-09-16 17:00:08 -07:00
Marcus Moore
9e03c4ba6f Merge branch 'testing/fmcs' into testing/fmcs-accessories 2024-09-16 16:58:46 -07:00
Marcus Moore
3519a82ddd Fix name: TestsFullMultipleCompaniesSupport 2024-09-16 16:55:20 -07:00
Marcus Moore
8eb1c487bc implement FMCS test for accessory index 2024-09-16 16:52:10 -07:00
Marcus Moore
e835637ef0 Add accessory checkin test 2024-09-16 16:40:10 -07:00
Marcus Moore
eb35608bb5 Remove call handled by form request 2024-09-16 16:35:33 -07:00
Marcus Moore
3f07f682de Migrate existing tests to TestsPermissionsRequirement 2024-09-16 16:35:21 -07:00
Marcus Moore
a629df07bf Implement interfaces on existing test classes 2024-09-16 14:49:08 -07:00
Marcus Moore
9a13fcab23 Pluralize 2024-09-16 14:38:38 -07:00
Marcus Moore
f5705a1dde More unification 2024-09-16 14:34:55 -07:00
Marcus Moore
f325c4afdb Unify assertion method 2024-09-16 14:32:38 -07:00
Marcus Moore
1fddacd7d0 Re-order test methods 2024-09-16 14:25:11 -07:00
Marcus Moore
4af893df61 Improve assertions 2024-09-16 14:20:24 -07:00
Marcus Moore
b8b3f91ce4 Formatting 2024-09-16 13:55:18 -07:00
Marcus Moore
7f40f55343 Add tests for delete supplier endpoint 2024-09-16 13:52:02 -07:00
Marcus Moore
b06e8d442d Add tests for delete status label endpoint 2024-09-16 13:37:08 -07:00
Marcus Moore
c269184c60 Add tests for delete predefined kit endpoint 2024-09-16 13:29:41 -07:00
Marcus Moore
53c673dee2 Add tests for delete manufacturer endpoint 2024-09-16 13:13:12 -07:00
Marcus Moore
50730fc4fb Add tests for delete location endpoint 2024-09-16 12:37:18 -07:00
Marcus Moore
60a54cee79 Add tests for delete license endpoint 2024-09-16 12:33:30 -07:00
Marcus Moore
446e962a50 Add tests for delete group endpoint 2024-09-16 10:38:51 -07:00
Marcus Moore
79a4bb7316 Add tests for delete depreciation endpoint 2024-09-16 10:35:44 -07:00
Marcus Moore
2f76c1bc5b Add assertion 2024-09-16 10:33:21 -07:00
Marcus Moore
38b9f4a438 Add tests for delete departments endpoint 2024-09-16 10:29:20 -07:00
snipe
fe5fc6e0ce Merge pull request #15471 from Godmartinz/Edit_side-panel
Fixes margin for the sidebar menus while using rtl languages
2024-09-16 15:56:31 +01:00
snipe
62747a0090 Merge pull request #15493 from Godmartinz/fix_consumables_media_sizing
Fixed misalignment of consumables with smaller media
2024-09-16 15:02:55 +01:00
snipe
9ff2111055 Merge remote-tracking branch 'origin/develop' 2024-09-16 14:52:48 +01:00
snipe
b465cc98d8 Merge pull request #15510 from snipe/bulk_users_locale_fix
Fixed #15504 - allow nulling/not changing locale in user bulk edit
2024-09-16 14:45:06 +01:00
snipe
4debaaea39 Fixed #15504 - allow nulling/not changing locale in user bulk edit
Signed-off-by: snipe <snipe@snipe.net>
2024-09-16 14:31:10 +01:00
snipe
1328366a48 Merge remote-tracking branch 'origin/develop' 2024-09-16 12:38:56 +01:00
setpill
4facc4007e feat: Explicitly request LDAP attributes during sync 2024-09-13 17:05:48 +02:00
setpill
31da47e046 refactor: Put LDAP attribute mapping in array 2024-09-13 17:05:28 +02:00
Marcus Moore
3105f53aff Add tests for delete custom fieldsets endpoint 2024-09-12 16:54:29 -07:00
Marcus Moore
2047cfed09 Add tests for delete custom fields endpoint 2024-09-12 16:20:32 -07:00
Marcus Moore
e3268d32df Add tests for delete consumable endpoint 2024-09-12 16:00:02 -07:00
Marcus Moore
6df8b0ac0e Add tests for delete component endpoint 2024-09-12 15:52:07 -07:00
Marcus Moore
910f13c1f7 Add tests for delete companies endpoint 2024-09-12 15:38:30 -07:00
Marcus Moore
8ce2512f55 Add tests for delete category endpoint 2024-09-12 13:54:44 -07:00
Marcus Moore
0ec415d4d0 Clean up 2024-09-12 13:46:22 -07:00
Marcus Moore
2044570e95 Add tests for delete asset model endpoint 2024-09-12 13:39:36 -07:00
Marcus Moore
b336c6273d Pluralize test classes 2024-09-12 13:32:42 -07:00
Marcus Moore
5299b3e9f0 Remove code handled by CompanyableChildTrait 2024-09-12 13:29:44 -07:00
Marcus Moore
872b76b45f Add tests for delete asset maintenance endpoint 2024-09-12 13:29:10 -07:00
Marcus Moore
275cf4630e Add tests for delete asset endpoint 2024-09-12 13:16:37 -07:00
Marcus Moore
5c2660bd34 Introduce interface 2024-09-12 13:02:32 -07:00
Marcus Moore
c7ae9d9dfa Add tests for delete accessory endpoint 2024-09-12 12:58:47 -07:00
Godfrey M
0bc98e971f refactoring modals with partials and fixing misalignments 2024-09-12 12:26:19 -07:00
snipe
8774da3921 Merge pull request #15492 from snipe/fixes/edit_to_archived_warning
Fix - warn user on changing status to undeployable when editing
2024-09-12 16:08:44 +01:00
Godfrey M
c6c5cb73cf fixes consumables positioning with smaller media 2024-09-11 10:49:27 -07:00
snipe
a97530367d Fixed tests again
Signed-off-by: snipe <snipe@snipe.net>
2024-09-11 17:29:22 +01:00
snipe
43250ae881 Updated tests
Signed-off-by: snipe <snipe@snipe.net>
2024-09-11 17:04:09 +01:00
snipe
04e96b8f20 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2024-09-11 16:43:41 +01:00
snipe
98323185de Null and warn if editing asset to a non-deployabe state
Signed-off-by: snipe <snipe@snipe.net>
2024-09-11 16:43:33 +01:00
Brady Wetherington
9e5f6d656a Improve multi-asset create when using numeric prefixes to asset_tags 2024-09-11 15:45:01 +01:00
snipe
7e14f8c6d6 Merge remote-tracking branch 'origin/develop' 2024-09-11 12:25:28 +01:00
snipe
ab3b655312 Fixed #15483 - show EOL by default
Signed-off-by: snipe <snipe@snipe.net>
2024-09-11 12:25:09 +01:00
snipe
601d8d7e5f Merge pull request #15486 from marcusmoore/fixes/custom-field-values
Fixed a couple bugs in CustomFieldSetDefaultValuesForModel component
2024-09-11 09:46:58 +01:00
Marcus Moore
ca01261c1f Merge branch 'develop' into fixes/custom-field-values 2024-09-10 16:05:39 -07:00
Godfrey M
15183c4822 rephrased the ternary <-correctly spelled 2024-09-10 11:05:03 -07:00
snipe
fddbdafb99 Fixed conflict
Signed-off-by: snipe <snipe@snipe.net>
2024-09-10 19:03:56 +01:00
snipe
a5dbece1a9 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-09-10 19:00:05 +01:00
snipe
4f0f72b29e Fixed version
Signed-off-by: snipe <snipe@snipe.net>
2024-09-10 18:15:12 +01:00
snipe
4183d1834f Pre-release assets
Signed-off-by: snipe <snipe@snipe.net>
2024-09-10 18:14:03 +01:00
snipe
713bb104ec Merge remote-tracking branch 'origin/develop' 2024-09-10 14:46:15 +01:00
snipe
4998d60f39 Merge pull request #15481 from snipe/localizations/2024-09-10
Updated translations
2024-09-10 14:43:27 +01:00
snipe
7cf30003b6 Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2024-09-10 14:41:08 +01:00
snipe
f6bf2d03c4 Merge pull request #15445 from Godmartinz/eula_confusion
Fixed priority for category eula vs default eula
2024-09-10 11:04:58 +01:00
snipe
6f44441a8b Merge pull request #15469 from marcusmoore/accessory_tests
Added UI tests for creating accessories
2024-09-10 11:04:23 +01:00
snipe
e7e5dfbdfa Merge pull request #15470 from marcusmoore/company_tests
Added UI tests for creating companies
2024-09-10 11:04:08 +01:00
snipe
d62315fbe4 Merge pull request #15472 from marcusmoore/testing/dashboard_counts
Added test for dashboard counts
2024-09-10 11:03:55 +01:00
snipe
7f3f77dec8 Merge pull request #15473 from marcusmoore/testing/accessory_api_tests
Added some permission tests for accessory api endpoints
2024-09-10 11:03:46 +01:00
snipe
82e56c6832 Merge pull request #15474 from marcusmoore/bug/sc-26730
Fixed login success message not being displayed
2024-09-10 09:37:02 +01:00
Marcus Moore
76c9015aa9 Add test case 2024-09-09 16:51:40 -07:00
Marcus Moore
5d5f421294 Add test case 2024-09-09 16:49:43 -07:00
Godfrey M
367f02af86 more partials and includes 2024-09-09 16:34:04 -07:00
Godfrey M
7a1c721eca making modal partials for reuse 2024-09-09 16:22:56 -07:00
Marcus Moore
6423df2133 Merge branch 'develop' into fixes/custom-field-values
# Conflicts:
#	resources/views/livewire/custom-field-set-default-values-for-model.blade.php
2024-09-09 16:07:37 -07:00
Marcus Moore
dc6a5bf998 Reflash session so login message is displayed 2024-09-09 14:54:19 -07:00
Marcus Moore
0820dd9da4 Update test names 2024-09-09 14:36:32 -07:00
Marcus Moore
aa6ab2df60 Add permission tests for some accessory api endpoints 2024-09-09 14:35:38 -07:00
Marcus Moore
22a2cc0256 Add test for dashboard counts 2024-09-09 13:21:10 -07:00
Godfrey M
57fab0268b made it a terenary 2024-09-09 13:02:25 -07:00
Godfrey M
ad5768d8b2 fixes margin for the sidebar using rtl languages 2024-09-09 12:45:11 -07:00
Marcus Moore
35533c39d5 Merge branch 'develop' into company_tests 2024-09-09 12:18:02 -07:00
Marcus Moore
de403f6e07 Merge branch 'develop' into accessory_tests 2024-09-09 12:17:53 -07:00
snipe
549dec9f9e Merge pull request #15468 from marcusmoore/coverage
Added coverage commands for Herd users
2024-09-09 20:13:01 +01:00
Marcus Moore
d4426e4686 Add simple tests for company creation via UI 2024-09-09 11:03:00 -07:00
snipe
b2a6349243 Merge pull request #15465 from snipe/update_city_on_bulk_user_edit
Correctly save user’s city on bulk edit
2024-09-09 10:06:42 +01:00
snipe
c5dbc5f6b8 Correctly save user’s city on bulk edit
Signed-off-by: snipe <snipe@snipe.net>
2024-09-09 10:01:07 +01:00
snipe
7f2cae4f26 Merge remote-tracking branch 'origin/develop' 2024-09-09 03:56:05 +01:00
snipe
ce97e2a30f Merge pull request #15463 from snipe/consumables_order_by_remaining
Added ability to sort on qty and remaining for consumables
2024-09-09 03:54:28 +01:00
snipe
7d9a0eba04 Added ability to sort on qty and remaining for consumables
Signed-off-by: snipe <snipe@snipe.net>
2024-09-09 03:49:58 +01:00
Marcus Moore
010f66f4c9 Add validation test 2024-09-04 15:48:11 -07:00
Marcus Moore
9c6718b459 Organize 2024-09-04 15:46:35 -07:00
Marcus Moore
9f832a93c9 Ensure user is stored 2024-09-04 15:44:52 -07:00
Marcus Moore
487d88c012 Add some ui tests for accessories 2024-09-04 15:43:01 -07:00
Marcus Moore
0e9f7153c0 Add composer commands for generating coverage reports via Herd 2024-09-04 15:13:45 -07:00
Godfrey M
7c8955b126 revert changes to label view 2024-09-04 12:38:35 -07:00
Godfrey M
20fa4c39f9 adds setEula to support\settings 2024-09-04 12:26:44 -07:00
Godfrey M
f04a4a3cf5 adds test 2024-09-04 12:21:49 -07:00
Godfrey M
cf07186ae8 gives priority to default eula being checked vs catregory eula 2024-09-03 12:23:23 -07:00
Marcus Moore
51d63d57c6 Hide the "Add default values" checkbox if no fieldset selected 2024-09-03 12:22:43 -07:00
snipe
e34f549e4c Merge remote-tracking branch 'origin/develop' 2024-09-02 19:16:23 +01:00
snipe
e1fcfc8dc1 Merge pull request #15440 from snipe/fixes/user_api_put_patch
Fixes  #15435 - user api put patch API route regression
2024-09-02 19:14:49 +01:00
snipe
9fe8a866e0 Updated test
Signed-off-by: snipe <snipe@snipe.net>
2024-09-02 19:07:21 +01:00
snipe
e8e3060a75 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2024-09-02 18:51:22 +01:00
snipe
6aaf2f623f Removed extra route
Signed-off-by: snipe <snipe@snipe.net>
2024-09-02 18:49:55 +01:00
snipe
dfbccf50e8 Added patch/put back into resource routes
Signed-off-by: snipe <snipe@snipe.net>
2024-09-02 18:48:09 +01:00
snipe
a8813cca94 Merge remote-tracking branch 'origin/develop' 2024-08-31 13:48:59 +01:00
snipe
13dbf9ee74 Added icon for dept
Signed-off-by: snipe <snipe@snipe.net>
2024-08-31 13:48:42 +01:00
snipe
f8bbb7ad9b Merge pull request #15431 from snipe/add_employee_num_to_asset_overview
Added employee number to asset view
2024-08-31 13:47:25 +01:00
snipe
3c7d455ee3 Added employee number to asset view
Signed-off-by: snipe <snipe@snipe.net>
2024-08-31 13:38:38 +01:00
snipe
9fef27a448 Merge remote-tracking branch 'origin/develop' 2024-08-29 21:07:56 +01:00
snipe
12fa505972 Disabmiguate licenses company_id
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 21:07:30 +01:00
snipe
d2b88a5107 Merge remote-tracking branch 'origin/develop' 2024-08-29 21:02:21 +01:00
snipe
4e4930ba62 Check for array
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 21:01:48 +01:00
snipe
4e35f389df Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-08-29 20:07:03 +01:00
snipe
76301bc30d Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 20:05:03 +01:00
snipe
964e105cf9 Merge pull request #15415 from snipe/rules/prevent_company_switch
Validation rules to prevent switching user companies if items are assigned to them
2024-08-29 19:20:03 +01:00
snipe
6fd24c7e14 Merge pull request #15418 from snipe/added_multiple_for_custom_report
Fixed #15416 - Added multiple selects for custom report
2024-08-29 18:55:11 +01:00
snipe
231bc1e2de Updated blade selectors
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 18:31:34 +01:00
snipe
37d04b7176 Some CSS tweaks for select2
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 17:52:01 +01:00
snipe
e62a802926 Use whereIn instead of where =
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 17:51:44 +01:00
snipe
69e981364a Made multiple select
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 17:51:20 +01:00
snipe
e5b9d9a28b Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/js/build/app.js
#	public/js/build/vendor.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2024-08-29 15:04:32 +01:00
snipe
abb4221539 Validation rules to prevent switchng user companies if assets are assigned
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 14:55:18 +01:00
snipe
e4ebabdaba Merge pull request #15414 from uberbrady/fix_create_user
Use the null-safe property accessor for new-user creation
2024-08-29 14:19:51 +01:00
Brady Wetherington
da1e383295 Use the null-safe property accessor for new-user creation 2024-08-29 14:09:23 +01:00
snipe
b64ed254e0 Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 13:49:09 +01:00
snipe
ba291edc42 Merge pull request #15412 from uberbrady/ImprovePatchPurchasePrice
Fix [FD-43836] PATCH of purchase_cost for assets for comma as decimal separator
2024-08-29 13:18:52 +01:00
Brady Wetherington
ec2ea955d8 Fix PATCH of purchase_cost for assets for comma as decimal separator 2024-08-29 12:35:14 +01:00
snipe
c197644ba7 Merge pull request #15284 from spencerrlongg/bug/sc-26584
[Multi-Company] Fixes Users Being Moved With Items Still Assigned
2024-08-29 11:38:15 +01:00
snipe
29b30cc5d3 Merge pull request #15411 from snipe/snyk/upgrade-webpack
Upgraded webpack
2024-08-29 11:29:44 +01:00
snipe
6af27516dc Upgraded webpack
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 11:29:00 +01:00
snipe
a89f17a145 Merge pull request #15410 from snipe/snyk/upgrade-jquery-ui
Updated jquery UI
2024-08-29 11:25:56 +01:00
snipe
de0565f5b3 Updated jquery UI
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 11:24:06 +01:00
snipe
4111ef0d78 Merge remote-tracking branch 'origin/develop' 2024-08-29 11:20:21 +01:00
snipe
68c708bdef Merge pull request #15409 from snipe/fixes-string
Corrected language string
2024-08-29 11:18:34 +01:00
snipe
5581950fee Corrected language string
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 11:17:17 +01:00
snipe
cfa56e2219 Merge remote-tracking branch 'origin/develop' 2024-08-29 11:08:53 +01:00
snipe
58e366a063 Merge pull request #15408 from snipe/redirect-on-print-if-user-invalid
Check that the user exists before trying to print
2024-08-29 11:08:02 +01:00
snipe
b06c527767 Check that the user exists before trying to print
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 11:06:30 +01:00
snipe
7f1dfcc935 Merge remote-tracking branch 'origin/develop' 2024-08-28 14:29:06 +01:00
snipe
26f28a862a Merge pull request #15404 from snipe/bug/sc-26717-model-delete
Set image to null if model is deleted
2024-08-28 14:26:03 +01:00
snipe
94c981e22c Set image to null if model is deleted
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 14:23:49 +01:00
snipe
6f3fb21fef Merge remote-tracking branch 'origin/develop' 2024-08-28 12:50:19 +01:00
snipe
e8da7e2df2 Merge pull request #15403 from snipe/clean_up_depreciations
Fixed #15392 - filter by depreciation when showing models
2024-08-28 12:46:48 +01:00
snipe
d635c86e00 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:46:30 +01:00
snipe
406ff6984b Added click to select on models table
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:42:23 +01:00
snipe
c6ddc501c5 Filter by depreciation_id
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:40:12 +01:00
snipe
4839181beb Added counts to API
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:40:01 +01:00
snipe
63a05c89a7 Added counts to show method
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:39:52 +01:00
snipe
385c4f69f7 Added counts to depreciation transformer
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:39:43 +01:00
snipe
486cd8c8c9 Nicer formatting for searchableAttributes
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:39:09 +01:00
snipe
eb5d93b3c2 Added assets relationship
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:38:55 +01:00
snipe
a5ff623484 Added asset, license, model count to API
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:38:43 +01:00
snipe
b5a4389815 Added badge count, fixed model bulk edit menu
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 12:38:31 +01:00
snipe
7b5b559baa Merge pull request #15401 from snipe/fixes-15397-new-window-for-label
Opens label new window
2024-08-28 11:57:29 +01:00
snipe
67a9929745 Opens label new window
Signed-off-by: snipe <snipe@snipe.net>
2024-08-28 11:56:54 +01:00
snipe
a48e79a1fc Merge remote-tracking branch 'origin/develop' 2024-08-27 07:37:53 +01:00
snipe
64c4433b98 Merge pull request #15396 from snipe/add_start_end_date_to_users_edit
Added `start_date` and `end_date` to user bulk edit
2024-08-27 07:36:37 +01:00
snipe
22bc088f6f Added start_date and end_date to user bulk edit
Signed-off-by: snipe <snipe@snipe.net>
2024-08-27 07:21:19 +01:00
snipe
d3e8e06638 Add @swift2512 as a contributor 2024-08-26 14:07:06 +01:00
snipe
c207d48430 Merge remote-tracking branch 'origin/develop' 2024-08-26 14:01:38 +01:00
snipe
1b933f7add Added s to fa icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-26 13:47:17 +01:00
snipe
991e48696a Merge remote-tracking branch 'origin/develop' 2024-08-26 10:26:06 +01:00
snipe
3fe891a05b Removed a few more commas
Signed-off-by: snipe <snipe@snipe.net>
2024-08-26 10:25:27 +01:00
snipe
7974885041 Merge remote-tracking branch 'origin/develop' 2024-08-26 10:24:19 +01:00
snipe
f4c5b712f4 Removed colons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-26 10:24:07 +01:00
snipe
4ef85bd529 Merge remote-tracking branch 'origin/develop' 2024-08-23 17:58:08 +01:00
snipe
4c8dc7818d Merge pull request #15389 from snipe/added_generate_label_to_button_stack
Fixed #15388 - Moved generate label  button
2024-08-23 17:57:00 +01:00
snipe
5c43a1f87c Use proper style for buttons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 17:54:49 +01:00
snipe
d3b265de8e Moved button on hardware
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 17:48:36 +01:00
snipe
263151658f Moved general label button
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 17:44:09 +01:00
snipe
6eab83a85a Merge remote-tracking branch 'origin/develop' 2024-08-23 15:22:53 +01:00
snipe
aa86e07cd2 Fixed #15385 - small icon tweaks
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 15:22:39 +01:00
snipe
cce1f87da6 Merge remote-tracking branch 'origin/develop' 2024-08-23 15:18:30 +01:00
snipe
d92fa5de65 fa-fw on settings icon
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 15:17:25 +01:00
snipe
b460e8dc83 Merge remote-tracking branch 'origin/develop' 2024-08-23 08:42:32 +01:00
snipe
c589140ea0 Merge pull request #15383 from snipe/re-adds-checkout-button
Fixed #15378 - Corrected gate on checkin button on asset view
2024-08-23 08:42:04 +01:00
snipe
52894615ce More specific gate for checkin
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 08:40:41 +01:00
snipe
8546bbdd65 Fixed gate for checkout button
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 08:38:47 +01:00
snipe
50cb7e65c9 Merge remote-tracking branch 'origin/develop' 2024-08-23 07:32:39 +01:00
snipe
cc2c8f76d0 Merge pull request #15375 from Godmartinz/fix-acceptance-reminder-command
Fixes the `acceptance-reminder` command
2024-08-23 07:31:29 +01:00
snipe
1ffa69c43c Merge pull request #15380 from snipe/fixed/fixed_nav_bracket
Added pull-right to angle bracket
2024-08-23 07:28:20 +01:00
snipe
f85ebd7ffd Added pull-right to angle bracket
Signed-off-by: snipe <snipe@snipe.net>
2024-08-23 07:27:39 +01:00
snipe
78d355f136 Merge pull request #15377 from marcusmoore/fixes/custom-field-values-on-validation-error
Fixed custom field defaults being prematurely updated
2024-08-23 07:20:23 +01:00
snipe
ec0346e4a8 Add @setpill as a contributor 2024-08-23 07:19:08 +01:00
snipe
fc5eb37776 Merge pull request #15379 from setpill/fix/load-trustproxies-middleware
fixed #15374: load TrustProxies middleware in Kernel.php
2024-08-23 07:18:41 +01:00
Marcus Moore
9a73311a99 Fix nested checkboxes being updated as a group 2024-08-22 17:04:04 -07:00
Marcus Moore
aec781e7df Be a little more explicit 2024-08-22 16:03:30 -07:00
setpill
1d7853cbfe fixed #15374: load TrustProxies middleware in Kernel.php 2024-08-22 23:41:27 +02:00
Marcus Moore
7f3c86165b Conditionally disable Add default values checkbox 2024-08-22 13:58:31 -07:00
Marcus Moore
10b45812c4 Improve id for checkboxes and radio buttons 2024-08-22 13:38:01 -07:00
Marcus Moore
c3165717ed Handle old input 2024-08-22 13:20:04 -07:00
Marcus Moore
d0a351a132 Add comment 2024-08-22 12:59:03 -07:00
Marcus Moore
68749e7e87 Simplify logic 2024-08-22 12:58:35 -07:00
Marcus Moore
0abb5637e0 WIP: handle old input 2024-08-22 12:54:54 -07:00
Marcus Moore
af0a95be12 Simplify assertions 2024-08-22 10:18:23 -07:00
Marcus Moore
d67975cb62 Implement fix 2024-08-22 10:18:23 -07:00
Marcus Moore
663b2fd844 Add test case 2024-08-22 10:18:23 -07:00
Marcus Moore
bcace9d019 Point test to correct endpoint 2024-08-22 10:18:23 -07:00
Marcus Moore
b59bf3e7dc Add failing test 2024-08-22 10:18:23 -07:00
Godfrey M
3957d670d0 fixes send acceptance reminder query 2024-08-22 10:04:46 -07:00
snipe
821dd158d1 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2024-08-22 15:50:20 +01:00
snipe
833dace2b4 Merge pull request #15373 from snipe/fixes/#15366_custom_fields
Fixed #15366 use the non-admin edit encrypted custom fields permissions
2024-08-22 15:00:16 +01:00
snipe
56e31d2303 Fixed #15366 - use permission for encrypted custom fields
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 14:58:09 +01:00
snipe
ec365b0804 Merge pull request #15372 from StarlessNights/update-docker-compose-files
Fixed #15371: docker-compose files updated.
2024-08-22 14:49:13 +01:00
Iisakki Jaakkola
aef0ac68c3 Need to use the long format for redis too in docker-compose file. 2024-08-22 16:10:00 +03:00
Iisakki Jaakkola
f12f9a816f Update the official docker-compose file too while at it. 2024-08-22 15:47:12 +03:00
Iisakki Jaakkola
a000d6454f Fix non-functional development docker-compose file. 2024-08-22 15:46:40 +03:00
snipe
ca8864c061 Fixed small layout quirks in asset view
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 13:28:52 +01:00
snipe
423f4f9126 Merge pull request #14667 from Godmartinz/add_location_to_create_user_via_asset
Adds location select to the create new user via asset checkout
2024-08-22 13:25:41 +01:00
snipe
456c7d8d91 Merge pull request #15065 from Godmartinz/explicit_eol_removal_command
Adds `snipeit:remove-explicit-eols` command
2024-08-22 13:20:56 +01:00
snipe
54cfe3f6e6 Merge pull request #15156 from uberbrady/re-add-stalebot
Re-add stalebot-esque github Action
2024-08-22 13:20:10 +01:00
snipe
5e0b18104d Merge pull request #15369 from snipe/fixes/checkbox_on_restore
Fixed checkbox layout on modal from #15296
2024-08-22 12:59:20 +01:00
snipe
8b5d3f7fbd Fixed extra closing p tag
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 12:56:32 +01:00
snipe
744f43676d Fixed checkbox layout on modal from #15296
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 12:53:16 +01:00
snipe
ec0b9b198f Merge pull request #15296 from uberbrady/expose_restore_sanitize
Expose the 'sanitize' system for backup restores to the web GUI
2024-08-22 12:43:07 +01:00
snipe
6c9a402685 Updated prod assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 11:20:52 +01:00
snipe
1b310f3a24 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-08-22 11:20:42 +01:00
snipe
94300d81d6 Updated dev assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 11:19:32 +01:00
snipe
bc9ea5a2ec Merge pull request #15352 from Godmartinz/mobile_breakpoint
Fixed Mobile misalignment of info on Assets and Users view pages
2024-08-22 11:18:06 +01:00
snipe
4635a6efc3 Merge pull request #15360 from snipe/more_print_fixes
More print fixes for asset view
2024-08-22 11:17:49 +01:00
snipe
9608414eae Merge pull request #15367 from snipe/fixes/15344_added_freeform_to_country_select2
Fixed #15344 - make select2 for countries freeform-ish
2024-08-22 11:06:13 +01:00
snipe
5efddf6f5b Allow clear on country dropdown
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 11:01:39 +01:00
snipe
305dc049a4 Added asterisk help text
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 11:01:28 +01:00
snipe
3ac0702094 Fixed #15344 - make select2 for countries freeform-ish
Signed-off-by: snipe <snipe@snipe.net>
2024-08-22 10:13:22 +01:00
snipe
47d8e2f8b9 Add @Scarzy as a contributor 2024-08-22 09:42:05 +01:00
Marcus Moore
a2246b9645 Simplify assertions 2024-08-21 17:00:32 -07:00
Marcus Moore
1d89759706 Implement fix 2024-08-21 16:59:44 -07:00
Marcus Moore
206f8fe605 Add test case 2024-08-21 16:59:38 -07:00
Marcus Moore
21d2217619 Point test to correct endpoint 2024-08-21 16:54:16 -07:00
Marcus Moore
833bcb282f Add failing test 2024-08-21 16:49:29 -07:00
snipe
83dd9ce20e Merge pull request #15362 from r-xyz/model-files-api
Added #9413: AssetModel files endpoints to API
2024-08-21 23:15:24 +01:00
r-xyz
a8eb76fd8d Fixed model files API routes. 2024-08-21 22:25:41 +02:00
r-xyz
cd7db5c4a8 Fix some typos in models file handler. 2024-08-21 22:24:08 +02:00
r-xyz
da7313bc9d Fix models files API routes. 2024-08-21 20:24:22 +02:00
r-xyz
4ec361c718 Add AssetModel files endpoints to API 2024-08-21 19:49:51 +02:00
Brady Wetherington
738ef442fd Rename .env var to have DB_ prefix for sanitize-by-default setting 2024-08-21 13:16:51 +01:00
snipe
d29b3bfb9a Few more hidden-print classes
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 13:06:16 +01:00
snipe
6fdce3c536 Merge pull request #15358 from r-xyz/rename-docker-startup
Renamed  docker startup scripts coherently.
2024-08-21 13:02:50 +01:00
snipe
912bbf0e32 More print fixes
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 13:02:21 +01:00
snipe
c54bff0f83 Merge remote-tracking branch 'origin/develop' 2024-08-21 12:24:13 +01:00
snipe
01c4fe6113 Merge pull request #15359 from uberbrady/improve_windows_upgrade
Fixed #15190 - Improvements to upgrade.php script to improve Windows experience
2024-08-21 12:12:23 +01:00
Brady Wetherington
0fa9f57971 Improvements to upgrade.php script to improve Windows experience 2024-08-21 11:53:38 +01:00
r-xyz
1ab29ec3a4 Rename docker startup scripts coherently. 2024-08-21 11:52:09 +02:00
snipe
7e475a0786 Merge pull request #15357 from snipe/tighten_category_view_translations
Fixed #15330 - Cleaned up category title
2024-08-21 10:41:17 +01:00
snipe
26b3c62ab8 Cleaned up category title
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 10:29:51 +01:00
snipe
d3f30ced94 Merge remote-tracking branch 'origin/develop' 2024-08-21 10:13:57 +01:00
snipe
d0acf5b8a6 Merge pull request #15356 from snipe/validate_location_parent
Fixed #15341 - validate parent ID
2024-08-21 10:12:58 +01:00
snipe
74fbc23823 Updated tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 10:09:35 +01:00
snipe
a23dee52f2 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 09:58:47 +01:00
snipe
4d03f1e110 Fixed #15341 - validate parent ID
Signed-off-by: snipe <snipe@snipe.net>
2024-08-21 09:46:18 +01:00
Godfrey M
963911f2e1 changed order of info stgack 2024-08-21 00:23:10 -07:00
Marcus Moore
59832126cb Improve comment 2024-08-20 16:52:51 -07:00
Marcus Moore
680cce3ee2 Align indents 2024-08-20 16:42:29 -07:00
Marcus Moore
6c5ec6a16c Get datepicker working 2024-08-20 16:41:24 -07:00
Marcus Moore
5d1f98bf93 Simplify by directly wire:modeling 2024-08-20 15:38:43 -07:00
Godfrey M
9d484077ae missed a file 2024-08-20 14:24:37 -07:00
Godfrey M
9858b0f37f fixes info tab for users and assets 2024-08-20 14:23:55 -07:00
snipe
973e2e5756 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2024-08-20 19:45:53 +01:00
snipe
09033b19a7 Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 19:44:13 +01:00
snipe
46ed076428 Merge remote-tracking branch 'origin/develop' 2024-08-20 19:42:56 +01:00
snipe
5fdeb9c413 Merge pull request #15351 from snipe/localizations/new_translations_2024-08-20
Updated languages
2024-08-20 19:42:08 +01:00
snipe
22d3734075 Merge pull request #15350 from marcusmoore/icon-component-updates
Fixed icon not rotated and simplified component
2024-08-20 19:34:38 +01:00
Marcus Moore
eca6b03f44 Allow id to be rendered 2024-08-20 11:08:53 -07:00
Marcus Moore
bbdbec7197 Rely on $attributes behavior rendering passed attributes 2024-08-20 11:00:39 -07:00
snipe
6c450d1338 Updated languages
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 18:18:17 +01:00
spencerrlongg
a8cd1027f3 rm commented code 2024-08-20 11:40:15 -05:00
snipe
d3a555ce91 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 11:49:39 +01:00
snipe
0f8e041809 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2024-08-20 11:49:32 +01:00
snipe
d99b306ae9 Merge pull request #15345 from snipe/add_trim_strings_middleware
Added TrimStrings middleware
2024-08-20 11:46:55 +01:00
snipe
74136761df Added TrimStrings middleware
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 11:45:13 +01:00
snipe
f597d64339 Merge pull request #15342 from snipe/snyk/bs-tables
[Snyk] Upgrade bootstrap-table from 1.23.0 to 1.23.2
2024-08-20 10:17:26 +01:00
snipe
0072f1500e [Snyk] Upgrade bootstrap-table from 1.23.0 to 1.23.2
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 10:16:27 +01:00
snipe
64bed01a91 Merge pull request #15327 from snipe/update_button_style
Update icons to use blade components, standardize button colors and format
2024-08-20 10:13:43 +01:00
snipe
f6319e11e7 Added fa-fw to sidebar elements
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 10:11:27 +01:00
snipe
5d9f988df3 Added fw class to topnav icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-20 10:01:49 +01:00
snipe
f8c72fb0ac Merge pull request #15112 from marcusmoore/livewire-importer-improvements
Improved handling attempted access of deleted files in importer
2024-08-20 09:57:03 +01:00
akemidx
8e1111c681 Merge remote-tracking branch 'upstream/develop' into eol_date_range_for_reports 2024-08-19 19:33:44 -04:00
snipe
886514a25f Merge pull request #15336 from marcusmoore/fixes/remove-displayed-parentheses
Fixed `)` being added to expected asset checkin report email header
2024-08-19 22:46:08 +01:00
Marcus Moore
fa765667f2 Merge branch 'develop' into livewire-importer-improvements 2024-08-19 14:41:58 -07:00
Marcus Moore
434bdcd6d4 Add missing parentheses to conditional 2024-08-19 14:31:47 -07:00
snipe
be5f3f38f8 Settings pages
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 14:48:12 +01:00
snipe
08c3a25b39 Little more padding
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 14:16:57 +01:00
snipe
34cd4b6244 Added links to apple/google maps
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 14:15:36 +01:00
snipe
d89c8682be Reversed location button ordering
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:46:31 +01:00
snipe
6f024849e9 Few more
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:39:24 +01:00
snipe
e048f0955f More icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:27:21 +01:00
snipe
479b2b4fd3 More icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:23:08 +01:00
snipe
84f14a05bd Fixed logging for asset model restore
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:20:19 +01:00
snipe
8d52fa51b1 Fixed suppliers buttons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:20:06 +01:00
snipe
229d8b9bf5 Added location restore
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 13:19:59 +01:00
snipe
eb8d43a804 Updated buttons on models
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 12:32:44 +01:00
snipe
f82266fade Cleaned up presenters
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 11:58:31 +01:00
snipe
b4b6f7a35f Added css-consumable to overrides for table headers
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 11:58:21 +01:00
snipe
0bc995b87f Updated more icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 11:58:05 +01:00
snipe
59725f2031 Removed extra debugging in test
Signed-off-by: snipe <snipe@snipe.net>
2024-08-19 11:57:40 +01:00
snipe
00bc9ac806 Fixed spacing
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 22:39:14 +01:00
snipe
f200960a57 Aaaand more
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 22:26:57 +01:00
snipe
c700127f1a Updated user view
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 22:09:00 +01:00
snipe
ae2f9571b4 And still more
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 21:57:37 +01:00
snipe
a77dcad336 More links
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 20:30:53 +01:00
snipe
7ace9324b4 Added padlock sound
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 20:30:22 +01:00
snipe
d2e889e927 Still more
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 19:21:59 +01:00
snipe
803bdb457c Added calendar
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 18:48:19 +01:00
snipe
7c9b1f6e38 Added the plus icon
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 18:39:22 +01:00
snipe
d545537a43 More icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 18:34:13 +01:00
snipe
4d8904938d Added calendar icon for datepickers
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 18:24:26 +01:00
snipe
0c09f2b2c0 Moar icon replacement
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 18:13:49 +01:00
snipe
bffba02511 Updated icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 17:26:44 +01:00
snipe
901f4df7ee Added more icons
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 17:03:36 +01:00
snipe
9337cba340 Added download
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 15:53:58 +01:00
snipe
2b0c67c263 Load the icon helper
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 15:51:00 +01:00
snipe
da71f031f5 Use icon in hardware view
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 15:48:24 +01:00
snipe
d2e585baa7 Added icon blade
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 15:47:45 +01:00
snipe
a102c085df Added icon helper
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 15:47:37 +01:00
snipe
e8a22f3c5b Merge remote-tracking branch 'origin/develop' 2024-08-18 04:55:04 +01:00
snipe
cb40a82e79 Merge pull request #15324 from snipe/jerk_prevention
Prevent passing an array as login
2024-08-18 04:54:23 +01:00
snipe
4253acad4c Prevent passing an array as login
Signed-off-by: snipe <snipe@snipe.net>
2024-08-18 04:51:36 +01:00
snipe
d843cf8dcc Merge remote-tracking branch 'origin/develop' 2024-08-17 00:52:10 +01:00
snipe
7e6ff3cbe6 Removed trailing rows
Signed-off-by: snipe <snipe@snipe.net>
2024-08-17 00:51:19 +01:00
snipe
1013dcae61 Merge remote-tracking branch 'origin/develop' 2024-08-17 00:38:44 +01:00
snipe
e7ef3bf515 Merge pull request #15322 from snipe/importer_model_fixes
Importer model fixes
2024-08-17 00:37:37 +01:00
snipe
a25efe53aa Removed some debugging
Signed-off-by: snipe <snipe@snipe.net>
2024-08-17 00:35:42 +01:00
snipe
de059a715a Cleaner test CSV
Signed-off-by: snipe <snipe@snipe.net>
2024-08-17 00:30:49 +01:00
snipe
318aff1ef0 Fixed behavior for null model numbers
Signed-off-by: snipe <snipe@snipe.net>
2024-08-17 00:27:44 +01:00
snipe
e96b9b2f4f Added test for models with same name but no model number
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 23:04:11 +01:00
snipe
3ae4a5caf0 Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:53:27 +01:00
snipe
559f0d2f90 Added string
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:53:21 +01:00
snipe
9b6a36c8aa Removed unusued parameter
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:45:57 +01:00
snipe
1a4aebf805 Added TwoColumnUniqueUndeletedTrait trait
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:45:47 +01:00
snipe
6ad7100aa3 Removed unused use statements
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:45:17 +01:00
snipe
5529669884 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:44:03 +01:00
snipe
b57283d8d1 Removed commented code
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 22:43:56 +01:00
snipe
7658f7c41d First shot
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 20:29:53 +01:00
spencerrlongg
70e5e0f9df get rid of dd 2024-08-16 12:52:06 -05:00
spencerrlongg
dec4691c73 should be good to go now 2024-08-16 12:50:09 -05:00
snipe
48903b1402 Added Gate Pass Generator link
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 17:42:42 +01:00
snipe
7376c21f10 Removed dupe link, linked name
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 17:01:07 +01:00
snipe
f921400579 Added link to UnifiSnipeSync
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 16:55:16 +01:00
snipe
c30c649aaa Merge remote-tracking branch 'origin/develop' 2024-08-16 16:44:02 +01:00
snipe
ad6d09b6ad Removed default label
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 16:43:51 +01:00
snipe
bb1385369c Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-08-16 16:18:00 +01:00
snipe
43b338d612 Fixed translation
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 16:15:58 +01:00
snipe
c1caf6088e Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 13:12:13 +01:00
snipe
67655ad84b Dev assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 13:11:33 +01:00
snipe
12dfe71ea8 Merge remote-tracking branch 'origin/develop' 2024-08-16 12:48:42 +01:00
snipe
ea2b1b0748 Merge pull request #15318 from snipe/localization/fixed_strings
Corrected some translations
2024-08-16 12:43:06 +01:00
snipe
856c57cb12 Corrected some translations
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 12:39:59 +01:00
snipe
90584ab803 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2024-08-16 11:11:00 +01:00
snipe
184f54a6cd Removed extra spaces
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 11:10:57 +01:00
snipe
f24031b974 Merge pull request #15206 from Godmartinz/dashboard_box_alignment
Fixed dashboard box overflow
2024-08-16 11:10:40 +01:00
snipe
0a7aaa54b6 Merge pull request #15282 from r-xyz/alpine-secrets
Added support for Docker secrets in Standard and alpine image.
2024-08-16 11:08:09 +01:00
snipe
ca89268716 Merge remote-tracking branch 'origin/develop' 2024-08-16 11:02:56 +01:00
snipe
3167ee91d1 Added a setting test and validation on settings
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 10:51:49 +01:00
snipe
e8f1190628 Added missing migration from #15314
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 10:44:28 +01:00
snipe
44f18d210e Remove MBP constraint
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 10:36:35 +01:00
snipe
e8deecc9b4 Removed MBP constraint on model
This was creating a validation error since the name already exists

Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 10:35:42 +01:00
snipe
a79fe69bf4 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2024-08-16 10:22:16 +01:00
snipe
d49c33fbe3 Add @Glukose1 as a contributor 2024-08-16 10:22:05 +01:00
snipe
de29c1d8a0 Merge pull request #15314 from Glukose1/features/add_setting_due_for_checkin_in_days
Added #15312: Add checkin due in days setting
2024-08-16 10:21:36 +01:00
snipe
f9172594b2 Clearer time example display
Signed-off-by: snipe <snipe@snipe.net>
2024-08-16 10:14:43 +01:00
Marcus Moore
94d8a547b8 Merge branch 'develop' into livewire-importer-improvements 2024-08-15 13:47:49 -07:00
Marcus Moore
43b109fac0 Use cached values for textarea and radio input 2024-08-15 13:20:22 -07:00
Marcus Moore
75c1e7658f Improve method name 2024-08-15 10:43:41 -07:00
Marcus Moore
e7c9c799bb Add wire:keys 2024-08-15 10:40:23 -07:00
Marcus Moore
6ab976f353 Use cached values for text input 2024-08-15 10:32:33 -07:00
snipe
ec5731353a Merge remote-tracking branch 'origin/develop' 2024-08-15 15:53:52 +01:00
snipe
b39a7c6f0c String constraint
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 15:42:11 +01:00
snipe
a3d847151a Model name uniqueness
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 15:19:27 +01:00
snipe
3283704fe8 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 12:25:08 +01:00
snipe
540df32046 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2024-08-15 12:24:59 +01:00
snipe
594f506641 Merge pull request #15305 from snipe/localizations/updated_languages_2024-08-15
Updated translation strings
2024-08-15 12:21:59 +01:00
snipe
dd458dfa7f Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 12:21:06 +01:00
snipe
b917489f00 Corrected string
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 12:10:41 +01:00
snipe
75dfedcb82 Merge pull request #15304 from snipe/confetti_fun_mode_redux
Added confetti option
2024-08-15 11:37:34 +01:00
snipe
6216b4fc0d Use native browser control for required in addition to the css effect
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 11:35:56 +01:00
snipe
4356cb7b9b Added confetti option
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 11:32:42 +01:00
Glukose1
d8df52cc8f Implemented setting to specify the amount of days before an assets appers in the due for checkin page. Currently this uses the audit warning days but a sperated setting gives the possibility of defineing different values for each field. 2024-08-15 12:20:51 +02:00
spencerrlongg
9622e05cf5 correct api test 2024-08-14 18:41:06 -05:00
spencerrlongg
afaf53cdfc failing ui test 2024-08-14 18:14:21 -05:00
spencerrlongg
f031309f8f set up api controller for route/model binding 2024-08-14 16:09:15 -05:00
spencerrlongg
20ec420ba3 not quite done, api side needs some work 2024-08-14 13:53:29 -05:00
Marcus Moore
ab63a19aff Initialize concept of cached values 2024-08-14 11:01:51 -07:00
spencerrlongg
a70b94e707 Merge branch 'refs/heads/develop' into bug/sc-26584 2024-08-14 11:36:19 -05:00
r-xyz
0d7cf55a3a Add support for Docker secrets in Standard and alpine image. 2024-08-14 17:40:52 +02:00
Brady Wetherington
008bf036b5 Got rid of weird namespace declaration and commented-out data-toggle line 2024-08-14 16:09:34 +01:00
Brady Wetherington
cc5ad456e6 Expose the 'sanitize' system for backup restores to the web GUI 2024-08-14 15:59:21 +01:00
Marcus Moore
038e86954b Improve property name 2024-08-13 17:30:53 -07:00
Marcus Moore
f6c1642bf2 Use computed fields in CustomFieldSetDefaultValuesForModel component 2024-08-13 17:01:35 -07:00
spencerrlongg
120cfd13c5 translation 2024-08-13 14:07:40 -05:00
spencerrlongg
09f2739298 works, un-reassignable licenses are an issue 2024-08-13 13:45:41 -05:00
Godfrey M
5d1c48c071 fixes alignment, and box issue with pie chart 2024-08-13 10:11:49 -07:00
spencerrlongg
ec863df007 rm conditional that might be unnecessary 2024-08-12 16:58:53 -05:00
spencerrlongg
cc3b8e0681 this should more or less work, but i need to determine if this is the best way 2024-08-12 16:58:21 -05:00
spencerrlongg
ff145abbe7 use array for eager loading, makes ide prettier 2024-08-12 16:13:03 -05:00
Marcus Moore
6521c02526 Merge branch 'develop' into livewire-importer-improvements
# Conflicts:
#	resources/views/livewire/importer.blade.php
2024-08-07 15:20:39 -07:00
Godfrey M
bc0ff706b0 fixes dashboard box overflow 2024-08-01 10:31:39 -07:00
Brady Wetherington
bb465dbfaa Cut down run number to 100 from 1000 2024-07-24 15:09:23 +01:00
Brady Wetherington
8cbcc237c0 Cleanup of Stale workflow for GH - set to debug-mode to start 2024-07-24 13:27:31 +01:00
Brady Wetherington
97e3af8fc9 WIP on new GitHub-backed stalebot settings 2024-07-24 12:33:26 +01:00
Brady Wetherington
914e29210a Initial rough stab at re-implementing stalebot 2024-07-24 12:33:26 +01:00
Marcus Moore
8d1cc22c58 Turn on legacy binding since other components still use it 2024-07-18 12:00:01 -07:00
Marcus Moore
7685de45f2 Turn off legacy binding 2024-07-17 17:12:14 -07:00
Marcus Moore
199e68ff29 Simplify computed propery 2024-07-17 17:10:12 -07:00
Marcus Moore
81bffccf01 Use better error message 2024-07-17 16:28:26 -07:00
Marcus Moore
cfca1514c0 Swap file_id for activeFileId 2024-07-17 16:22:44 -07:00
Marcus Moore
b4ed01243b Add more details 2024-07-17 13:40:41 -07:00
Marcus Moore
3772a21a51 Move comment up 2024-07-17 13:37:24 -07:00
Marcus Moore
04b6cb763f Add todo 2024-07-17 10:58:48 -07:00
Marcus Moore
dd32341502 Display message if attempting to delete non-existent file 2024-07-16 17:21:18 -07:00
Marcus Moore
f58e3114a2 Simplify destroy method and update list 2024-07-16 17:17:45 -07:00
Marcus Moore
eba494ad8c Make $activeFile a computed property 2024-07-16 17:03:42 -07:00
Marcus Moore
7e89b58746 Move files to computed property 2024-07-16 16:08:42 -07:00
Marcus Moore
b7744105a0 Migrate import type to component 2024-07-16 14:20:41 -07:00
Marcus Moore
69263f0e5b Migrate header row to component 2024-07-16 13:30:29 -07:00
Marcus Moore
017530ba4b Make updating hook more specific 2024-07-16 12:02:50 -07:00
Marcus Moore
c8dad528a8 Migrate a couple items out of mount 2024-07-15 16:15:58 -07:00
Marcus Moore
256e989ba1 Add test for importer 2024-07-15 15:49:18 -07:00
Marcus Moore
9793016603 Remove unneeded AuthorizesRequests 2024-07-11 13:32:16 -07:00
Marcus Moore
9e06f2d17f Remove commented code 2024-07-11 13:22:10 -07:00
Godfrey M
d4d19569ee adds execution timer 2024-07-11 10:52:47 -07:00
Godfrey M
43c7504f89 adds an all option, adds help context for all, seperates logic 2024-07-11 10:03:51 -07:00
Godfrey M
1fa6a763bc updated description 2024-07-10 11:09:57 -07:00
Godfrey M
726308bfd5 removed typo 2024-07-10 10:58:45 -07:00
Godfrey M
22ddb695f2 better description 2024-07-10 10:57:47 -07:00
Godfrey M
09b2feac54 updates assets with selected model to inherit asset model eol 2024-07-10 10:56:44 -07:00
Godfrey M
57e1df86c8 finds model and collects assets with such model 2024-07-10 10:21:24 -07:00
Robert-Azelis
3ea5d4ee40 Update BulkAssetsController.php
Fix for bulk updarte of purchase date to calculate new EOL
2024-05-02 12:55:17 +02:00
Godfrey M
5fa0c87ab0 null debugbar 2024-04-30 12:02:11 -07:00
Godfrey M
75aa01791a adds location select to the create new user vice asset checkout 2024-04-30 11:54:33 -07:00
akemidx
697595d963 Merge branch 'develop' into eol_date_range_for_reports 2023-11-21 16:07:26 -05:00
akemidx
0bdd8a5917 fixing key names 2023-08-02 16:40:38 -04:00
akemidx
e35dd2daa1 asset_eol_date stuff 2023-07-26 17:45:18 -04:00
akemidx
f71b69a739 adding eol fields 2023-07-26 17:31:06 -04:00
akemidx
499a3debcd this WILL break. i'm back to site not found which is something missing. otherwise the columns are either blank or another value like expected checkin i was using to test a bit 2023-07-11 14:08:55 -04:00
1816 changed files with 288011 additions and 11284 deletions

View File

@@ -3181,6 +3181,42 @@
"contributions": [
"code"
]
},
{
"login": "Glukose1",
"name": "Glukose1",
"avatar_url": "https://avatars.githubusercontent.com/u/167117705?v=4",
"profile": "https://github.com/Glukose1",
"contributions": [
"code"
]
},
{
"login": "Scarzy",
"name": "Scarzy",
"avatar_url": "https://avatars.githubusercontent.com/u/1197791?v=4",
"profile": "https://github.com/Scarzy",
"contributions": [
"code"
]
},
{
"login": "setpill",
"name": "setpill",
"avatar_url": "https://avatars.githubusercontent.com/u/37372069?v=4",
"profile": "https://github.com/setpill",
"contributions": [
"code"
]
},
{
"login": "swift2512",
"name": "swift2512",
"avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4",
"profile": "https://github.com/swift2512",
"contributions": [
"bug"
]
}
]
}

View File

@@ -1,6 +1,8 @@
# --------------------------------------------
# REQUIRED: DB SETUP
# --------------------------------------------
# https://mariadb.com/kb/en/mariadb-server-docker-official-image-environment-variables/
MYSQL_DATABASE=snipeit
MYSQL_USER=snipeit
MYSQL_PASSWORD=changeme1234

View File

@@ -97,7 +97,7 @@ API_TOKEN_EXPIRATION_YEARS=40
# --------------------------------------------
# OPTIONAL: SECURITY HEADER SETTINGS
# --------------------------------------------
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1,172.0.0.0/8
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1,172.16.0.0/12
ALLOW_IFRAMING=false
REFERRER_POLICY=same-origin
ENABLE_CSP=false

View File

@@ -32,6 +32,8 @@ DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_SANITIZE_BY_DEFAULT=false
# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS

43
.github/stale.yml vendored
View File

@@ -1,43 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- :woman_technologist: ready for dev
- :moneybag: bounty
- :hand: bug
- "🔐 security"
- "👩‍💻 ready for dev"
- "💰 bounty"
- "✋ bug"
exemptMilestones: true
# Label to use when marking an issue as stale
staleLabel: stale
only: issues
# Comment to post when removing the stale label.
unmarkComment: >
Okay, it looks like this issue or feature request might still be important. We'll re-open
it for now. Thank you for letting us know!
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
Is this still relevant? We haven't heard from anyone in a bit. If so,
please comment with any updates or additional detail.
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Don't
take it personally, we just need to keep a handle on things. Thank you
for your contributions!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been automatically closed because it has not had
recent activity. If you believe this is still an issue, please confirm that
this issue is still happening in the most recent version of Snipe-IT and reply
to this thread to re-open it.

40
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: 'Close stale issues'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
# contents: write # only for delete-branch option
issues: write
# pull-requests: write
steps:
- uses: actions/stale@v9
with:
debug-only: true
ascending: true
operations-per-run: 1000 # just while we're debugging
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 60
days-before-close: 7
exempt-all-milestones: true
stale-issue-message: >
Is this still relevant? We haven't heard from anyone in a bit. If so,
please comment with any updates or additional detail.
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Don't
take it personally, we just need to keep a handle on things. Thank you
for your contributions!
close-issue-message: >
This issue has been automatically closed because it has not had
recent activity. If you believe this is still an issue, please confirm that
this issue is still happening in the most recent version of Snipe-IT and reply
to this thread to re-open it.
# There doesn't seem to be a 'reopen issue message'?
# Since there is no 'stale-pr-message' - PR's should not be stale'd
stale-issue-label: stale
exempt-issue-labels: >
pinned,security,:woman_technologist: ready for dev,:moneybag: bounty,:hand: bug,🔐 security,👩‍💻 ready for dev,💰 bounty,✋ bug

View File

@@ -76,4 +76,4 @@ jobs:
DB_DATABASE: snipeit
DB_PORT: ${{ job.services.mysql.ports[3306] }}
DB_USERNAME: root
run: php artisan test --parallel
run: php artisan test

View File

@@ -74,4 +74,4 @@ jobs:
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
DB_USERNAME: snipeit
DB_PASSWORD: password
run: php artisan test --parallel
run: php artisan test

View File

@@ -58,4 +58,4 @@ jobs:
- name: Execute tests (Unit and Feature tests) via PHPUnit
env:
DB_CONNECTION: sqlite_testing
run: php artisan test --parallel
run: php artisan test

1
.gitignore vendored
View File

@@ -47,6 +47,7 @@ storage/private_uploads/users/*
tests/_data/scenarios
tests/_output/*
tests/_support/_generated/*
tests/coverage/*
/npm-debug.log
/storage/oauth-private.key
/storage/oauth-public.key

View File

@@ -52,6 +52,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/47315739?v=4" width="110px;"/><br /><sub>bilias</sub>](https://github.com/bilias)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -79,12 +79,12 @@ USER root
VOLUME ["/var/lib/snipeit"]
# Entrypoints
COPY docker/entrypoint_alpine.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Startup script
COPY docker/startup_alpine.sh /startup.sh
RUN chmod +x /startup.sh
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]
CMD ["/startup.sh"]
EXPOSE 80

View File

@@ -97,7 +97,7 @@ RUN set -eux; \
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 --chmod=655 docker/startup_alpine_fpm.sh /startup.sh
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" ]
ENTRYPOINT [ "/startup.sh" ]
CMD [ "/startup.sh", "php-fpm" ]

View File

@@ -72,18 +72,23 @@ Since the release of the JSON REST API, several third-party developers have been
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-IT.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT.
- [WWW::SnipeIT](https://github.com/SEDC/perl-www-snipeit) by [@SEDC](https://github.com/SEDC) - perl module for accessing the API
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by [@ReticentRobot](https://github.com/ReticentRobot) - Windows agent for Snipe-IT.
- [Gate Pass Generator](https://github.com/cha7uraAE/snipe-it-gate-pass-system) by [@cha7uraAE](https://github.com/cha7uraAE) - A Streamlit application for generating gate passes based on hardware data from a Snipe-IT API.
-----
### Contributing
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview).
Please refrain from submitting issues or pull requests generated by fully-automated tools. Maintainers reserve the right, at their sole discretion, to close such submissions and to block any account responsible for them.
Ideally, contributions should follow from a human-to-human discussion in the form of an issue.
Please see the complete documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview).
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.

276
app/Console/Commands/LdapSync.php Executable file → Normal file
View File

@@ -53,18 +53,22 @@ class LdapSync extends Command
ini_set('max_execution_time', env('LDAP_TIME_LIM', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('LDAP_MEM_LIM', '500M'));
$ldap_result_username = Setting::getSettings()->ldap_username_field;
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
$ldap_result_active_flag = Setting::getSettings()->ldap_active_flag;
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
$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_location = Setting::getSettings()->ldap_location;
$ldap_result_dept = Setting::getSettings()->ldap_dept;
$ldap_result_manager = Setting::getSettings()->ldap_manager;
$ldap_map = [
"username" => Setting::getSettings()->ldap_username_field,
"last_name" => Setting::getSettings()->ldap_lname_field,
"first_name" => Setting::getSettings()->ldap_fname_field,
"active_flag" => Setting::getSettings()->ldap_active_flag,
"emp_num" => Setting::getSettings()->ldap_emp_num,
"email" => Setting::getSettings()->ldap_email,
"phone" => Setting::getSettings()->ldap_phone_field,
"jobtitle" => Setting::getSettings()->ldap_jobtitle,
"country" => Setting::getSettings()->ldap_country,
"location" => Setting::getSettings()->ldap_location,
"dept" => Setting::getSettings()->ldap_dept,
"manager" => Setting::getSettings()->ldap_manager,
];
$ldap_default_group = Setting::getSettings()->ldap_default_group;
$search_base = Setting::getSettings()->ldap_base_dn;
@@ -107,14 +111,21 @@ class LdapSync extends Command
}
/**
* If a filter has been specified, use that
* If a filter has been specified, use that, otherwise default to null
*/
if ($this->option('filter') != '') {
$results = Ldap::findLdapUsers($search_base, -1, $this->option('filter'));
$filter = $this->option('filter');
} else {
$results = Ldap::findLdapUsers($search_base);
$filter = null;
}
/**
* We only need to request the LDAP attributes that we process
*/
$attributes = array_values(array_filter($ldap_map));
$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
@@ -126,23 +137,24 @@ class LdapSync extends Command
}
/* Determine which location to assign users to by default. */
$location = null; // TODO - this would be better called "$default_location", which is more explicit about its purpose
$default_location = null;
if ($this->option('location') != '') {
if ($location = Location::where('name', '=', $this->option('location'))->first()) {
if ($default_location = Location::where('name', '=', $this->option('location'))->first()) {
Log::debug('Location name ' . $this->option('location') . ' passed');
Log::debug('Importing to ' . $location->name . ' (' . $location->id . ')');
Log::debug('Importing to '.$default_location->name.' ('.$default_location->id.')');
}
} elseif ($this->option('location_id')) {
//TODO - figure out how or why this is an array?
foreach($this->option('location_id') as $location_id) {
if ($location = Location::where('id', '=', $location_id)->first()) {
if ($default_location = Location::where('id', '=', $location_id)->first()) {
Log::debug('Location ID ' . $location_id . ' passed');
Log::debug('Importing to ' . $location->name . ' (' . $location->id . ')');
Log::debug('Importing to '.$default_location->name.' ('.$default_location->id.')');
}
}
}
if (! isset($location)) {
if (!isset($default_location)) {
Log::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
}
@@ -183,17 +195,17 @@ class LdapSync extends Command
}
$usernames = [];
for ($i = 0; $i < $location_users['count']; $i++) {
if (array_key_exists($ldap_result_username, $location_users[$i])) {
if (array_key_exists($ldap_map["username"], $location_users[$i])) {
$location_users[$i]['ldap_location_override'] = true;
$location_users[$i]['location_id'] = $ldap_loc['id'];
$usernames[] = $location_users[$i][$ldap_result_username][0];
$usernames[] = $location_users[$i][$ldap_map["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 (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
if ((is_array($generic_entry)) && (array_key_exists($ldap_map["username"], $generic_entry))) {
if (in_array($generic_entry[$ldap_map["username"]][0], $usernames)) {
unset($results[$key]);
}
}
@@ -218,77 +230,78 @@ class LdapSync extends Command
for ($i = 0; $i < $results['count']; $i++) {
$item = [];
$item['username'] = $results[$i][$ldap_result_username][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_result_emp_num][0] ?? '';
$item['lastname'] = $results[$i][$ldap_result_last_name][0] ?? '';
$item['firstname'] = $results[$i][$ldap_result_first_name][0] ?? '';
$item['email'] = $results[$i][$ldap_result_email][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_result_phone][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_result_jobtitle][0] ?? '';
$item['country'] = $results[$i][$ldap_result_country][0] ?? '';
$item['department'] = $results[$i][$ldap_result_dept][0] ?? '';
$item['manager'] = $results[$i][$ldap_result_manager][0] ?? '';
$item['location'] = $results[$i][$ldap_result_location][0] ?? '';
$item = [];
$item['username'] = $results[$i][$ldap_map["username"]][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_map["emp_num"]][0] ?? '';
$item['lastname'] = $results[$i][$ldap_map["last_name"]][0] ?? '';
$item['firstname'] = $results[$i][$ldap_map["first_name"]][0] ?? '';
$item['email'] = $results[$i][$ldap_map["email"]][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_map["phone"]][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_map["jobtitle"]][0] ?? '';
$item['country'] = $results[$i][$ldap_map["country"]][0] ?? '';
$item['department'] = $results[$i][$ldap_map["dept"]][0] ?? '';
$item['manager'] = $results[$i][$ldap_map["manager"]][0] ?? '';
$item['location'] = $results[$i][$ldap_map["location"]][0] ?? '';
$location = $default_location; //initially, set '$location' to the default_location (which may just be `null`)
// ONLY if you are using the "ldap_location" option *AND* you have an actual result
if ($ldap_result_location && $item['location']) {
$location = Location::firstOrCreate([
'name' => $item['location'],
]);
}
$department = Department::firstOrCreate([
'name' => $item['department'],
// ONLY if you are using the "ldap_location" option *AND* you have an actual result
if ($ldap_map["location"] && $item['location']) {
$location = Location::firstOrCreate([
'name' => $item['location'],
]);
}
$department = Department::firstOrCreate([
'name' => $item['department'],
]);
$user = User::where('username', $item['username'])->first();
if ($user) {
// Updating an existing user.
$item['createorupdate'] = 'updated';
} else {
// Creating a new user.
$user = new User;
$user->password = $user->noPassword();
$user->locale = app()->getLocale();
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
$item['createorupdate'] = 'created';
}
$user = User::where('username', $item['username'])->first();
if ($user) {
// Updating an existing user.
$item['createorupdate'] = 'updated';
} else {
// Creating a new user.
$user = new User;
$user->password = $user->noPassword();
$user->locale = app()->getLocale();
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
$item['createorupdate'] = 'created';
}
//If a sync option is not filled in on the LDAP settings don't populate the user field
if($ldap_result_username != null){
if($ldap_map["username"] != null){
$user->username = $item['username'];
}
if($ldap_result_last_name != null){
if($ldap_map["last_name"] != null){
$user->last_name = $item['lastname'];
}
if($ldap_result_first_name != null){
if($ldap_map["first_name"] != null){
$user->first_name = $item['firstname'];
}
if($ldap_result_emp_num != null){
if($ldap_map["emp_num"] != null){
$user->employee_num = e($item['employee_number']);
}
if($ldap_result_email != null){
if($ldap_map["email"] != null){
$user->email = $item['email'];
}
if($ldap_result_phone != null){
if($ldap_map["phone"] != null){
$user->phone = $item['telephone'];
}
if($ldap_result_jobtitle != null){
if($ldap_map["jobtitle"] != null){
$user->jobtitle = $item['jobtitle'];
}
if($ldap_result_country != null){
if($ldap_map["country"] != null){
$user->country = $item['country'];
}
if($ldap_result_dept != null){
if($ldap_map["dept"] != null){
$user->department_id = $department->id;
}
if($ldap_result_location != null){
$user->location_id = $location ? $location->id : null;
if($ldap_map["location"] != null){
$user->location_id = $location?->id;
}
if($ldap_result_manager != null){
if($ldap_map["manager"] != null){
if($item['manager'] != null) {
// Check Cache first
if (isset($manager_cache[$item['manager']])) {
@@ -305,7 +318,7 @@ class LdapSync extends Command
$ldap_manager = [
"count" => 1,
0 => [
$ldap_result_username => [$item['manager']]
$ldap_map["username"] => [$item['manager']]
]
];
}
@@ -314,7 +327,7 @@ class LdapSync extends Command
// Get the Manager's username
// PHP LDAP returns every LDAP attribute as an array, and 90% of the time it's an array of just one item. But, hey, it's an array.
$ldapManagerUsername = $ldap_manager[0][$ldap_result_username][0];
$ldapManagerUsername = $ldap_manager[0][$ldap_map["username"]][0];
// Get User from Manager username.
$ldap_manager = User::where('username', $ldapManagerUsername)->first();
@@ -330,38 +343,38 @@ class LdapSync extends Command
}
}
// Sync activated state for Active Directory.
if ( !empty($ldap_result_active_flag)) { // IF we have an 'active' flag set....
// ....then *most* things that are truthy will activate the user. Anything falsey will deactivate them.
// (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_result_active_flag][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool)$raw_value;
// Sync activated state for Active Directory.
if (!empty($ldap_map["active_flag"])) { // IF we have an 'active' flag set....
// ....then *most* things that are truthy will activate the user. Anything falsey will deactivate them.
// (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_map["active_flag"]][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool) $raw_value;
$user->activated = $filter_var ?? $boolean_cast; // if filter_var() was true or false, use that. If it's null, use the $boolean_cast
$user->activated = $filter_var ?? $boolean_cast; // if filter_var() was true or false, use that. If it's null, use the $boolean_cast
} elseif (array_key_exists('useraccountcontrol', $results[$i]) ) {
// ....otherwise, (ie if no 'active' LDAP flag is defined), IF the UAC setting exists,
// ....then use the UAC setting on the account to determine can-log-in vs. cannot-log-in
} elseif (array_key_exists('useraccountcontrol', $results[$i])) {
// ....otherwise, (ie if no 'active' LDAP flag is defined), IF the UAC setting exists,
// ....then use the UAC setting on the account to determine can-log-in vs. cannot-log-in
/* 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
to allow to log in.
/* 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
to allow to log in.
$useraccountcontrol = $results[$i]['useraccountcontrol'][0];
if(
// based on MS docs at: https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
($useraccountcontrol & 0x200) && // is a NORMAL_ACCOUNT
!($useraccountcontrol & 0x02) && // *and* _not_ ACCOUNTDISABLE
!($useraccountcontrol & 0x10) // *and* _not_ LOCKOUT
) {
$user->activated = 1;
} else {
$user->activated = 0;
} */
$enabled_accounts = [
$useraccountcontrol = $results[$i]['useraccountcontrol'][0];
if(
// based on MS docs at: https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
($useraccountcontrol & 0x200) && // is a NORMAL_ACCOUNT
!($useraccountcontrol & 0x02) && // *and* _not_ ACCOUNTDISABLE
!($useraccountcontrol & 0x10) // *and* _not_ LOCKOUT
) {
$user->activated = 1;
} else {
$user->activated = 0;
} */
$enabled_accounts = [
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
@@ -374,44 +387,47 @@ class LdapSync extends Command
'4260352', // 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
'1049088', // 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
'1114624', // 0x110200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, 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
} /* implied 'else' here - leave the $user->activated flag alone. Newly-created accounts will be active.
already-existing accounts will be however the administrator has set them */
} /* implied 'else' here - leave the $user->activated flag alone. Newly-created accounts will be active.
already-existing accounts will be however the administrator has set them */
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
} 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;
}
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
} 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; //THIS is the magic line, this should do it.
}
$location = null;
$user->ldap_import = 1;
}
// TODO - should we be NULLING locations if $location is really `null`, and that's what we came up with?
// will that conflict with any overriding setting that the user set? Like, if they moved someone from
// the 'null' location to somewhere, we wouldn't want to try to override that, right?
$location = null;
$user->ldap_import = 1;
$errors = '';
$errors = '';
if ($user->save()) {
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
if ( $item['createorupdate'] === 'created' && $ldap_default_group) {
$user->groups()->attach($ldap_default_group);
}
} else {
foreach ($user->getErrors()->getMessages() as $key => $err) {
$errors .= $err[0];
}
$item['note'] = $errors;
$item['status'] = 'error';
if ($user->save()) {
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
if ($item['createorupdate'] === 'created' && $ldap_default_group) {
$user->groups()->attach($ldap_default_group);
}
array_push($summary, $item);
} else {
foreach ($user->getErrors()->getMessages() as $key => $err) {
$errors .= $err[0];
}
$item['note'] = $errors;
$item['status'] = 'error';
}
array_push($summary, $item);
}
if ($this->option('summary')) {

View File

@@ -6,6 +6,7 @@ use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Console\Helper\ProgressIndicator;
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
@@ -29,6 +30,11 @@ class ObjectImportCommand extends Command
*/
protected $description = 'Import Items from CSV';
/**
* The progress indicator instance.
*/
protected ProgressIndicator $progressIndicator;
/**
* Create a new command instance.
*
@@ -39,8 +45,6 @@ class ObjectImportCommand extends Command
parent::__construct();
}
private $bar;
/**
* Execute the console command.
*
@@ -48,6 +52,8 @@ class ObjectImportCommand extends Command
*/
public function handle()
{
$this->progressIndicator = new ProgressIndicator($this->output);
$filename = $this->argument('filename');
$class = title_case($this->option('item-type'));
$classString = "App\\Importer\\{$class}Importer";
@@ -61,46 +67,25 @@ class ObjectImportCommand extends Command
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
// $logFile = $this->option('logfile');
// Log::useFiles($logFile);
$this->comment('======= Importing Items from '.$filename.' =========');
$this->progressIndicator->start('======= Importing Items from '.$filename.' =========');
$importer->import();
$this->bar = null;
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));
}
} else {
$this->comment('All Items imported successfully!');
}
$this->comment('');
$this->progressIndicator->finish('Import finished.');
}
public function errorCallback($item, $field, $errorString)
public function errorCallback($item, $field, $error)
{
$this->errors[$item->name][$field] = $errorString;
$this->output->write("\x0D\x1B[2K");
$this->warn('Error: Item: '.$item->name.' failed validation: '.json_encode($error));
}
public function progress($count)
public function progress($importedItemsCount)
{
if (! $this->bar) {
$this->bar = $this->output->createProgressBar($count);
}
static $index = 0;
$index++;
if ($index < $count) {
$this->bar->advance();
} else {
$this->bar->finish();
}
$this->progressIndicator->advance();
}
// 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.

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Console\Commands;
use App\Models\Asset;
use App\Models\AssetModel;
use Illuminate\Console\Command;
class RemoveExplicitEols extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:remove-explicit-eols {--model_name= : The name of the asset model to update (use "all" to update all models)}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes explicit EOLs on assets with selected model so they may inherit the asset model EOL';
/**
* Execute the console command.
*/
public function handle()
{
$startTime = microtime(true);
if ($this->option('model_name') == 'all') {
$assets = Asset::all();
$this->updateAssets($assets);
} else {
$assetModel = AssetModel::where('name', '=', $this->option('model_name'))->first();
if ($assetModel) {
$assets = Asset::where('model_id', '=', $assetModel->id)->get();
$this->updateAssets($assets);
} else {
$this->error('Asset model not found');
}
}
$endTime = microtime(true);
$executionTime = ($endTime - $startTime);
$this->info('Command executed in ' . round($executionTime, 2) . ' seconds.');
}
private function updateAssets($assets)
{
foreach ($assets as $asset) {
$asset->eol_explicit = 0;
$asset->asset_eol_date = null;
$asset->save();
}
$this->info($assets->count() . ' Assets updated successfully');
}
}

View File

@@ -47,7 +47,8 @@ class SendAcceptanceReminder extends Command
{
$pending = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')
->whereHas('checkoutable', function($query) {
$query->where('archived', 0);
$query->where('accepted_at', null)
->where('declined_at', null);
})
->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model', 'checkoutable.adminuser'])
->get();

View File

@@ -553,7 +553,7 @@ class Helper
*/
public static function statusLabelList()
{
$statuslabel_list = ['' => trans('general.select_statuslabel')] + Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('deployable', 'desc')
$statuslabel_list = ['' => trans('general.select_statuslabel')] + Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('status_type', 'desc')
->pluck('name', 'id')->toArray();
return $statuslabel_list;
@@ -572,9 +572,9 @@ class Helper
*/
public static function deployableStatusLabelList()
{
$statuslabel_list = Statuslabel::where('deployable', '=', '1')->orderBy('default_label', 'desc')
$statuslabel_list = Statuslabel::where('status_type', 'deployable')->orderBy('default_label', 'desc')
->orderBy('name', 'asc')
->orderBy('deployable', 'desc')
->orderBy('status_type', 'desc')
->pluck('name', 'id')->toArray();
return $statuslabel_list;
@@ -1123,6 +1123,7 @@ class Helper
'png' => 'far fa-image',
'webp' => 'far fa-image',
'avif' => 'far fa-image',
'svg' => 'fas fa-vector-square',
// word
'doc' => 'far fa-file-word',
'docx' => 'far fa-file-word',
@@ -1135,7 +1136,7 @@ class Helper
//Text
'txt' => 'far fa-file-alt',
'rtf' => 'far fa-file-alt',
'xml' => 'far fa-file-alt',
'xml' => 'fas fa-code',
// Misc
'pdf' => 'far fa-file-pdf',
'lic' => 'far fa-save',
@@ -1148,41 +1149,7 @@ class Helper
return 'far fa-file';
}
public static function show_file_inline($filename)
{
$extension = substr(strrchr($filename, '.'), 1);
if ($extension) {
switch ($extension) {
case 'jpg':
case 'jpeg':
case 'gif':
case 'png':
case 'webp':
case 'avif':
return true;
break;
default:
return false;
}
}
return false;
}
/**
* Generate a random encrypted password.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @return string
*/
public static function generateEncyrptedPassword(): string
{
return bcrypt(self::generateUnencryptedPassword());
}
/**
* Get a random unencrypted password.

190
app/Helpers/IconHelper.php Normal file
View File

@@ -0,0 +1,190 @@
<?php
namespace App\Helpers;
class IconHelper
{
public static function icon($type) {
switch ($type) {
case 'checkout':
return 'fa-solid fa-rotate-left';
case 'checkin':
return 'fa-solid fa-rotate-right';
case 'edit':
return 'fas fa-pencil-alt';
case 'clone':
return 'far fa-clone';
case 'delete':
return 'fas fa-trash';
case 'create':
return 'fa-solid fa-plus';
case 'audit':
return 'fa-solid fa-clipboard-check';
case '2fa reset':
return 'fa-solid fa-mobile-screen';
case 'new-user':
return 'fa-solid fa-user-plus';
case 'merged-user':
return 'fa-solid fa-people-arrows';
case 'delete-user':
return 'fa-solid fa-user-minus';
case 'update-user':
return 'fa-solid fa-user-pen';
case 'user':
return 'fa-solid fa-user';
case 'users':
return 'fas fa-users';
case 'restore':
return 'fa-solid fa-trash-arrow-up';
case 'external-link':
return 'fa fa-external-link';
case 'email':
return 'fa-regular fa-envelope';
case 'phone':
return 'fa-solid fa-phone';
case 'long-arrow-right':
return 'fas fa-long-arrow-alt-right';
case 'download':
return 'fas fa-download';
case 'checkmark':
return 'fas fa-check icon-white';
case 'x':
return 'fas fa-times';
case 'logout':
return 'fa fa-sign-out';
case 'admin-settings':
return 'fas fa-cogs';
case 'settings':
return 'fas fa-cog';
case 'angle-left':
return 'fas fa-angle-left';
case 'warning':
return 'fas fa-exclamation-triangle';
case 'kits':
return 'fas fa-object-group';
case 'assets':
case 'asset':
return 'fas fa-barcode';
case 'accessories':
case 'accessory':
return 'far fa-keyboard';
case 'components':
case 'component':
return 'far fa-hdd';
case 'consumables':
case 'consumable':
return 'fas fa-tint';
case 'licenses':
case 'license':
return 'far fa-save';
case 'requestable':
return 'fas fa-laptop';
case 'reports':
return 'fas fa-chart-bar';
case 'heart':
return 'fas fa-heart';
case 'circle':
return 'fa-regular fa-circle';
case 'circle-solid':
return 'fa-solid fa-circle';
case 'due':
return 'fas fa-history';
case 'import':
return 'fas fa-cloud-upload-alt';
case 'search':
return 'fas fa-search';
case 'alerts':
return 'far fa-flag';
case 'password':
return 'fa-solid fa-key';
case 'api-key':
return 'fa-solid fa-user-secret';
case 'nav-toggle':
return 'fas fa-bars';
case 'dashboard':
return 'fas fa-tachometer-alt';
case 'info-circle':
return 'fas fa-info-circle';
case 'caret-right':
return 'fa fa-caret-right';
case 'caret-up':
return 'fa fa-caret-up';
case 'caret-down':
return 'fa fa-caret-down';
case 'arrow-circle-right':
return 'fa fa-arrow-circle-right';
case 'minus':
return 'fas fa-minus';
case 'spinner':
return 'fas fa-spinner fa-spin';
case 'copy-clipboard':
return 'fa-regular fa-clipboard';
case 'paperclip':
return 'fas fa-paperclip';
case 'files':
return 'fa-regular fa-file';
case 'more-info':
return 'far fa-life-ring';
case 'calendar':
return 'fas fa-calendar';
case 'plus':
return 'fas fa-plus';
case 'history':
return 'fas fa-history';
case 'more-files':
return 'fa-solid fa-laptop-file';
case 'maintenances':
return 'fas fa-wrench';
case 'seats':
return 'far fa-list-alt';
case 'globe-us':
return 'fas fa-globe-americas';
case 'locked':
return 'fas fa-lock';
case 'unlocked':
return 'fas fa-lock';
case 'locations':
return 'fas fa-map-marker-alt';
case 'location':
return 'fas fa-map-marker-alt';
case 'superadmin':
return 'fas fa-crown';
case 'print':
return 'fa-solid fa-print';
case 'checkin-and-delete':
return 'fa-solid fa-user-xmark';
case 'branding':
return 'fas fa-copyright';
case 'general-settings':
return 'fa-solid fa-list-check';
case 'groups':
return 'fa-solid fa-user-group';
case 'bell':
return 'fa-solid fa-bell';
case 'hashtag':
return 'fa-solid fa-hashtag';
case 'asset-tags':
return 'fas fa-list-ol';
case 'labels':
return 'fas fa-tags';
case 'ldap':
return 'fas fa-sitemap';
case 'google':
return 'fa-brands fa-google';
case 'saml':
return 'fas fa-sign-in-alt';
case 'backups':
return 'fas fa-file-archive';
case 'logins':
return 'fas fa-crosshairs';
case 'oauth':
return 'fas fa-user-secret';
case 'employee_num' :
return 'fa-regular fa-id-card';
case 'department' :
return 'fa-solid fa-building-user';
}
}
}

View File

@@ -7,6 +7,7 @@ use Illuminate\Http\Response;
use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
class StorageHelper
{
public static function downloader($filename, $disk = 'default') : BinaryFileResponse | RedirectResponse | StreamedResponse
@@ -25,4 +26,64 @@ class StorageHelper
return Storage::disk($disk)->download($filename);
}
}
/**
* This determines the file types that should be allowed inline and checks their fileinfo extension
* to determine that they are safe to display inline.
*
* @author <A. Gianotto> [<snipe@snipe.net]>
* @since v7.0.14
* @param $file_with_path
* @return bool
*/
public static function allowSafeInline($file_with_path) {
$allowed_inline = [
'pdf',
'svg',
'jpg',
'gif',
'svg',
'avif',
'webp',
'png',
];
// The file exists and is allowed to be displayed inline
if (Storage::exists($file_with_path) && (in_array(pathinfo($file_with_path, PATHINFO_EXTENSION), $allowed_inline))) {
return true;
}
return false;
}
/**
* Decide whether to show the file inline or download it.
*/
public static function showOrDownloadFile($file, $filename) {
$headers = [];
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
// This is NOT allowed as inline - force it to be displayed as text in the browser
if (self::allowSafeInline($file) != true) {
$headers = array_merge($headers, ['Content-Type' => 'text/plain']);
}
}
// Everything else seems okay, but the file doesn't exist on the server.
if (Storage::missing($file)) {
throw new FileNotFoundException();
}
return Storage::download($file, $filename, $headers);
}
}

View File

@@ -73,7 +73,7 @@ class AccessoriesController extends Controller
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = request('purchase_cost');
$accessory->qty = request('qty');
$accessory->user_id = auth()->id();
$accessory->created_by = auth()->id();
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');

View File

@@ -106,50 +106,29 @@ class AccessoriesFilesController extends Controller
* @param int $accessoryId
* @param int $fileId
*/
public function show($accessoryId = null, $fileId = null, $download = true) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse
public function show($accessoryId = null, $fileId = null) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse
{
Log::debug('Private filesystem is: '.config('filesystems.default'));
$accessory = Accessory::find($accessoryId);
// the accessory is valid
if (isset($accessory->id)) {
if ($accessory = Accessory::find($accessoryId)) {
$this->authorize('view', $accessory);
$this->authorize('accessories.files', $accessory);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) {
return redirect()->route('accessories.index')->with('error', trans('admin/users/message.log_record_not_found'));
}
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) {
$file = 'private_uploads/accessories/'.$log->filename;
$file = 'private_uploads/accessories/'.$log->filename;
if (Storage::missing($file)) {
Log::debug('FILE DOES NOT EXISTS for '.$file);
Log::debug('URL should be '.Storage::url($file));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.file_not_found'));
}
}
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
return redirect()->route('accessories.index')->with('error', trans('general.file_not_found'));
}
}

View File

@@ -78,7 +78,7 @@ class AccessoryCheckoutController extends Controller
AccessoryCheckout::create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'created_by' => auth()->id(),
'assigned_to' => $target->id,
'assigned_type' => $target::class,
'note' => $request->input('note'),

View File

@@ -237,7 +237,11 @@ class AcceptanceController extends Controller
}
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
try {
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
} catch (\Exception $e) {
Log::warning($e);
}
event(new CheckoutAccepted($acceptance));
$return_msg = trans('admin/users/message.accepted');

View File

@@ -56,8 +56,9 @@ class AccessoriesController extends Controller
];
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier')
->withCount('checkouts as checkouts_count');
$accessories = Accessory::select('accessories.*')
->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier', 'adminuser')
->withCount('checkouts as checkouts_count');
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
@@ -110,7 +111,10 @@ class AccessoriesController extends Controller
break;
case 'supplier':
$accessories = $accessories->OrderSupplier($order);
break;
break;
case 'created_by':
$accessories = $accessories->OrderByCreatedByName($order);
break;
default:
$accessories = $accessories->orderBy($column_sort, $order);
break;
@@ -133,7 +137,6 @@ class AccessoriesController extends Controller
*/
public function store(StoreAccessoryRequest $request)
{
$this->authorize('create', Accessory::class);
$accessory = new Accessory;
$accessory->fill($request->all());
$accessory = $request->handleImages($accessory);
@@ -193,9 +196,6 @@ class AccessoriesController extends Controller
$this->authorize('view', Accessory::class);
$accessory = Accessory::with('lastCheckout')->findOrFail($id);
if (! Company::isCurrentUserHasAccess($accessory)) {
return ['total' => 0, 'rows' => []];
}
$offset = request('offset', 0);
$limit = request('limit', 50);
@@ -287,7 +287,7 @@ class AccessoriesController extends Controller
AccessoryCheckout::create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'created_by' => auth()->id(),
'assigned_to' => $target->id,
'assigned_type' => $target::class,
'note' => $request->input('note'),
@@ -321,7 +321,7 @@ class AccessoriesController extends Controller
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
$logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
$accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
// Was the accessory updated?
if ($accessory_checkout->delete()) {
@@ -329,14 +329,6 @@ class AccessoriesController extends Controller
$user = User::find($accessory_checkout->assigned_to);
}
$data['log_id'] = $logaction->id;
$data['first_name'] = $user->first_name;
$data['last_name'] = $user->last_name;
$data['item_name'] = $accessory->name;
$data['checkin_date'] = $logaction->created_at;
$data['item_tag'] = '';
$data['note'] = $logaction->note;
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
}

View File

@@ -34,7 +34,7 @@ class AssetMaintenancesController extends Controller
$this->authorize('view', Asset::class);
$maintenances = AssetMaintenance::select('asset_maintenances.*')
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'admin');
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'adminuser');
if ($request->filled('search')) {
$maintenances = $maintenances->TextSearch($request->input('search'));
@@ -48,6 +48,10 @@ class AssetMaintenancesController extends Controller
$maintenances->where('asset_maintenances.supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('created_by')) {
$maintenances->where('asset_maintenances.created_by', '=', $request->input('created_by'));
}
if ($request->filled('asset_maintenance_type')) {
$maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type'));
}
@@ -69,7 +73,7 @@ class AssetMaintenancesController extends Controller
'asset_tag',
'asset_name',
'serial',
'user_id',
'created_by',
'supplier',
'is_warranty',
'status_label',
@@ -79,8 +83,8 @@ class AssetMaintenancesController extends Controller
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
switch ($sort) {
case 'user_id':
$maintenances = $maintenances->OrderAdmin($order);
case 'created_by':
$maintenances = $maintenances->OrderByCreatedBy($order);
break;
case 'supplier':
$maintenances = $maintenances->OrderBySupplier($order);
@@ -124,7 +128,7 @@ class AssetMaintenancesController extends Controller
// create a new model instance
$maintenance = new AssetMaintenance();
$maintenance->fill($request->all());
$maintenance->user_id = Auth::id();
$maintenance->created_by = auth()->id();
// Was the asset maintenance created?
if ($maintenance->save()) {
@@ -186,11 +190,8 @@ class AssetMaintenancesController extends Controller
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot delete a maintenance for that asset'));
}
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
$assetMaintenance->delete();

View File

@@ -0,0 +1,200 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\StorageHelper;
use Illuminate\Support\Facades\Storage;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\AssetModel;
use App\Models\Actionlog;
use App\Http\Requests\UploadFileRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
/**
* This class controls file related actions related
* to assets for the Snipe-IT Asset Management application.
*
* Based on the Assets/AssetFilesController by A. Gianotto <snipe@snipe.net>
*
* @version v1.0
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
*/
class AssetModelFilesController extends Controller
{
/**
* Accepts a POST to upload a file to the server.
*
* @param \App\Http\Requests\UploadFileRequest $request
* @param int $assetModelId
* @since [v7.0.12]
* @author [r-xyz]
*/
public function store(UploadFileRequest $request, $assetModelId = null) : JsonResponse
{
// Start by checking if the asset being acted upon exists
if (! $assetModel = AssetModel::find($assetModelId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
}
// Make sure we are allowed to update this asset
$this->authorize('update', $assetModel);
if ($request->hasFile('file')) {
// If the file storage directory doesn't exist; create it
if (! Storage::exists('private_uploads/assetmodels')) {
Storage::makeDirectory('private_uploads/assetmodels', 775);
}
// Loop over the attached files and add them to the asset
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$assetModel->id, $file);
$assetModel->logUpload($file_name, e($request->get('notes')));
}
// All done - report success
return response()->json(Helper::formatStandardApiResponse('success', $assetModel, trans('admin/models/message.upload.success')));
}
// We only reach here if no files were included in the POST, so tell the user this
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.upload.nofiles')), 500);
}
/**
* List the files for an asset.
*
* @param int $assetModelId
* @since [v7.0.12]
* @author [r-xyz]
*/
public function list($assetModelId = null) : JsonResponse
{
// Start by checking if the asset being acted upon exists
if (! $assetModel = AssetModel::find($assetModelId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
}
// the asset is valid
if (isset($assetModel->id)) {
$this->authorize('view', $assetModel);
// Check that there are some uploads on this asset that can be listed
if ($assetModel->uploads->count() > 0) {
$files = array();
foreach ($assetModel->uploads as $upload) {
array_push($files, $upload);
}
// Give the list of files back to the user
return response()->json(Helper::formatStandardApiResponse('success', $files, trans('admin/models/message.upload.success')));
}
// There are no files.
return response()->json(Helper::formatStandardApiResponse('success', array(), trans('admin/models/message.upload.success')));
}
// Send back an error message
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.error')), 500);
}
/**
* Check for permissions and display the file.
*
* @param int $assetModelId
* @param int $fileId
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
* @since [v7.0.12]
* @author [r-xyz]
*/
public function show($assetModelId = null, $fileId = null) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
{
// Start by checking if the asset being acted upon exists
if (! $assetModel = AssetModel::find($assetModelId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
}
// the asset is valid
if (isset($assetModel->id)) {
$this->authorize('view', $assetModel);
// Check that the file being requested exists for the asset
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $assetModel->id)->find($fileId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.no_match', ['id' => $fileId])), 404);
}
// Form the full filename with path
$file = 'private_uploads/assetmodels/'.$log->filename;
Log::debug('Checking for '.$file);
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
// Check the file actually exists on the filesystem
if (! Storage::exists($file)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.does_not_exist', ['id' => $fileId])), 404);
}
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
return StorageHelper::downloader($file);
}
// Send back an error message
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.error', ['id' => $fileId])), 500);
}
/**
* Delete the associated file
*
* @param int $assetModelId
* @param int $fileId
* @since [v7.0.12]
* @author [r-xyz]
*/
public function destroy($assetModelId = null, $fileId = null) : JsonResponse
{
// Start by checking if the asset being acted upon exists
if (! $assetModel = AssetModel::find($assetModelId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
}
$rel_path = 'private_uploads/assetmodels';
// the asset is valid
if (isset($assetModel->id)) {
$this->authorize('update', $assetModel);
// Check for the file
$log = Actionlog::find($fileId);
if ($log) {
// Check the file actually exists, and delete it
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
// Delete the record of the file
$log->delete();
// All deleting done - notify the user of success
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/models/message.deletefile.success')), 200);
}
// The file doesn't seem to really exist, so report an error
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.deletefile.error')), 500);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.deletefile.error')), 500);
}
}

View File

@@ -48,6 +48,8 @@ class AssetModelsController extends Controller
'assets_count',
'category',
'fieldset',
'deleted_at',
'updated_at',
];
$assetmodels = AssetModel::select([
@@ -67,7 +69,7 @@ class AssetModelsController extends Controller
'models.deleted_at',
'models.updated_at',
])
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues')
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues','adminuser')
->withCount('assets as assets_count');
if ($request->input('status')=='deleted') {
@@ -78,6 +80,10 @@ class AssetModelsController extends Controller
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
}
if ($request->filled('depreciation_id')) {
$assetmodels = $assetmodels->where('models.depreciation_id', '=', $request->input('depreciation_id'));
}
if ($request->filled('search')) {
$assetmodels->TextSearch($request->input('search'));
}

View File

@@ -56,7 +56,12 @@ class AssetsController extends Controller
public function index(Request $request, $action = null, $upcoming_status = null) : JsonResponse | array
{
$filter_non_deprecable_assets = false;
// This handles the legacy audit endpoints :(
if ($action == 'audit') {
$action = 'audits';
}
$filter_non_depreciable_assets = false;
/**
* This looks MAD janky (and it is), but the AssetsController@index does a LOT of heavy lifting throughout the
@@ -70,7 +75,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;
$filter_non_depreciable_assets = true;
$transformer = 'App\Http\Transformers\DepreciationReportTransformer';
$this->authorize('reports.view');
} else {
@@ -121,13 +126,13 @@ class AssetsController extends Controller
}
$assets = Asset::select('assets.*')
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo', 'adminuser','model.depreciation',
'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());
if ($filter_non_depreciable_assets) {
$non_depreciable_models = AssetModel::select('id')->whereNotNull('depreciation_id')->get();
$assets->InModelList($non_depreciable_models->toArray());
}
@@ -154,8 +159,8 @@ class AssetsController extends Controller
* Handle due and overdue audits and checkin dates
*/
switch ($action) {
case 'audits':
// Audit (singular) is left over from earlier legacy APIs
case 'audits' :
switch ($upcoming_status) {
case 'due':
$assets->DueForAudit($settings);
@@ -201,18 +206,14 @@ class AssetsController extends Controller
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)
->where('status_alias.archived', '=', 0);
->where('status_alias.status_type', '=', 'pending');
});
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)
->where('status_alias.archived', '=', 0);
->where('status_alias.status_type', '=', 'deployable');
});
break;
case 'Undeployable':
@@ -221,20 +222,15 @@ class AssetsController extends Controller
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)
->where('status_alias.archived', '=', 1);
->where('status_alias.status_type', '=', 'archived');
});
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)
->where('status_alias.archived', '=', 0);
->where('status_alias.status_type', '=', 'deployable');
});
break;
case 'Deployed':
// more sad, horrible workarounds for laravel bugs when doing full text searches
@@ -251,7 +247,7 @@ class AssetsController extends Controller
// 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')
->where('status_alias.archived', '=', 0);
->where('status_alias.status_type', '!=', 'archived');
});
// If there is a status ID, don't take show_archived_in_list into consideration
@@ -260,6 +256,7 @@ class AssetsController extends Controller
$join->on('status_alias.id', '=', 'assets.status_id');
});
}
break;
}
@@ -371,8 +368,33 @@ class AssetsController extends Controller
case 'assigned_to':
$assets->OrderAssigned($order);
break;
case 'created_by':
$assets->OrderByCreatedByName($order);
break;
default:
$assets->orderBy($column_sort, $order);
$numeric_sort = false;
// Search through the custom fields array to see if we're sorting on a custom field
if (array_search($column_sort, $all_custom_fields->pluck('db_column')->toArray()) !== false) {
// Check to see if this is a numeric field type
foreach ($all_custom_fields as $field) {
if (($field->db_column == $sort_override) && ($field->format == 'NUMERIC')) {
$numeric_sort = true;
break;
}
}
// This may not work for all databases, but it works for MySQL
if ($numeric_sort) {
$assets->orderByRaw(DB::getTablePrefix() . 'assets.' . $sort_override . ' * 1 ' . $order);
} else {
$assets->orderBy($sort_override, $order);
}
} else {
$assets->orderBy($column_sort, $order);
}
break;
}
@@ -544,8 +566,8 @@ class AssetsController extends Controller
}
if ($asset->assetstatus->getStatuslabelType() == 'pending') {
$asset->use_text .= '('.$asset->assetstatus->getStatuslabelType().')';
if ($asset->assetstatus->status_label == 'pending') {
$asset->use_text .= '('.$asset->assetstatus->status_label.')';
}
$asset->use_image = ($asset->getImageUrl()) ? $asset->getImageUrl() : null;
@@ -568,7 +590,7 @@ class AssetsController extends Controller
$asset->model()->associate(AssetModel::find((int) $request->get('model_id')));
$asset->fill($request->validated());
$asset->user_id = Auth::id();
$asset->created_by = auth()->id();
/**
* this is here just legacy reasons. Api\AssetController
@@ -602,7 +624,7 @@ class AssetsController extends Controller
if ($field->field_encrypted == '1') {
Log::debug('This model field is encrypted in this fieldset.');
if (Gate::allows('admin')) {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
// If input value is null, use custom field's default value
if (($field_val == null) && ($request->has('model_id') != '')) {
@@ -695,7 +717,7 @@ class AssetsController extends Controller
}
}
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
$field_val = Crypt::encrypt($field_val);
} else {
$problems_updating_encrypted_custom_fields = true;
@@ -750,9 +772,16 @@ class AssetsController extends Controller
if ($asset = Asset::find($id)) {
$this->authorize('delete', $asset);
DB::table('assets')
->where('id', $asset->id)
->update(['assigned_to' => null]);
if ($asset->assignedTo) {
$target = $asset->assignedTo;
$checkin_at = date('Y-m-d H:i:s');
$originalValues = $asset->getRawOriginal();
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
DB::table('assets')
->where('id', $asset->id)
->update(['assigned_to' => null]);
}
$asset->delete();

View File

@@ -43,6 +43,7 @@ class CategoriesController extends Controller
$categories = Category::select([
'id',
'created_by',
'created_at',
'updated_at',
'name', 'category_type',
@@ -50,8 +51,10 @@ class CategoriesController extends Controller
'eula_text',
'require_acceptance',
'checkin_email',
'image'
])->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
'image',
])
->with('adminuser')
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
/*
@@ -91,13 +94,33 @@ class CategoriesController extends Controller
$categories->where('checkin_email', '=', $request->input('checkin_email'));
}
if ($request->filled('created_by')) {
$categories->where('created_by', '=', $request->input('created_by'));
}
if ($request->filled('created_at')) {
$categories->where('created_at', '=', $request->input('created_at'));
}
if ($request->filled('updated_at')) {
$categories->where('updated_at', '=', $request->input('updated_at'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $categories->count()) ? $categories->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets_count';
$categories->orderBy($sort, $order);
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets_count';
switch ($sort_override) {
case 'created_by':
$categories = $categories->OrderByCreatedBy($order);
break;
default:
$categories = $categories->orderBy($column_sort, $order);
break;
}
$total = $categories->count();
$categories = $categories->skip($offset)->take($limit)->get();

View File

@@ -42,7 +42,7 @@ class CompaniesController extends Controller
$companies = Company::withCount(['assets as assets_count' => function ($query) {
$query->AssetsForShow();
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
}])->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'));
@@ -56,17 +56,29 @@ class CompaniesController extends Controller
$companies->where('email', '=', $request->input('email'));
}
if ($request->filled('created_by')) {
$companies->where('created_by', '=', $request->input('created_by'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $companies->count()) ? $companies->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$companies->orderBy($sort, $order);
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort_override) {
case 'created_by':
$companies = $companies->OrderByCreatedBy($order);
break;
default:
$companies = $companies->orderBy($column_sort, $order);
break;
}
$total = $companies->count();
$companies = $companies->skip($offset)->take($limit)->get();
return (new CompaniesTransformer)->transformCompanies($companies, $total);

View File

@@ -38,6 +38,7 @@ class ComponentsController extends Controller
'name',
'min_amt',
'order_number',
'model_number',
'serial',
'purchase_date',
'purchase_cost',
@@ -47,7 +48,7 @@ class ComponentsController extends Controller
];
$components = Component::select('components.*')
->with('company', 'location', 'category', 'assets', 'supplier');
->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer');
if ($request->filled('search')) {
$components = $components->TextSearch($request->input('search'));
@@ -69,6 +70,14 @@ class ComponentsController extends Controller
$components->where('supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('manufacturer_id')) {
$components->where('manufacturer_id', '=', $request->input('manufacturer_id'));
}
if ($request->filled('model_number')) {
$components->where('model_number', '=', $request->input('model_number'));
}
if ($request->filled('location_id')) {
$components->where('location_id', '=', $request->input('location_id'));
}
@@ -98,6 +107,12 @@ class ComponentsController extends Controller
case 'supplier':
$components = $components->OrderSupplier($order);
break;
case 'manufacturer':
$components = $components->OrderManufacturer($order);
break;
case 'created_by':
$components = $components->OrderByCreatedBy($order);
break;
default:
$components = $components->orderBy($column_sort, $order);
break;
@@ -270,7 +285,7 @@ class ComponentsController extends Controller
'component_id' => $component->id,
'created_at' => Carbon::now(),
'assigned_qty' => $request->get('assigned_qty', 1),
'user_id' => auth()->id(),
'created_by' => auth()->id(),
'asset_id' => $request->get('assigned_to'),
'note' => $request->get('note'),
]);

View File

@@ -86,9 +86,15 @@ class ConsumablesController extends Controller
case 'company':
$consumables = $consumables->OrderCompany($order);
break;
case 'remaining':
$consumables = $consumables->OrderRemaining($order);
break;
case 'supplier':
$consumables = $consumables->OrderSupplier($order);
break;
case 'created_by':
$consumables = $consumables->OrderByCreatedBy($order);
break;
default:
// This array is what determines which fields should be allowed to be sorted on ON the table itself.
// These must match a column on the consumables table directly.
@@ -207,7 +213,7 @@ class ConsumablesController extends Controller
$consumable = Consumable::with(['consumableAssignments'=> function ($query) {
$query->orderBy($query->getModel()->getTable().'.created_at', 'DESC');
},
'consumableAssignments.admin'=> function ($query) {
'consumableAssignments.adminuser'=> function ($query) {
},
'consumableAssignments.user'=> function ($query) {
},
@@ -225,7 +231,8 @@ class ConsumablesController extends Controller
'name' => ($consumable_assignment->user) ? $consumable_assignment->user->present()->nameUrl() : 'Deleted User',
'created_at' => Helper::getFormattedDateObject($consumable_assignment->created_at, 'datetime'),
'note' => ($consumable_assignment->note) ? e($consumable_assignment->note) : null,
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : null,
'admin' => ($consumable_assignment->adminuser) ? $consumable_assignment->adminuser->present()->nameUrl() : null, // legacy, so we don't change the shape of the response
'created_by' => ($consumable_assignment->adminuser) ? $consumable_assignment->adminuser->present()->nameUrl() : null,
];
}
@@ -251,6 +258,8 @@ class ConsumablesController extends Controller
$this->authorize('checkout', $consumable);
$consumable->checkout_qty = $request->input('checkout_qty', 1);
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.checkout.unavailable')));
@@ -261,6 +270,12 @@ class ConsumablesController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.invalid_item_category_single', ['type' => trans('general.consumable')])));
}
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0 || $consumable->checkout_qty > $consumable->numRemaining()) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.checkout.unavailable', ['requested' => $consumable->checkout_qty, 'remaining' => $consumable->numRemaining() ])));
}
// Check if the user exists - @TODO: this should probably be handled via validation, not here??
if (!$user = User::find($request->input('assigned_to'))) {
@@ -271,14 +286,17 @@ class ConsumablesController extends Controller
// Update the consumable data
$consumable->assigned_to = $request->input('assigned_to');
$consumable->users()->attach($consumable->id,
for ($i = 0; $i < $consumable->checkout_qty; $i++) {
$consumable->users()->attach($consumable->id,
[
'consumable_id' => $consumable->id,
'user_id' => $user->id,
'created_by' => $user->id,
'assigned_to' => $request->input('assigned_to'),
'note' => $request->input('note'),
]
);
}
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));

View File

@@ -97,7 +97,7 @@ class DepartmentsController extends Controller
$department->fill($request->all());
$department = $request->handleImages($department);
$department->user_id = auth()->id();
$department->created_by = auth()->id();
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
if ($department->save()) {

View File

@@ -20,9 +20,23 @@ class DepreciationsController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', Depreciation::class);
$allowed_columns = ['id','name','months','depreciation_min', 'depreciation_type','created_at'];
$allowed_columns = [
'id',
'name',
'months',
'depreciation_min',
'depreciation_type',
'created_at',
'assets_count',
'models_count',
'licenses_count',
];
$depreciations = Depreciation::select('id','name','months','depreciation_min','depreciation_type','user_id','created_at','updated_at');
$depreciations = Depreciation::select('id','name','months','depreciation_min','depreciation_type','created_at','updated_at', 'created_by')
->with('adminuser')
->withCount('assets as assets_count')
->withCount('models as models_count')
->withCount('licenses as licenses_count');
if ($request->filled('search')) {
$depreciations = $depreciations->TextSearch($request->input('search'));
@@ -31,10 +45,18 @@ class DepreciationsController extends Controller
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $depreciations->count()) ? $depreciations->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$depreciations->orderBy($sort, $order);
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort_override) {
case 'created_by':
$depreciations = $depreciations->OrderByCreatedBy($order);
break;
default:
$depreciations = $depreciations->orderBy($column_sort, $order);
break;
}
$total = $depreciations->count();
$depreciations = $depreciations->skip($offset)->take($limit)->get();

View File

@@ -23,9 +23,8 @@ class GroupsController extends Controller
$this->authorize('superadmin');
$this->authorize('view', Group::class);
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('admin')->withCount('users as users_count');
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search'));
@@ -35,13 +34,29 @@ class GroupsController extends Controller
$groups->where('name', '=', $request->input('name'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $groups->count()) ? $groups->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$groups->orderBy($sort, $order);
switch ($request->input('sort')) {
case 'created_by':
$groups = $groups->OrderByCreatedBy($order);
break;
default:
// This array is what determines which fields should be allowed to be sorted on ON the table itself.
// These must match a column on the consumables table directly.
$allowed_columns = [
'id',
'name',
'created_at',
'users_count',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$groups = $groups->orderBy($sort, $order);
break;
}
$total = $groups->count();
$groups = $groups->skip($offset)->take($limit)->get();

View File

@@ -107,7 +107,7 @@ class LicenseSeatsController extends Controller
// attempt to update the license seat
$licenseSeat->fill($request->all());
$licenseSeat->user_id = auth()->id();
$licenseSeat->created_by = auth()->id();
// check if this update is a checkin operation
// 1. are relevant fields touched at all?

View File

@@ -27,7 +27,7 @@ class LicensesController extends Controller
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
if ($request->filled('company_id')) {
$licenses->where('company_id', '=', $request->input('company_id'));
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
}
if ($request->filled('name')) {
@@ -70,8 +70,8 @@ class LicensesController extends Controller
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
}
if ($request->filled('user_id')) {
$licenses->where('user_id', '=', $request->input('user_id'));
if ($request->filled('created_by')) {
$licenses->where('created_by', '=', $request->input('created_by'));
}
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
@@ -117,7 +117,7 @@ class LicensesController extends Controller
$licenses = $licenses->leftJoin('companies', 'licenses.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
break;
case 'created_by':
$licenses = $licenses->OrderCreatedBy($order);
$licenses = $licenses->OrderByCreatedBy($order);
break;
default:
$allowed_columns =
@@ -182,7 +182,7 @@ class LicensesController extends Controller
public function show($id) : JsonResponse | array
{
$this->authorize('view', License::class);
$license = License::withCount('freeSeats')->findOrFail($id);
$license = License::withCount('freeSeats as free_seats_count')->findOrFail($id);
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
return (new LicensesTransformer)->transformLicense($license);
@@ -220,7 +220,6 @@ class LicensesController extends Controller
*/
public function destroy($id) : JsonResponse
{
//
$license = License::findOrFail($id);
$this->authorize('delete', $license);

View File

@@ -25,11 +25,43 @@ class ManufacturersController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', Manufacturer::class);
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'warranty_lookup_url', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
$allowed_columns = [
'id',
'name',
'url',
'support_url',
'support_email',
'warranty_lookup_url',
'support_phone',
'created_at',
'updated_at',
'image',
'assets_count',
'consumables_count',
'components_count',
'licenses_count'
];
$manufacturers = Manufacturer::select(
['id', 'name', 'url', 'support_url', 'warranty_lookup_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');
$manufacturers = Manufacturer::select([
'id',
'name',
'url',
'support_url',
'warranty_lookup_url',
'support_email',
'support_phone',
'created_by',
'created_at',
'updated_at',
'image',
'deleted_at',
])
->with('adminuser')
->withCount('assets as assets_count')
->withCount('licenses as licenses_count')
->withCount('consumables as consumables_count')
->withCount('accessories as accessories_count')
->withCount('components as components_count');
if ($request->input('deleted') == 'true') {
$manufacturers->onlyTrashed();
@@ -66,10 +98,18 @@ class ManufacturersController extends Controller
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$manufacturers->orderBy($sort, $order);
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort_override) {
case 'created_by':
$manufacturers = $manufacturers->OrderByCreatedBy($order);
break;
default:
$manufacturers = $manufacturers->orderBy($column_sort, $order);
break;
}
$total = $manufacturers->count();
$manufacturers = $manufacturers->skip($offset)->take($limit)->get();
@@ -181,7 +221,7 @@ class ManufacturersController extends Controller
$logaction->item_type = Manufacturer::class;
$logaction->item_id = $manufacturer->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200);

View File

@@ -23,9 +23,8 @@ class PredefinedKitsController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', PredefinedKit::class);
$allowed_columns = ['id', 'name'];
$kits = PredefinedKit::query();
$kits = PredefinedKit::query()->with('adminuser');
if ($request->filled('search')) {
$kits = $kits->TextSearch($request->input('search'));
@@ -36,8 +35,25 @@ class PredefinedKitsController extends Controller
$limit = app('api_limit_value');
$order = $request->input('order') === 'desc' ? 'desc' : 'asc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'name';
$kits->orderBy($sort, $order);
switch ($request->input('sort')) {
case 'created_by':
$kits = $kits->OrderByCreatedBy($order);
break;
default:
// This array is what determines which fields should be allowed to be sorted on ON the table itself.
// These must match a column on the consumables table directly.
$allowed_columns = [
'id',
'name',
'created_at',
'updated_at',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$kits = $kits->orderBy($sort, $order);
break;
}
$total = $kits->count();
$kits = $kits->skip($offset)->take($limit)->get();
@@ -246,7 +262,7 @@ class PredefinedKitsController extends Controller
$relation = $kit->models();
if ($relation->find($model_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['model' => 'Model already attached to kit']));
return response()->json(Helper::formatStandardApiResponse('error', null, ['model' => trans('admin/kits/general.model_already_attached')]));
}
$relation->attach($model_id, ['quantity' => $quantity]);

View File

@@ -20,7 +20,7 @@ class ReportsController extends Controller
{
$this->authorize('reports.view');
$actionlogs = Actionlog::with('item', 'user', 'admin', 'target', 'location');
$actionlogs = Actionlog::with('item', 'user', 'adminuser', 'target', 'location');
if ($request->filled('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
@@ -48,8 +48,8 @@ class ReportsController extends Controller
$actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc');
}
if ($request->filled('user_id')) {
$actionlogs = $actionlogs->where('user_id', '=', $request->input('user_id'));
if ($request->filled('created_by')) {
$actionlogs = $actionlogs->where('created_by', '=', $request->input('created_by'));
}
if ($request->filled('action_source')) {
@@ -68,13 +68,14 @@ class ReportsController extends Controller
'id',
'created_at',
'target_id',
'user_id',
'created_by',
'accept_signature',
'action_type',
'note',
'remote_ip',
'user_agent',
'action_source',
'action_date',
];
@@ -86,8 +87,8 @@ class ReportsController extends Controller
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
switch ($request->input('sort')) {
case 'admin':
$actionlogs->OrderAdmin($order);
case 'created_by':
$actionlogs->OrderByCreatedBy($order);
break;
default:
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';

View File

@@ -25,9 +25,18 @@ class StatuslabelsController extends Controller
public function index(Request $request) : array
{
$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',
'status_type',
];
$statuslabels = Statuslabel::withCount('assets as assets_count');
$statuslabels = Statuslabel::with('adminuser')->withCount('assets as assets_count');
if ($request->filled('search')) {
$statuslabels = $statuslabels->TextSearch($request->input('search'));
@@ -41,23 +50,30 @@ class StatuslabelsController extends Controller
// 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();
$statuslabels->where('status_type', '=', 'pending');
} elseif (strtolower($request->input('status_type')) == 'archived') $statuslabels->where('status_type', '=', 'archived');
elseif (strtolower($request->input('status_type')) == 'deployable') {
$statuslabels->where('status_type', '=', 'deployable');
} elseif (strtolower($request->input('status_type')) == 'undeployable') {
$statuslabels = $statuslabels->Undeployable();
$statuslabels->whereNot('status_type', 'deployable');
}
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $statuslabels->count()) ? $statuslabels->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$statuslabels->orderBy($sort, $order);
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort_override) {
case 'created_by':
$statuslabels = $statuslabels->OrderByCreatedBy($order);
break;
default:
$statuslabels = $statuslabels->orderBy($column_sort, $order);
break;
}
$total = $statuslabels->count();
$statuslabels = $statuslabels->skip($offset)->take($limit)->get();
@@ -76,19 +92,11 @@ class StatuslabelsController extends Controller
public function store(Request $request) : JsonResponse
{
$this->authorize('create', Statuslabel::class);
$request->except('deployable', 'pending', 'archived');
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->status_type = $request->input('status_type');
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);
@@ -129,20 +137,12 @@ class StatuslabelsController extends Controller
{
$this->authorize('update', Statuslabel::class);
$statuslabel = Statuslabel::findOrFail($id);
$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->status_type = $request->input('status_type');
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);
@@ -190,7 +190,7 @@ class StatuslabelsController extends Controller
$this->authorize('view', Statuslabel::class);
if (Setting::getSettings()->show_archived_in_list == 0 ) {
$statuslabels = Statuslabel::withCount('assets')->where('archived','0')->get();
$statuslabels = Statuslabel::withCount('assets')->whereNot('status_type','archived')->get();
} else {
$statuslabels = Statuslabel::withCount('assets')->get();
}
@@ -284,7 +284,7 @@ class StatuslabelsController extends Controller
public function checkIfDeployable($id) : string
{
$statuslabel = Statuslabel::findOrFail($id);
if ($statuslabel->getStatuslabelType() == 'deployable') {
if ($statuslabel->status_type == 'deployable') {
return '1';
}
@@ -302,22 +302,22 @@ class StatuslabelsController extends Controller
{
$this->authorize('view.selectlists');
$statuslabels = Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('deployable', 'desc');
$statuslabels = Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('status_type', 'desc');
if ($request->filled('search')) {
$statuslabels = $statuslabels->where('name', 'LIKE', '%'.$request->get('search').'%');
}
if ($request->filled('deployable')) {
$statuslabels = $statuslabels->where('deployable', '=', '1');
$statuslabels = $statuslabels->where('status_type', '=', 'deployable');
}
if ($request->filled('pending')) {
$statuslabels = $statuslabels->where('pending', '=', '1');
$statuslabels = $statuslabels->where('status_type', '=', 'pending');
}
if ($request->filled('archived')) {
$statuslabels = $statuslabels->where('archived', '=', '1');
$statuslabels = $statuslabels->where('status_type', '=', 'archived');
}
$statuslabels = $statuslabels->orderBy('name', 'ASC')->paginate(50);

View File

@@ -14,6 +14,7 @@ use App\Http\Transformers\UsersTransformer;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\License;
use App\Models\User;
@@ -42,13 +43,14 @@ class UsersController extends Controller
$users = User::select([
'users.activated',
'users.created_by',
'users.address',
'users.avatar',
'users.city',
'users.company_id',
'users.country',
'users.created_by',
'users.created_at',
'users.updated_at',
'users.deleted_at',
'users.department_id',
'users.email',
@@ -67,7 +69,6 @@ class UsersController extends Controller
'users.state',
'users.two_factor_enrolled',
'users.two_factor_optin',
'users.updated_at',
'users.username',
'users.zip',
'users.remote',
@@ -206,6 +207,10 @@ class UsersController extends Controller
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
}
if ($request->filled('locale')) {
$users = $users->where('users.locale', '=', $request->input('locale'));
}
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
$users = $users->onlyTrashed();
@@ -251,6 +256,7 @@ class UsersController extends Controller
'groups',
'activated',
'created_at',
'updated_at',
'two_factor_enrolled',
'two_factor_optin',
'last_login',
@@ -276,6 +282,7 @@ class UsersController extends Controller
'end_date',
'autoassign_licenses',
'website',
'locale',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name';
@@ -365,6 +372,7 @@ class UsersController extends Controller
$user = new User;
$user->fill($request->all());
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$user->created_by = auth()->id();
if ($request->has('permissions')) {
@@ -427,13 +435,10 @@ class UsersController extends Controller
* @param \Illuminate\Http\Request $request
* @param int $id
*/
public function update(SaveUserRequest $request, $id) : JsonResponse
public function update(SaveUserRequest $request, User $user): JsonResponse
{
$this->authorize('update', User::class);
if ($user = User::find($id)) {
$this->authorize('update', $user);
/**
@@ -443,14 +448,16 @@ class UsersController extends Controller
*
*/
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
}
$user->fill($request->all());
if ($request->filled('company_id')) {
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
}
if ($user->id == $request->input('manager_id')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
}
@@ -473,16 +480,13 @@ class UsersController extends Controller
$user->permissions = $permissions_array;
}
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
// Check if the request has groups passed and has a value, AND that the user us a superuser
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
@@ -496,18 +500,10 @@ class UsersController extends Controller
// Sync the groups since the user is a superuser and the groups pass validation
$user->groups()->sync($request->input('groups'));
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
}
/**
@@ -702,7 +698,7 @@ class UsersController extends Controller
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('2FA reset');
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
@@ -752,7 +748,7 @@ class UsersController extends Controller
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);

View File

@@ -109,7 +109,7 @@ class AssetMaintenancesController extends Controller
$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->created_by = auth()->id();
if (($assetMaintenance->completion_date !== null)
&& ($assetMaintenance->start_date !== '')

View File

@@ -78,7 +78,7 @@ class AssetModelsController extends Controller
$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->created_by = auth()->id();
$model->requestable = $request->has('requestable');
if ($request->input('fieldset_id') != '') {
@@ -151,17 +151,17 @@ class AssetModelsController extends Controller
$model->notes = $request->input('notes');
$model->requestable = $request->input('requestable', '0');
$this->removeCustomFieldsDefaultValues($model);
$model->fieldset_id = $request->input('fieldset_id');
if ($this->shouldAddDefaultValues($request->input())) {
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
}
}
if ($model->save()) {
$this->removeCustomFieldsDefaultValues($model);
if ($this->shouldAddDefaultValues($request->input())) {
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))) {
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
}
}
if ($model->wasChanged('eol')) {
if ($model->eol > 0) {
$newEol = $model->eol;
@@ -202,6 +202,7 @@ class AssetModelsController extends Controller
if ($model->image) {
try {
Storage::disk('public')->delete('models/'.$model->image);
$model->update(['image' => null]);
} catch (\Exception $e) {
Log::info($e);
}
@@ -233,10 +234,10 @@ class AssetModelsController extends Controller
if ($model->restore()) {
$logaction = new Actionlog();
$logaction->item_type = User::class;
$logaction->item_type = AssetModel::class;
$logaction->item_id = $model->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('restore');

View File

@@ -61,43 +61,30 @@ class AssetFilesController extends Controller
*/
public function show($assetId = null, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
{
$asset = Asset::find($assetId);
// the asset is valid
if (isset($asset->id)) {
if ($asset = Asset::find($assetId)) {
$this->authorize('view', $asset);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
$file = 'private_uploads/assets/'.$log->filename;
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.file_not_found'));
}
}
$file = 'private_uploads/assets/'.$log->filename;
if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename;
}
if (! Storage::exists($file)) {
return response('File '.$file.' not found on server', 404)
->header('Content-Type', 'text/plain');
}
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
return StorageHelper::downloader($file);
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
}
// Prepare the error message
$error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]);
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', $error);
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
/**

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Assets;
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
@@ -16,7 +17,6 @@ use App\Models\Location;
use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\View\Label;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
@@ -111,8 +111,10 @@ class AssetsController extends Controller
$settings = Setting::getSettings();
$success = false;
$successes = [];
$failures = [];
$serials = $request->input('serials');
$asset = null;
for ($a = 1; $a <= count($asset_tags); $a++) {
$asset = new Asset();
@@ -132,7 +134,7 @@ class AssetsController extends Controller
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->notes = $request->input('notes');
$asset->user_id = Auth::id();
$asset->created_by = auth()->id();
$asset->status_id = request('status_id');
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = request('purchase_cost');
@@ -165,7 +167,7 @@ class AssetsController extends Controller
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
@@ -199,20 +201,35 @@ class AssetsController extends Controller
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
}
$success = true;
$successes[] = "<a href='" . route('hardware.show', ['hardware' => $asset->id]) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
} else {
$failures[] = join(",", $asset->getErrors()->all());
}
}
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
if ($success) {
if ($successes) {
if ($failures) {
//some succeeded, some failed
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets')) //FIXME - not tested
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]))
->with('warning', trans_choice('admin/hardware/message.create.partial_failure', $failures, ['failures' => join("; ", $failures)]));
} else {
if (count($successes) == 1) {
//the most common case, keeping it so we don't have to make every use of that translation string be trans_choice'ed
//and re-translated
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', ['hardware' => $asset->id]), 'id', 'tag' => e($asset->asset_tag)]));
} else {
//multi-success
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]));
}
}
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', ['hardware' => $asset->id]), 'id', 'tag' => e($asset->asset_tag)]));
}
return redirect()->back()->withInput()->withErrors($asset->getErrors());
@@ -328,16 +345,21 @@ class AssetsController extends Controller
}
$asset->supplier_id = $request->input('supplier_id', null);
$asset->expected_checkin = $request->input('expected_checkin', null);
// If the box isn't checked, it's not in the request at all.
$asset->requestable = $request->filled('requestable');
$asset->requestable = $request->input('requestable', 0);
$asset->rtd_location_id = $request->input('rtd_location_id', null);
$asset->byod = $request->input('byod', 0);
$status = Statuslabel::find($asset->status_id);
$status = Statuslabel::find($request->input('status_id'));
if ($status && $status->archived) {
// This is a non-deployable status label - we should check the asset back in.
if (($status && $status->status_type != 'deployable') && ($target = $asset->assignedTo)) {
$originalValues = $asset->getRawOriginal();
$asset->assigned_to = null;
$asset->assigned_type = null;
$asset->accepted = null;
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update', date('Y-m-d H:i:s'), $originalValues));
}
if ($asset->assigned_to == '') {
@@ -388,7 +410,7 @@ class AssetsController extends Controller
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
@@ -422,7 +444,7 @@ class AssetsController extends Controller
* @param int $assetId
* @since [v1.0]
*/
public function destroy($assetId) : RedirectResponse
public function destroy(Request $request, $assetId) : RedirectResponse
{
// Check if the asset exists
if (is_null($asset = Asset::find($assetId))) {
@@ -432,9 +454,17 @@ class AssetsController extends Controller
$this->authorize('delete', $asset);
DB::table('assets')
->where('id', $asset->id)
->update(['assigned_to' => null]);
if ($asset->assignedTo) {
$target = $asset->assignedTo;
$checkin_at = date('Y-m-d H:i:s');
$originalValues = $asset->getRawOriginal();
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
DB::table('assets')
->where('id', $asset->id)
->update(['assigned_to' => null]);
}
if ($asset->image) {
try {
@@ -739,7 +769,7 @@ class AssetsController extends Controller
Actionlog::firstOrCreate([
'item_id' => $asset->id,
'item_type' => Asset::class,
'user_id' => auth()->id(),
'created_by' => auth()->id(),
'note' => 'Checkout imported by '.auth()->user()->present()->fullName().' from history importer',
'target_id' => $item[$asset_tag][$batch_counter]['user_id'],
'target_type' => User::class,
@@ -767,7 +797,7 @@ class AssetsController extends Controller
Actionlog::firstOrCreate([
'item_id' => $item[$asset_tag][$batch_counter]['asset_id'],
'item_type' => Asset::class,
'user_id' => auth()->id(),
'created_by' => auth()->id(),
'note' => 'Checkin imported by '.auth()->user()->present()->fullName().' from history importer',
'target_id' => null,
'created_at' => $checkin_date,

View File

@@ -10,6 +10,7 @@ use App\Models\AssetModel;
use App\Models\Statuslabel;
use App\Models\Setting;
use App\View\Label;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
@@ -51,6 +52,10 @@ class BulkAssetsController extends Controller
}
$asset_ids = $request->input('ids');
if ($request->input('bulk_actions') === 'checkout') {
$request->session()->flashInput(['selected_assets' => $asset_ids]);
return redirect()->route('hardware.bulkcheckout.show');
}
// Figure out where we need to send the user after the update is complete, and store that in the session
$bulk_back_url = request()->headers->get('referer');
@@ -271,6 +276,23 @@ class BulkAssetsController extends Controller
$this->conditionallyAddItem($custom_field_column);
}
if (!($asset->eol_explicit)) {
if ($request->filled('model_id')) {
$model = AssetModel::find($request->input('model_id'));
if ($model->eol > 0) {
if ($request->filled('purchase_date')) {
$this->update_array['asset_eol_date'] = Carbon::parse($request->input('purchase_date'))->addMonths($model->eol)->format('Y-m-d');
} else {
$this->update_array['asset_eol_date'] = Carbon::parse($asset->purchase_date)->addMonths($model->eol)->format('Y-m-d');
}
} else {
$this->update_array['asset_eol_date'] = null;
}
} elseif (($request->filled('purchase_date')) && ($asset->model->eol > 0)) {
$this->update_array['asset_eol_date'] = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
}
}
/**
* Blank out fields that were requested to be blanked out via checkbox
*/
@@ -281,6 +303,9 @@ class BulkAssetsController extends Controller
if ($request->input('null_purchase_date')=='1') {
$this->update_array['purchase_date'] = null;
if (!($asset->eol_explicit)) {
$this->update_array['asset_eol_date'] = null;
}
}
if ($request->input('null_expected_checkin_date')=='1') {
@@ -550,31 +575,34 @@ class BulkAssetsController extends Controller
}
$errors = [];
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, $errors, $asset_ids, $request) {
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, &$errors, $asset_ids, $request) { //NOTE: $errors is passsed by reference!
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')), $asset->name, null);
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
//TODO - I think this logic is duplicated in the checkOut method?
if ($target->location_id != '') {
$asset->location_id = $target->location_id;
$asset->unsetEventDispatcher();
$asset->save();
// TODO - I don't know why this is being saved without events
$asset::withoutEvents(function () use ($asset) {
$asset->save();
});
}
if ($error) {
array_merge_recursive($errors, $asset->getErrors()->toArray());
if (!$checkout_success) {
$errors = array_merge_recursive($errors, $asset->getErrors()->toArray());
}
}
});
if (! $errors) {
// Redirect to the new asset page
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.checkout.success'));
return redirect()->to('hardware')->with('success', trans_choice('admin/hardware/message.multi-checkout.success', $asset_ids));
}
// Redirect to the asset management page with error
return redirect()->route('hardware.bulkcheckout.show')->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans_choice('admin/hardware/message.multi-checkout.error', $asset_ids))->withErrors($errors);
} catch (ModelNotFoundException $e) {
return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors());
}

View File

@@ -508,8 +508,8 @@ class LoginController extends Controller
protected function validator(array $data)
{
return Validator::make($data, [
'username' => 'required',
'password' => 'required',
'username' => 'required|not_array',
'password' => 'required|not_array',
]);
}

View File

@@ -69,7 +69,7 @@ class CategoriesController extends Controller
$category->use_default_eula = $request->input('use_default_eula', '0');
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$category->user_id = Auth::id();
$category->created_by = auth()->id();
$category = $request->handleImages($category);
if ($category->save()) {

View File

@@ -60,6 +60,7 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone');
$company->fax = $request->input('fax');
$company->email = $request->input('email');
$company->created_by = auth()->id();
$company = $request->handleImages($company);

View File

@@ -106,7 +106,7 @@ class ComponentCheckoutController extends Controller
$component->asset_id = $request->input('asset_id');
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'user_id' => auth()->user()->id,
'created_by' => auth()->user()->id,
'created_at' => date('Y-m-d H:i:s'),
'assigned_qty' => $request->input('assigned_qty'),
'asset_id' => $request->input('asset_id'),

View File

@@ -73,6 +73,8 @@ class ComponentsController extends Controller
$component->name = $request->input('name');
$component->category_id = $request->input('category_id');
$component->supplier_id = $request->input('supplier_id');
$component->manufacturer_id = $request->input('manufacturer_id');
$component->model_number = $request->input('model_number');
$component->location_id = $request->input('location_id');
$component->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$component->order_number = $request->input('order_number', null);
@@ -81,7 +83,7 @@ class ComponentsController extends Controller
$component->purchase_date = $request->input('purchase_date', null);
$component->purchase_cost = $request->input('purchase_cost', null);
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
$component->created_by = auth()->id();
$component->notes = $request->input('notes');
$component = $request->handleImages($component);
@@ -150,6 +152,8 @@ class ComponentsController extends Controller
$component->name = $request->input('name');
$component->category_id = $request->input('category_id');
$component->supplier_id = $request->input('supplier_id');
$component->manufacturer_id = $request->input('manufacturer_id');
$component->model_number = $request->input('model_number');
$component->location_id = $request->input('location_id');
$component->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$component->order_number = $request->input('order_number');

View File

@@ -112,40 +112,25 @@ class ComponentsFilesController extends Controller
public function show($componentId = null, $fileId = null)
{
Log::debug('Private filesystem is: '.config('filesystems.default'));
$component = Component::find($componentId);
// the component is valid
if (isset($component->id)) {
if ($component = Component::find($componentId)) {
$this->authorize('view', $component);
$this->authorize('components.files', $component);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) {
$file = 'private_uploads/components/'.$log->filename;
$file = 'private_uploads/components/'.$log->filename;
if (Storage::missing($file)) {
Log::debug('FILE DOES NOT EXISTS for '.$file);
Log::debug('URL should be '.Storage::url($file));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.file_not_found'));
}
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
}
}
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));

View File

@@ -70,7 +70,7 @@ class ConsumableCheckoutController extends Controller
$this->authorize('checkout', $consumable);
// If the quantity is not present in the request or is not a positive integer, set it to 1
$quantity = $request->input('qty');
$quantity = $request->input('checkout_qty');
if (!isset($quantity) || !ctype_digit((string)$quantity) || $quantity <= 0) {
$quantity = 1;
}
@@ -92,14 +92,16 @@ class ConsumableCheckoutController extends Controller
// Update the consumable data
$consumable->assigned_to = e($request->input('assigned_to'));
for($i = 0; $i < $quantity; $i++){
for ($i = 0; $i < $quantity; $i++){
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'user_id' => $admin_user->id,
'created_by' => $admin_user->id,
'assigned_to' => e($request->input('assigned_to')),
'note' => $request->input('note'),
]);
}
$consumable->checkout_qty = $quantity;
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
$request->request->add(['checkout_to_type' => 'user']);

View File

@@ -81,7 +81,7 @@ class ConsumablesController extends Controller
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = $request->input('purchase_cost');
$consumable->qty = $request->input('qty');
$consumable->user_id = Auth::id();
$consumable->created_by = auth()->id();
$consumable->notes = $request->input('notes');
@@ -221,7 +221,7 @@ class ConsumablesController extends Controller
$consumable = clone $consumable_to_close;
$consumable->id = null;
$consumable->image = null;
$consumable->user_id = null;
$consumable->created_by = null;
return view('consumables/edit')->with('item', $consumable);
}

View File

@@ -104,7 +104,6 @@ class ConsumablesFilesController extends Controller
* @since [v1.4]
* @param int $consumableId
* @param int $fileId
* @return \Symfony\Consumable\HttpFoundation\Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($consumableId = null, $fileId = null)
@@ -116,36 +115,18 @@ class ConsumablesFilesController extends Controller
$this->authorize('view', $consumable);
$this->authorize('consumables.files', $consumable);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) {
$file = 'private_uploads/consumables/'.$log->filename;
$file = 'private_uploads/consumables/'.$log->filename;
if (Storage::missing($file)) {
Log::debug('FILE DOES NOT EXISTS for '.$file);
Log::debug('URL should be '.Storage::url($file));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.file_not_found'));
}
}
// The log record doesn't exist somehow
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));

View File

@@ -104,7 +104,7 @@ class CustomFieldsController extends Controller
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
"show_in_listview" => $request->get("show_in_listview", 0),
"show_in_requestable_list" => $request->get("show_in_requestable_list", 0),
"user_id" => Auth::id()
"user_id" => auth()->id()
]);
@@ -248,7 +248,7 @@ class CustomFieldsController extends Controller
$field->name = trim(e($request->get("name")));
$field->element = e($request->get("element"));
$field->field_values = $request->get("field_values");
$field->user_id = Auth::id();
$field->created_by = auth()->id();
$field->help_text = $request->get("help_text");
$field->show_in_email = $show_in_email;
$field->is_unique = $request->get("is_unique", 0);

View File

@@ -90,7 +90,7 @@ class CustomFieldsetsController extends Controller
$fieldset = new CustomFieldset([
'name' => $request->get('name'),
'user_id' => auth()->id(),
'created_by' => auth()->id(),
]);
$validator = Validator::make($request->all(), $fieldset->rules);

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Session;
/**
@@ -44,6 +45,8 @@ class DashboardController extends Controller
return view('dashboard')->with('asset_stats', $asset_stats)->with('counts', $counts);
} else {
Session::reflash();
// Redirect to the profile page
return redirect()->intended('account/view-assets');
}

View File

@@ -51,7 +51,7 @@ class DepartmentsController extends Controller
$this->authorize('create', Department::class);
$department = new Department;
$department->fill($request->all());
$department->user_id = auth()->id();
$department->created_by = auth()->id();
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
$department->location_id = ($request->filled('location_id') ? $request->input('location_id') : null);
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);

View File

@@ -61,7 +61,7 @@ class DepreciationsController extends Controller
// Depreciation data
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$depreciation->user_id = Auth::id();
$depreciation->created_by = auth()->id();
$request->validate([
'depreciation_min' => [
@@ -193,13 +193,20 @@ class DepreciationsController extends Controller
*/
public function show($id) : View | RedirectResponse
{
if (is_null($depreciation = Depreciation::find($id))) {
// Redirect to the blogs management page
return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
$depreciation = Depreciation::withCount('assets as assets_count')
->withCount('models as models_count')
->withCount('licenses as licenses_count')
->find($id);
$this->authorize('view', $depreciation);
return view('depreciations/view', compact('depreciation'));
if ($depreciation) {
return view('depreciations/view', compact('depreciation'));
}
return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\DB;
/**
* This controller provide the health route for
@@ -15,13 +16,35 @@ use Illuminate\Routing\Controller as BaseController;
*/
class HealthController extends BaseController
{
public function __construct()
{
$this->middleware('health');
}
/**
* Returns a fixed JSON content ({ "status": "ok"}) which indicate the app is up and running
*/
public function get()
{
return response()->json([
'status' => 'ok',
]);
try {
if (DB::select('select 2 + 2')) {
return response()->json([
'status' => 'ok',
]);
}
} catch (\Exception $e) {
\Log::error('Could not connect to database');
return response()->json([
'status' => 'database connection failed',
], 500);
}
}
}

View File

@@ -62,10 +62,10 @@ class CheckoutKitController extends Controller
$checkout_result = $this->kitService->checkout($request, $kit, $user);
if (Arr::has($checkout_result, 'errors') && count($checkout_result['errors']) > 0) {
return redirect()->back()->with('error', trans('general.checkout_error'))->with('error_messages', $checkout_result['errors']);
return redirect()->back()->with('error', trans('admin/kits/general.checkout_error'))->with('error_messages', $checkout_result['errors']);
}
return redirect()->back()->with('success', trans('general.checkout_success'))
return redirect()->back()->with('success', trans('admin/kits/general.checkout_success'))
->with('assets', Arr::get($checkout_result, 'assets', null))
->with('accessories', Arr::get($checkout_result, 'accessories', null))
->with('consumables', Arr::get($checkout_result, 'consumables', null));

View File

@@ -55,6 +55,7 @@ class PredefinedKitsController extends Controller
// Create a new Predefined Kit
$kit = new PredefinedKit;
$kit->name = $request->input('name');
$kit->created_by = auth()->id();
if (! $kit->save()) {
return redirect()->back()->withInput()->withErrors($kit->getErrors());

View File

@@ -77,7 +77,7 @@ class LicenseCheckoutController extends Controller
$this->authorize('checkout', $license);
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
$licenseSeat->user_id = Auth::id();
$licenseSeat->created_by = auth()->id();
$licenseSeat->notes = $request->input('notes');

View File

@@ -112,37 +112,19 @@ class LicenseFilesController extends Controller
$this->authorize('view', $license);
$this->authorize('licenses.files', $license);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/licenses/'.$log->filename;
if (Storage::missing($file)) {
Log::debug('NOT EXISTS for '.$file);
Log::debug('NOT EXISTS URL should be '.Storage::url($file));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) {
$file = 'private_uploads/licenses/'.$log->filename;
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.file_not_found'));
}
}
// The log record doesn't exist somehow
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.log_record_not_found'));
}
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId]));

View File

@@ -99,7 +99,7 @@ class LicensesController extends Controller
$license->supplier_id = $request->input('supplier_id');
$license->category_id = $request->input('category_id');
$license->termination_date = $request->input('termination_date');
$license->user_id = Auth::id();
$license->created_by = auth()->id();
$license->min_amt = $request->input('min_amt');
session()->put(['redirect_option' => $request->get('redirect_option')]);

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Location;
use App\Models\User;
@@ -74,7 +75,7 @@ class LocationsController extends Controller
$location->zip = $request->input('zip');
$location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id');
$location->user_id = auth()->id();
$location->created_by = auth()->id();
$location->phone = request('phone');
$location->fax = request('fax');
@@ -193,7 +194,13 @@ class LocationsController extends Controller
*/
public function show($id = null) : View | RedirectResponse
{
$location = Location::find($id);
$location = Location::withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withTrashed()
->find($id);
if (isset($location->id)) {
return view('locations/view', compact('location'));
@@ -249,6 +256,41 @@ class LocationsController extends Controller
}
/**
* Restore a given Asset Model (mark as un-deleted)
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $id
*/
public function postRestore($id) : RedirectResponse
{
$this->authorize('create', Location::class);
if ($location = Location::withTrashed()->find($id)) {
if ($location->deleted_at == '') {
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.location')]));
}
if ($location->restore()) {
$logaction = new Actionlog();
$logaction->item_type = Location::class;
$logaction->item_id = $location->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
}
// Check validation
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
}
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
}
public function print_all_assigned($id) : View | RedirectResponse
{
if ($location = Location::where('id', $id)->first()) {

View File

@@ -61,7 +61,7 @@ class ManufacturersController extends Controller
$this->authorize('create', Manufacturer::class);
$manufacturer = new Manufacturer;
$manufacturer->name = $request->input('name');
$manufacturer->user_id = Auth::id();
$manufacturer->created_by = auth()->id();
$manufacturer->url = $request->input('url');
$manufacturer->support_url = $request->input('support_url');
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
@@ -219,7 +219,7 @@ class ManufacturersController extends Controller
$logaction->item_type = Manufacturer::class;
$logaction->item_id = $manufacturer->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index

View File

@@ -40,7 +40,7 @@ class ModalController extends Controller
$view = view("modals.${type}");
if ($type == "statuslabel") {
$view->with('statuslabel_types', Helper::statusTypeList());
$view->with('status_types', Helper::statusTypeList());
}
if (in_array($type, ['kit-model', 'kit-license', 'kit-consumable', 'kit-accessory'])) {
$view->with('kitId', $itemId);

View File

@@ -50,6 +50,7 @@ class ProfileController extends Controller
$user->skin = $request->input('skin');
$user->phone = $request->input('phone');
$user->enable_sounds = $request->input('enable_sounds', false);
$user->enable_confetti = $request->input('enable_confetti', false);
if (! config('app.lock_passwords')) {
$user->locale = $request->input('locale', 'en-US');
@@ -193,14 +194,14 @@ class ProfileController extends Controller
*/
public function printInventory() : View
{
$show_user = auth()->user();
$show_users = User::where('id',auth()->user()->id)->get();
return view('users/print')
->with('assets', auth()->user()->assets)
->with('licenses', $show_user->licenses()->get())
->with('accessories', $show_user->accessories()->get())
->with('consumables', $show_user->consumables()->get())
->with('show_user', $show_user)
->with('assets', auth()->user()->assets())
->with('licenses', auth()->user()->licenses()->get())
->with('accessories', auth()->user()->accessories()->get())
->with('consumables', auth()->user()->consumables()->get())
->with('users', $show_users)
->with('settings', Setting::getSettings());
}
@@ -221,7 +222,12 @@ class ProfileController extends Controller
return redirect()->back()->with('error', trans('admin/users/message.user_has_no_email'));
}
$user->notify((new CurrentInventory($user)));
try {
$user->notify((new CurrentInventory($user)));
} catch (\Exception $e) {
\Log::error($e);
}
return redirect()->back()->with('success', trans('admin/users/general.user_notified'));
}
}

View File

@@ -703,6 +703,10 @@ class ReportsController extends Controller
$assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]);
}
if (($request->filled('asset_eol_date_start')) && ($request->filled('asset_eol_date_end'))) {
$assets->whereBetween('assets.asset_eol_date', [$request->input('asset_eol_date_start'), $request->input('asset_eol_date_end')]);
}
if (($request->filled('last_audit_start')) && ($request->filled('last_audit_end'))) {
$last_audit_start = Carbon::parse($request->input('last_audit_start'))->startOfDay();
$last_audit_end = Carbon::parse($request->input('last_audit_end'))->endOfDay();
@@ -778,7 +782,7 @@ class ReportsController extends Controller
}
if ($request->filled('eol')) {
$row[] = ($asset->asset_eol_date) ? $asset->asset_eol_date : '';
$row[] = ($asset->purchase_date != '') ? $asset->asset_eol_date : '';
}
if ($request->filled('order')) {

View File

@@ -7,6 +7,11 @@ use App\Helpers\StorageHelper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsSamlRequest;
use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\StoreLdapSettings;
use App\Http\Requests\StoreLocalizationSettings;
use App\Http\Requests\StoreNotificationSettings;
use App\Http\Requests\StoreLabelSettings;
use App\Http\Requests\StoreSecuritySettings;
use App\Models\CustomField;
use App\Models\Group;
use App\Models\Setting;
@@ -181,7 +186,7 @@ class SettingsController extends Controller
$settings->brand = 1;
$settings->locale = $request->input('locale', 'en-US');
$settings->default_currency = $request->input('default_currency', 'USD');
$settings->user_id = 1;
$settings->created_by = 1;
$settings->email_domain = $request->input('email_domain');
$settings->email_format = $request->input('email_format');
$settings->next_auto_tag_base = 1;
@@ -273,20 +278,6 @@ class SettingsController extends Controller
return view('settings/index', compact('settings'));
}
/**
* Return the admin settings page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v1.0]
*/
public function getEdit() : View
{
$setting = Setting::getSettings();
return view('settings/general', compact('setting'));
}
/**
* Return a form to allow a super admin to update settings.
@@ -486,7 +477,7 @@ class SettingsController extends Controller
*
* @since [v1.0]
*/
public function postSecurity(Request $request) : RedirectResponse
public function postSecurity(StoreSecuritySettings $request) : RedirectResponse
{
$this->validate($request, [
'pwd_secure_complexity' => 'array',
@@ -556,7 +547,7 @@ class SettingsController extends Controller
*
* @since [v1.0]
*/
public function postLocalization(Request $request) : RedirectResponse
public function postLocalization(StoreLocalizationSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@@ -599,7 +590,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
*/
public function postAlerts(Request $request) : RedirectResponse
public function postAlerts(StoreNotificationSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@@ -637,6 +628,7 @@ class SettingsController extends Controller
$setting->alert_threshold = $request->input('alert_threshold');
$setting->audit_interval = $request->input('audit_interval');
$setting->audit_warning_days = $request->input('audit_warning_days');
$setting->due_checkin_days = $request->input('due_checkin_days');
$setting->show_alerts_in_menu = $request->input('show_alerts_in_menu', '0');
if ($setting->save()) {
@@ -779,7 +771,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*/
public function postLabels(Request $request) : RedirectResponse
public function postLabels(StoreLabelSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@@ -858,26 +850,7 @@ class SettingsController extends Controller
{
$setting = Setting::getSettings();
$groups = Group::pluck('name', 'id');
/**
* This validator is only temporary (famous last words.) - @snipe
*/
$messages = [
'ldap_username_field.not_in' => '<code>sAMAccountName</code> (mixed case) will likely not work. You should use <code>samaccountname</code> (lowercase) instead. ',
'ldap_auth_filter_query.not_in' => '<code>uid=samaccountname</code> is probably not a valid auth filter. You probably want <code>uid=</code> ',
'ldap_filter.regex' => 'This value should probably not be wrapped in parentheses.',
];
$validator = Validator::make($setting->toArray(), [
'ldap_username_field' => 'not_in:sAMAccountName',
'ldap_auth_filter_query' => 'not_in:uid=samaccountname|required_if:ldap_enabled,1',
'ldap_filter' => 'nullable|regex:"^[^(]"|required_if:ldap_enabled,1',
], $messages);
return view('settings.ldap', compact('setting', 'groups'))->withErrors($validator);
return view('settings.ldap', compact('setting', 'groups'));
}
/**
@@ -886,7 +859,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*/
public function postLdapSettings(Request $request) : RedirectResponse
public function postLdapSettings(StoreLdapSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@@ -1203,7 +1176,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0]
*/
public function postRestore($filename = null) : RedirectResponse
public function postRestore(Request $request, $filename = null): RedirectResponse
{
if (! config('app.lock_passwords')) {
@@ -1223,13 +1196,29 @@ class SettingsController extends Controller
Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
// run the restore command
Artisan::call('snipeit:restore',
[
$restore_params = [
'--force' => true,
'--no-progress' => true,
'filename' => storage_path($path).'/'.$filename
]);
'filename' => storage_path($path) . '/' . $filename
];
if ($request->input('clean')) {
Log::debug("Attempting 'clean' - first, guessing prefix...");
Artisan::call('snipeit:restore', [
'--sanitize-guess-prefix' => true,
'filename' => storage_path($path) . '/' . $filename
]);
$guess_prefix_output = Artisan::output();
Log::debug("Sanitize output is: $guess_prefix_output");
list($prefix, $_output) = explode("\n", $guess_prefix_output);
Log::debug("prefix is: '$prefix'");
$restore_params['--sanitize-with-prefix'] = $prefix;
}
// run the restore command
Artisan::call('snipeit:restore',
$restore_params
);
// If it's greater than 300, it probably worked
$output = Artisan::output();

View File

@@ -47,7 +47,7 @@ class StatuslabelsController extends Controller
return view('statuslabels/edit')
->with('item', new Statuslabel)
->with('statuslabel_types', Helper::statusTypeList());
->with('status_types', Helper::statusTypeList());
}
/**
@@ -61,19 +61,11 @@ class StatuslabelsController extends Controller
// create a new model instance
$statusLabel = new Statuslabel();
if ($request->missing('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
$statusType = Statuslabel::getStatuslabelTypesForDB($request->input('statuslabel_types'));
// Save the Statuslabel data
$statusLabel->name = $request->input('name');
$statusLabel->user_id = Auth::id();
$statusLabel->created_by = auth()->id();
$statusLabel->notes = $request->input('notes');
$statusLabel->deployable = $statusType['deployable'];
$statusLabel->pending = $statusType['pending'];
$statusLabel->archived = $statusType['archived'];
$statusLabel->status_type = $request->input('status_type');
$statusLabel->color = $request->input('color');
$statusLabel->show_in_nav = $request->input('show_in_nav', 0);
$statusLabel->default_label = $request->input('default_label', 0);
@@ -100,11 +92,7 @@ class StatuslabelsController extends Controller
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
$use_statuslabel_type = $item->getStatuslabelType();
$statuslabel_types = ['' => trans('admin/hardware/form.select_statustype')] + ['undeployable' => trans('admin/hardware/general.undeployable')] + ['pending' => trans('admin/hardware/general.pending')] + ['archived' => trans('admin/hardware/general.archived')] + ['deployable' => trans('admin/hardware/general.deployable')];
return view('statuslabels/edit', compact('item', 'statuslabel_types'))->with('use_statuslabel_type', $use_statuslabel_type);
return view('statuslabels/edit', compact('item'))->with('status_types', Helper::statusTypeList());;
}
/**
@@ -121,17 +109,10 @@ class StatuslabelsController extends Controller
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
if (! $request->filled('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
// Update the Statuslabel data
$statustype = Statuslabel::getStatuslabelTypesForDB($request->input('statuslabel_types'));
$statuslabel->name = $request->input('name');
$statuslabel->notes = $request->input('notes');
$statuslabel->deployable = $statustype['deployable'];
$statuslabel->pending = $statustype['pending'];
$statuslabel->archived = $statustype['archived'];
$statuslabel->status_type = $request->input('status_type');
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);

View File

@@ -62,7 +62,7 @@ class SuppliersController extends Controller
$supplier->email = request('email');
$supplier->notes = request('notes');
$supplier->url = $supplier->addhttp(request('url'));
$supplier->user_id = Auth::id();
$supplier->created_by = auth()->id();
$supplier = $request->handleImages($supplier);
if ($supplier->save()) {

View File

@@ -13,6 +13,7 @@ use App\Models\Group;
use App\Models\LicenseSeat;
use App\Models\ConsumableAssignment;
use App\Models\Consumable;
use App\Models\Setting;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
@@ -30,12 +31,12 @@ class BulkUsersController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.7]
* @param Request $request
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit(Request $request)
{
$this->authorize('update', User::class);
$this->authorize('view', User::class);
// Make sure there were users selected
if (($request->filled('ids')) && (count($request->input('ids')) > 0)) {
@@ -47,16 +48,18 @@ class BulkUsersController extends Controller
// bulk edit, display the bulk edit form
if ($request->input('bulk_actions') == 'edit') {
$this->authorize('update', User::class);
return view('users/bulk-edit', compact('users'))
->with('groups', Group::pluck('name', 'id'));
// bulk delete, display the bulk delete confirmation form
} elseif ($request->input('bulk_actions') == 'delete') {
$this->authorize('delete', User::class);
return view('users/confirm-bulk-delete')->with('users', $users)->with('statuslabel_list', Helper::statusLabelList());
// merge, confirm they have at least 2 users selected and display the merge screen
} elseif ($request->input('bulk_actions') == 'merge') {
$this->authorize('delete', User::class);
if (($request->filled('ids')) && (count($request->input('ids')) > 1)) {
return view('users/confirm-merge')->with('users', $users);
// Not enough users selected, send them back
@@ -76,6 +79,33 @@ class BulkUsersController extends Controller
}
return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent'));
} elseif ($request->input('bulk_actions') == 'print') {
$users = User::query()
->with([
'assets.assetlog',
'assets.assignedAssets.assetlog',
'assets.assignedAssets.defaultLoc',
'assets.assignedAssets.location',
'assets.assignedAssets.model.category',
'assets.defaultLoc',
'assets.location',
'assets.model.category',
'accessories.assetlog',
'accessories.category',
'accessories.manufacturer',
'consumables.assetlog',
'consumables.category',
'consumables.manufacturer',
'licenses.category',
])
->withTrashed()
->findMany($request->input('ids'));
$users->each(fn($user) => $this->authorize('view', $user));
return view('users.print')
->with('users', $users)
->with('settings', Setting::getSettings());
}
}
@@ -101,7 +131,7 @@ class BulkUsersController extends Controller
$user_raw_array = $request->input('ids');
// Remove the user from any updates.
$user_raw_array = array_diff($user_raw_array, [Auth::id()]);
$user_raw_array = array_diff($user_raw_array, [auth()->id()]);
$manager_conflict = false;
$users = User::whereIn('id', $user_raw_array)->where('id', '!=', auth()->id())->get();
@@ -116,6 +146,9 @@ class BulkUsersController extends Controller
->conditionallyAddItem('remote')
->conditionallyAddItem('ldap_import')
->conditionallyAddItem('activated')
->conditionallyAddItem('start_date')
->conditionallyAddItem('end_date')
->conditionallyAddItem('city')
->conditionallyAddItem('autoassign_licenses');
@@ -146,13 +179,24 @@ class BulkUsersController extends Controller
$this->update_array['company_id'] = null;
}
if ($request->input('null_start_date')=='1') {
$this->update_array['start_date'] = null;
}
if ($request->input('null_end_date')=='1') {
$this->update_array['end_date'] = null;
}
if ($request->input('null_locale')=='1') {
$this->update_array['locale'] = null;
}
if (! $manager_conflict) {
$this->conditionallyAddItem('manager_id');
}
// Save the updated info
User::whereIn('id', $user_raw_array)
->where('id', '!=', Auth::id())->update($this->update_array);
->where('id', '!=', auth()->id())->update($this->update_array);
if (array_key_exists('location_id', $this->update_array)){
Asset::where('assigned_type', User::class)
@@ -214,7 +258,7 @@ class BulkUsersController extends Controller
$user_raw_array = request('ids');
if (($key = array_search(Auth::id(), $user_raw_array)) !== false) {
if (($key = array_search(auth()->id(), $user_raw_array)) !== false) {
unset($user_raw_array[$key]);
}
@@ -279,7 +323,7 @@ class BulkUsersController extends Controller
$logAction->item_type = $itemType;
$logAction->target_id = $item->assigned_to;
$logAction->target_type = User::class;
$logAction->user_id = Auth::id();
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}
@@ -293,7 +337,7 @@ class BulkUsersController extends Controller
$logAction->item_type = Accessory::class;
$logAction->target_id = $accessoryUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->user_id = Auth::id();
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}
@@ -307,7 +351,7 @@ class BulkUsersController extends Controller
$logAction->item_type = Consumable::class;
$logAction->target_id = $consumableUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->user_id = Auth::id();
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}

View File

@@ -7,9 +7,6 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
use App\Models\Actionlog;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Illuminate\Support\Facades\Storage;
@@ -46,7 +43,7 @@ class UserFilesController extends Controller
$logAction = new Actionlog();
$logAction->item_id = $user->id;
$logAction->item_type = User::class;
$logAction->user_id = Auth::id();
$logAction->created_by = auth()->id();
$logAction->note = $request->input('notes');
$logAction->target_id = null;
$logAction->created_at = date("Y-m-d H:i:s");
@@ -116,31 +113,30 @@ class UserFilesController extends Controller
public function show($userId = null, $fileId = null)
{
if (empty($fileId)) {
return redirect()->route('users.show')->with('error', 'Invalid file request');
}
$user = User::find($userId);
// the license is valid
if (isset($user->id)) {
if ($user = User::find($userId)) {
$this->authorize('view', $user);
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
$file = 'private_uploads/users/'.$log->filename;
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download('private_uploads/users/'.$log->filename, $log->filename, $headers);
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.file_not_found'));
}
return Storage::download('private_uploads/users/'.$log->filename);
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.log_record_not_found'));
// The log record doesn't exist somehow
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.log_record_not_found'));
return redirect()->back()->with('error', trans('general.file_not_found'));
}
// Redirect to the user management page if the user doesn't exist

View File

@@ -186,7 +186,7 @@ class UsersController extends Controller
{
$this->authorize('update', User::class);
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id);
$user = User::with(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed()->find($id);
if ($user) {
@@ -214,83 +214,79 @@ class UsersController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(SaveUserRequest $request, $id = null)
public function update(SaveUserRequest $request, User $user)
{
$this->authorize('update', User::class);
// This is a janky hack to prevent people from changing admin demo user data on the public demo.
// The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
// Thanks, jerks. You are why we can't have nice things. - snipe
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) {
return redirect()->route('users.index')->with('error', trans('general.permission_denied_superuser_demo'));
}
// We need to reverse the UI specific logic for our
// permissions here before we update the user.
$permissions = $request->input('permissions', []);
app('request')->request->set('permissions', $permissions);
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id);
$user->load(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed();
// User is valid - continue...
if ($user) {
$this->authorize('update', $user);
$this->authorize('update', $user);
// Figure out of this user was an admin before this edit
$orig_permissions_array = $user->decodePermissions();
$orig_superuser = '0';
if (is_array($orig_permissions_array)) {
if (array_key_exists('superuser', $orig_permissions_array)) {
$orig_superuser = $orig_permissions_array['superuser'];
}
// Figure out of this user was an admin before this edit
$orig_permissions_array = $user->decodePermissions();
$orig_superuser = '0';
if (is_array($orig_permissions_array)) {
if (array_key_exists('superuser', $orig_permissions_array)) {
$orig_superuser = $orig_permissions_array['superuser'];
}
}
// Only save groups if the user is a superuser
if (auth()->user()->isSuperUser()) {
$user->groups()->sync($request->input('groups'));
}
// Only save groups if the user is a superuser
if (auth()->user()->isSuperUser()) {
$user->groups()->sync($request->input('groups'));
}
// Update the user fields
$user->username = trim($request->input('username'));
$user->email = trim($request->input('email'));
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
$user->locale = $request->input('locale');
$user->employee_num = $request->input('employee_num');
$user->activated = $request->input('activated', 0);
$user->jobtitle = $request->input('jobtitle', null);
$user->phone = $request->input('phone');
$user->location_id = $request->input('location_id', null);
$user->company_id = Company::getIdForUser($request->input('company_id', null));
$user->manager_id = $request->input('manager_id', null);
$user->notes = $request->input('notes');
$user->department_id = $request->input('department_id', null);
$user->address = $request->input('address', null);
$user->city = $request->input('city', null);
$user->state = $request->input('state', null);
$user->country = $request->input('country', null);
// if a user is editing themselves we should always keep activated true
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->vip = $request->input('vip', 0);
$user->website = $request->input('website', null);
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
// Update the user fields
$user->username = trim($request->input('username'));
$user->email = trim($request->input('email'));
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
$user->locale = $request->input('locale');
$user->employee_num = $request->input('employee_num');
$user->activated = $request->input('activated', 0);
$user->jobtitle = $request->input('jobtitle', null);
$user->phone = $request->input('phone');
$user->location_id = $request->input('location_id', null);
$user->company_id = Company::getIdForUser($request->input('company_id', null));
$user->manager_id = $request->input('manager_id', null);
$user->notes = $request->input('notes');
$user->department_id = $request->input('department_id', null);
$user->address = $request->input('address', null);
$user->city = $request->input('city', null);
$user->state = $request->input('state', null);
$user->country = $request->input('country', null);
// if a user is editing themselves we should always keep activated true
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->vip = $request->input('vip', 0);
$user->website = $request->input('website', null);
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)
->update(['location_id' => $request->input('location_id', null)]);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)
->update(['location_id' => $request->input('location_id', null)]);
// Do we want to update the user password?
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
// Do we want to update the user password?
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
// Update the location of any assets checked out to this user
@@ -318,13 +314,7 @@ class UsersController extends Controller
return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))
->with('success', trans('admin/users/message.success.update'));
}
return redirect()->back()->withInput()->withErrors($user->getErrors());
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
}
/**
@@ -382,7 +372,7 @@ class UsersController extends Controller
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->user_id = auth()->id();
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index
@@ -601,29 +591,43 @@ class UsersController extends Controller
/**
* Print inventory
*
* @author Aladin Alaily
* @since [v1.8]
* @return \Illuminate\Http\RedirectResponse
* @author Aladin Alaily
*/
public function printInventory($id)
{
$this->authorize('view', User::class);
$user = User::where('id', $id)->withTrashed()->first();
// Make sure they can view this particular user
$this->authorize('view', $user);
$user = User::where('id', $id)
->with([
'assets.assetlog',
'assets.assignedAssets.assetlog',
'assets.assignedAssets.defaultLoc',
'assets.assignedAssets.location',
'assets.assignedAssets.model.category',
'assets.defaultLoc',
'assets.location',
'assets.model.category',
'accessories.assetlog',
'accessories.category',
'accessories.manufacturer',
'consumables.assetlog',
'consumables.category',
'consumables.manufacturer',
'licenses.category',
])
->withTrashed()
->first();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', User::class)->with('model', 'model.category')->get();
$accessories = $user->accessories()->get();
$consumables = $user->consumables()->get();
if ($user) {
$this->authorize('view', $user);
return view('users/print')->with('assets', $assets)
->with('licenses', $user->licenses()->get())
->with('accessories', $accessories)
->with('consumables', $consumables)
->with('show_user', $user)
->with('settings', Setting::getSettings());
return view('users.print')
->with('users', [$user])
->with('settings', Setting::getSettings());
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
}
/**

View File

@@ -13,6 +13,7 @@ use App\Notifications\RequestAssetNotification;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View;
use Log;
/**
* This controller handles all actions related to the ability for users
@@ -179,8 +180,11 @@ class ViewAssetsController extends Controller
$asset->decrement('requests_counter', 1);
$logaction->logaction('request canceled');
$settings->notify(new RequestAssetCancelation($data));
try {
$settings->notify(new RequestAssetCancelation($data));
} catch (\Exception $e) {
Log::warning($e);
}
return redirect()->route('requestable-assets')
->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
}
@@ -188,7 +192,11 @@ class ViewAssetsController extends Controller
$logaction->logaction('requested');
$asset->request();
$asset->increment('requests_counter', 1);
$settings->notify(new RequestAssetNotification($data));
try {
$settings->notify(new RequestAssetNotification($data));
} catch (\Exception $e) {
Log::warning($e);
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
}

View File

@@ -14,6 +14,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\NoSessionStore::class,
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Session\Middleware\StartSession::class,
@@ -21,6 +22,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\CheckForSetup::class,
\App\Http\Middleware\CheckForDebug::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrimStrings::class,
\App\Http\Middleware\SecurityHeaders::class,
\App\Http\Middleware\PreventBackHistory::class,
\Illuminate\Http\Middleware\HandleCors::class,
@@ -48,8 +50,13 @@ class Kernel extends HttpKernel
'api' => [
'auth:api',
\App\Http\Middleware\CheckLocale::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'health' => [
],
];
/**
@@ -66,5 +73,6 @@ class Kernel extends HttpKernel
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'health' => null,
];
}

View File

@@ -7,14 +7,19 @@ use Closure;
class CheckForSetup
{
protected $except = [
'_debugbar*',
'health'
];
public function handle($request, Closure $next, $guard = null)
{
/**
* This is dumb
* @todo Check on removing this, not sure if it's still needed
* Skip this middleware for the debugbar and health check
*/
if ($request->is('_debugbar*')) {
if ($request->is($this->except)) {
return $next($request);
}
@@ -25,7 +30,7 @@ class CheckForSetup
return $next($request);
}
} else {
if (! ($request->is('setup*')) && ! ($request->is('.env')) && ! ($request->is('health'))) {
if (! ($request->is('setup*')) && ! ($request->is('.env'))) {
return redirect(config('app.url').'/setup');
}

View File

@@ -60,7 +60,7 @@ class ItemImportRequest extends FormRequest
$fieldMappings = array_change_key_case(array_flip($import->field_map), CASE_LOWER);
}
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
->setUserId(Auth::id())
->setUserId(auth()->id())
->setUpdating($this->get('import-update'))
->setShouldNotify($this->get('send-welcome'))
->setUsernameFormat('firstname.lastname')

View File

@@ -6,6 +6,7 @@ use App\Models\Setting;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use App\Rules\UserCannotSwitchCompaniesIfItemsAssigned;
class SaveUserRequest extends FormRequest
{
@@ -34,6 +35,7 @@ class SaveUserRequest extends FormRequest
$rules = [
'department_id' => 'nullable|exists:departments,id',
'manager_id' => 'nullable|exists:users,id',
'company_id' => ['nullable','exists:companies,id']
];
switch ($this->method()) {
@@ -52,11 +54,13 @@ class SaveUserRequest extends FormRequest
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('update').'|confirmed';
$rules['company_id'] = [new UserCannotSwitchCompaniesIfItemsAssigned()];
break;
// Save only what's passed
case 'PATCH':
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
$rules['company_id'] = [new UserCannotSwitchCompaniesIfItemsAssigned()];
break;
default:

View File

@@ -9,6 +9,7 @@ use App\Models\Setting;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Illuminate\Support\Facades\Gate;
use App\Rules\AssetCannotBeCheckedOutToNondeployableStatus;
class StoreAssetRequest extends ImageUploadRequest
{
@@ -28,7 +29,8 @@ class StoreAssetRequest extends ImageUploadRequest
// Guard against users passing in an array for company_id instead of an integer.
// If the company_id is not an integer then we simply use what was
// provided to be caught by model level validation later.
$idForCurrentUser = is_int($this->company_id)
// The use of is_numeric accounts for 1 and '1'.
$idForCurrentUser = is_numeric($this->company_id)
? Company::getIdForCurrentUser($this->company_id)
: $this->company_id;
@@ -61,6 +63,7 @@ class StoreAssetRequest extends ImageUploadRequest
return array_merge(
$modelRules,
['status_id' => [new AssetCannotBeCheckedOutToNondeployableStatus()]],
parent::rules(),
);
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLabelSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
'labels_pmargin_right' => 'numeric|nullable',
'labels_pmargin_top' => 'numeric|nullable',
'labels_pmargin_bottom' => 'numeric|nullable',
'labels_display_bgutter' => 'numeric|nullable',
'labels_display_sgutter' => 'numeric|nullable',
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'qr_text' => 'max:31|nullable',
];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLdapSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'ldap_username_field' => 'not_in:sAMAccountName|required_if:ldap_enabled,1',
'ldap_auth_filter_query' => 'not_in:uid=samaccountname|required_if:ldap_enabled,1',
'ldap_filter' => 'nullable|regex:"^[^(]"|required_if:ldap_enabled,1',
'ldap_server' => 'nullable|required_if:ldap_enabled,1|starts_with:ldap://,ldaps://',
'ldap_uname' => 'nullable|required_if:ldap_enabled,1',
'ldap_pword' => 'nullable|required_if:ldap_enabled,1',
'ldap_basedn' => 'nullable|required_if:ldap_enabled,1',
'ldap_fname_field' => 'nullable|required_if:ldap_enabled,1',
'custom_forgot_pass_url' => 'nullable|url',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLocalizationSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'default_currency' => 'required',
'locale' => 'required',
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests;
use App\Models\Accessory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreNotificationSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email|nullable',
'alert_threshold' => 'numeric|nullable|gt:0',
'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable|gt:0',
'due_checkin_days' => 'numeric|nullable|gt:0',
'audit_interval' => 'numeric|nullable|gt:0',
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreSecuritySettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'pwd_secure_min' => 'numeric|required|min:8',
'custom_forgot_pass_url' => 'url|nullable',
'privacy_policy_link' => 'nullable|url',
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'login_remote_user_header_name' => 'string|nullable',
];
}
}

View File

@@ -23,7 +23,7 @@ trait MayContainCustomFields
return str_starts_with($attributes, '_snipeit_');
});
// if there are custom fields, find the one's that don't exist on the model's fieldset and add an error to the validator's error bag
if (count($request_fields) > 0) {
if (count($request_fields) > 0 && $validator->errors()->isEmpty()) {
$request_fields->diff($asset_model?->fieldset?->fields?->pluck('db_column'))
->each(function ($request_field_name) use ($request_fields, $validator) {
if (CustomField::where('db_column', $request_field_name)->exists()) {

View File

@@ -4,6 +4,7 @@ namespace App\Http\Requests;
use App\Http\Requests\Traits\MayContainCustomFields;
use App\Models\Asset;
use App\Models\Setting;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
@@ -41,6 +42,12 @@ class UpdateAssetRequest extends ImageUploadRequest
],
);
// if the purchase cost is passed in as a string **and** the digit_separator is ',' (as is common in the EU)
// then we tweak the purchase_cost rule to make it a string
if (Setting::getSettings()->digit_separator === '1.234,56' && is_string($this->input('purchase_cost'))) {
$rules['purchase_cost'] = ['nullable', 'string'];
}
return $rules;
}
}

View File

@@ -11,15 +11,17 @@ trait TwoColumnUniqueUndeletedTrait
* @param string $field
* @return string
*/
protected function prepareTwoColumnUniqueUndeletedRule($parameters, $field)
protected function prepareTwoColumnUniqueUndeletedRule($parameters)
{
$column = $parameters[0];
$value = $this->{$parameters[0]};
// This is an existing model we're updating so ignore the current ID ($this->getKey())
if ($this->exists) {
return 'two_column_unique_undeleted:'.$this->table.','.$this->getKey().','.$column.','.$value;
}
// This is a new record, so we can ignore the current ID
return 'two_column_unique_undeleted:'.$this->table.',0,'.$column.','.$value;
}
}

View File

@@ -38,9 +38,12 @@ class AccessoriesTransformer
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => (int) $accessory->numRemaining(),
'remaining_qty' => (int) ($accessory->qty - $accessory->checkouts_count),
'checkouts_count' => $accessory->checkouts_count,
'created_by' => ($accessory->adminuser) ? [
'id' => (int) $accessory->adminuser->id,
'name'=> e($accessory->adminuser->present()->fullName()),
] : null,
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
@@ -57,7 +60,7 @@ class AccessoriesTransformer
$permissions_array['user_can_checkout'] = false;
if ($accessory->numRemaining() > 0) {
if (($accessory->qty - $accessory->checkouts_count) > 0) {
$permissions_array['user_can_checkout'] = true;
}

View File

@@ -141,6 +141,8 @@ class ActionlogsTransformer
if ($actionlog->item) {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'accessory') {
$file_url = route('show.accessoryfile', ['accessoryId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'license') {
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'user') {
@@ -158,7 +160,6 @@ class ActionlogsTransformer
[
'url' => $file_url,
'filename' => $actionlog->filename,
'inlineable' => (bool) Helper::show_file_inline($actionlog->filename),
] : null,
'item' => ($actionlog->item) ? [
@@ -176,11 +177,17 @@ class ActionlogsTransformer
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date'): null,
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
'action_type' => $actionlog->present()->actionType(),
'admin' => ($actionlog->admin) ? [
'id' => (int) $actionlog->admin->id,
'name' => e($actionlog->admin->getFullNameAttribute()),
'first_name'=> e($actionlog->admin->first_name),
'last_name'=> e($actionlog->admin->last_name)
'admin' => ($actionlog->adminuser) ? [
'id' => (int) $actionlog->adminuser->id,
'name' => e($actionlog->adminuser->getFullNameAttribute()),
'first_name'=> e($actionlog->adminuser->first_name),
'last_name'=> e($actionlog->adminuser->last_name)
] : null,
'created_by' => ($actionlog->adminuser) ? [
'id' => (int) $actionlog->adminuser->id,
'name' => e($actionlog->adminuser->getFullNameAttribute()),
'first_name'=> e($actionlog->adminuser->first_name),
'last_name'=> e($actionlog->adminuser->last_name)
] : null,
'target' => ($actionlog->target) ? [
'id' => (int) $actionlog->target->id,
@@ -340,4 +347,4 @@ class ActionlogsTransformer
}
}

View File

@@ -39,7 +39,7 @@ class AssetMaintenancesTransformer
'status_label' => ($assetmaintenance->asset->assetstatus) ? [
'id' => (int) $assetmaintenance->asset->assetstatus->id,
'name'=> e($assetmaintenance->asset->assetstatus->name),
'status_type'=> e($assetmaintenance->asset->assetstatus->getStatuslabelType()),
'status_type'=> e($assetmaintenance->asset->assetstatus->status_type),
'status_meta' => e($assetmaintenance->asset->present()->statusMeta),
] : null,
'company' => (($assetmaintenance->asset) && ($assetmaintenance->asset->company)) ? [
@@ -64,7 +64,14 @@ class AssetMaintenancesTransformer
'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'),
'asset_maintenance_time' => $assetmaintenance->asset_maintenance_time,
'completion_date' => Helper::getFormattedDateObject($assetmaintenance->completion_date, 'date'),
'user_id' => ($assetmaintenance->admin) ? ['id' => $assetmaintenance->admin->id, 'name'=> e($assetmaintenance->admin->getFullNameAttribute())] : null,
'user_id' => ($assetmaintenance->adminuser) ? [
'id' => $assetmaintenance->adminuser->id,
'name'=> e($assetmaintenance->adminuser->present()->fullName())
] : null, // legacy to not change the shape of the API
'created_by' => ($assetmaintenance->adminuser) ? [
'id' => (int) $assetmaintenance->adminuser->id,
'name'=> e($assetmaintenance->adminuser->present()->fullName()),
] : null,
'created_at' => Helper::getFormattedDateObject($assetmaintenance->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($assetmaintenance->updated_at, 'datetime'),
'is_warranty'=> $assetmaintenance->is_warranty,

View File

@@ -8,7 +8,6 @@ use App\Models\Setting;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
class AssetsTransformer
{
@@ -45,8 +44,8 @@ class AssetsTransformer
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name),
'status_type'=> e($asset->assetstatus->getStatuslabelType()),
'status_meta' => e($asset->present()->statusMeta),
'status_type'=> e($asset->assetstatus->status_type),
'status_meta' => e($asset->assetstatus->status_type),
] : null,
'category' => (($asset->model) && ($asset->model->category)) ? [
'id' => (int) $asset->model->category->id,
@@ -80,13 +79,17 @@ class AssetsTransformer
'assigned_to' => $this->transformAssignedTo($asset),
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'created_by' => ($asset->adminuser) ? [
'id' => (int) $asset->adminuser->id,
'name'=> e($asset->adminuser->present()->fullName()),
] : null,
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($asset->updated_at, 'datetime'),
'last_audit_date' => Helper::getFormattedDateObject($asset->last_audit_date, 'datetime'),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date, 'date'),
'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'),
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
'age' => $asset->purchase_date ? $asset->purchase_date->diffForHumans() : '',
'age' => $asset->purchase_date ? $asset->purchase_date->locale(app()->getLocale())->diffForHumans() : '',
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
'last_checkin' => Helper::getFormattedDateObject($asset->last_checkin, 'datetime'),
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),

View File

@@ -62,6 +62,10 @@ class CategoriesTransformer
'consumables_count' => (int) $category->consumables_count,
'components_count' => (int) $category->components_count,
'licenses_count' => (int) $category->licenses_count,
'created_by' => ($category->adminuser) ? [
'id' => (int) $category->adminuser->id,
'name'=> e($category->adminuser->present()->fullName()),
] : null,
'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'),
];

View File

@@ -30,14 +30,18 @@ class CompaniesTransformer
'fax' => ($company->fax!='') ? e($company->fax): null,
'email' => ($company->email!='') ? e($company->email): null,
'image' => ($company->image) ? Storage::disk('public')->url('companies/'.e($company->image)) : null,
'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
'assets_count' => (int) $company->assets_count,
'licenses_count' => (int) $company->licenses_count,
'accessories_count' => (int) $company->accessories_count,
'consumables_count' => (int) $company->consumables_count,
'components_count' => (int) $company->components_count,
'users_count' => (int) $company->users_count,
'created_by' => ($company->adminuser) ? [
'id' => (int) $company->adminuser->id,
'name'=> e($company->adminuser->present()->fullName()),
] : null,
'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
];
$permissions_array['available_actions'] = [

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