Compare commits

...

119 Commits

Author SHA1 Message Date
snipe
93014d7f34 Better handle backups in S3
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 14:58:32 +00:00
snipe
759e3794df Small upgrader UI fixes
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 14:57:28 +00:00
snipe
c50b14763f Merge pull request #16403 from snipe/#16402_each_localization
Fixed #16402 - localize "each" string in components tab on asset view
2025-03-04 13:35:08 +00:00
snipe
369a68fe57 Fixed #16402 - Localize “each” in string
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 13:33:04 +00:00
snipe
83855d44d0 Merge pull request #16251 from Godmartinz/Audit_Checkin_warning_fix
refactors audit notification to mail, adds test, adds  alerts check to scheduler
2025-03-04 12:51:42 +00:00
snipe
6f847294ed Merge pull request #15911 from Fiala06/patch-1
Fixed duplicate entries preventing LDAP sync from continuing
2025-03-04 12:49:54 +00:00
snipe
d556d1c6e7 Merge pull request #16150 from Godmartinz/add-translations-to-settings
Adds Translation strings to General and Branding Settings
2025-03-04 12:48:21 +00:00
snipe
3bb94e98f0 Merge pull request #16398 from marcusmoore/bug/sc-28535
Avoid using authenticated user's email address in email partial
2025-03-04 12:47:10 +00:00
Marcus Moore
8f5f6f3502 Avoid using authenticated user's email address in email partial 2025-03-03 16:28:08 -08:00
snipe
b3792bfa00 Merge pull request #16396 from marcusmoore/chore/migrate-checkbox-helpers-pt10
Replace calls to Form::checkbox pt10
2025-03-03 20:52:54 +00:00
Marcus Moore
40f7257723 Replace call to Form::checkbox 2025-03-03 12:44:50 -08:00
snipe
8486256142 Merge pull request #16381 from marcusmoore/chore/migrate-checkbox-helpers-pt9
Replace calls to Form::checkbox pt9
2025-03-03 20:28:21 +00:00
snipe
7f36750e33 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2025-03-03 19:54:14 +00:00
snipe
de046db106 Add @azmcnutt as a contributor 2025-03-03 19:53:30 +00:00
snipe
eb1d27a5bc Merge pull request #16379 from azmcnutt/feature/settings_ldap_invert_active_flag
Feature/settings ldap invert active flag
2025-03-03 19:52:57 +00:00
Godfrey M
cc0b9f404a merged develop, fix conflicts 2025-02-27 15:38:31 -08:00
Marcus Moore
70332696c6 Fix test by passing in required properties 2025-02-27 15:23:17 -08:00
Marcus Moore
7a9b5d61b0 Replace another Form::checkbox 2025-02-27 13:25:32 -08:00
Marcus Moore
5876259893 Replace another Form::checkbox 2025-02-27 13:19:26 -08:00
Marcus Moore
8755c54edc Replace Form::checkbox 2025-02-27 13:13:39 -08:00
Marcus Moore
014f3b7652 Cast to boolean 2025-02-27 13:12:01 -08:00
Marcus Moore
3a2579b205 WIP: replace Form::checkbox 2025-02-27 13:08:02 -08:00
James M
149474bfe3 Update general.php
FIX: Spelling error
2025-02-27 12:42:47 -07:00
James M
b2b768dede Merge branch 'snipe:develop' into develop 2025-02-27 12:25:07 -07:00
snipe
a9ed9e2a7f Merge pull request #16378 from snipe/wrap_pdf_table_results
Wrap long text in PDF export in tables
2025-02-27 19:06:34 +00:00
snipe
ce8523b00a Fixed wrapping
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 18:58:18 +00:00
snipe
7076a68d35 Wrap table results in PDF
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 18:38:10 +00:00
James M
112112d258 Feat: #14926 LDAP Active Flag - Add config option to make False = Enable 2025-02-27 10:52:12 -07:00
snipe
3928c8afe9 Merge pull request #16376 from uberbrady/improve_safety_csv_charset_detection
Add some safeties around the charset-detection and transliteration
2025-02-27 16:26:44 +00:00
snipe
23ce54e80c Make sure we’re saving the last_login in 2FA auths
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 16:17:59 +00:00
Brady Wetherington
646e3e8df5 Complete failed-transliteration test, clean up error, new translation string 2025-02-27 16:10:56 +00:00
snipe
30c4e9dbf7 Use formatter for created_at on unaccepted assets
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 15:48:24 +00:00
snipe
27fc30a881 Nicer button layout on unaccepted assets
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 15:43:53 +00:00
snipe
8ac7cda4ee Merge pull request #16366 from marcusmoore/chore/migrate-checkbox-helpers-pt7
Replace calls to Form::checkbox pt7
2025-02-27 15:01:31 +00:00
snipe
6f04d314a8 Merge pull request #16367 from marcusmoore/chore/migrate-checkbox-helpers-pt8
Replace calls to Form::checkbox pt8
2025-02-27 15:01:19 +00:00
snipe
1051b1d16d Merge pull request #16375 from snipe/fixes_16371_name_not_included_in_reminder_emails
Fixed #16371 - incorrect count and missing name in acceptance reminder email
2025-02-27 15:00:04 +00:00
snipe
115bb94704 Merge pull request #16156 from marcusmoore/acceptance-reminder-subject
Added "Reminder" to subject line of follow up asset checkout emails
2025-02-27 14:55:59 +00:00
snipe
25807cc62f Fixed constructor
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 14:22:48 +00:00
snipe
cd1d1b2d3e Fixed count
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 14:22:40 +00:00
Brady Wetherington
6dcd3bfd30 Add some safeties around the charset-detection and transliteration 2025-02-27 13:44:31 +00:00
snipe
b8799f8038 Bumped bash
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 12:21:28 +00:00
Marcus Moore
a0dc056da8 Replace Form::checkbox on label settings page 2025-02-26 16:33:07 -08:00
Marcus Moore
27aeb518ff Replace Form::checkbox on general settings page 2025-02-26 16:18:00 -08:00
snipe
dc619bb0dc Merge pull request #16365 from marcusmoore/chore/migrate-checkbox-helpers-pt6
Replace calls to Form::checkbox pt6
2025-02-26 23:54:50 +00:00
Marcus Moore
245a16c377 Replace Form::checkbox on branding settings page 2025-02-26 15:37:07 -08:00
Marcus Moore
de3c1d159f Replace Form::checkbox on branding settings page 2025-02-26 15:35:17 -08:00
Marcus Moore
af6d9e4a00 Replace Form::checkbox on custom report pages 2025-02-26 15:15:48 -08:00
snipe
8c8af3062e Merge pull request #16354 from snipe/dont_checkin_for_pending_on_asset_update
Allow pending as an asset status type that does not automatically check the asset in
2025-02-26 21:05:11 +00:00
snipe
2ff47edb94 Merge pull request #16361 from Godmartinz/acceptancer_reminder_unlisted_email_info
Fixed acceptance reminder command lag on users with no associated email
2025-02-26 20:33:02 +00:00
snipe
d923d29bad Merge pull request #16360 from spencerrlongg/bug/sc-28537
Add Safety Around Bulk Status Update
2025-02-26 20:32:19 +00:00
Godfrey M
899119ae2d changes output to a table 2025-02-26 12:30:19 -08:00
snipe
e031de8e49 Merge pull request #16363 from snipe/added_a_few_more_no_interaction_calls
Added `--no-interaction` to additional passport commands
2025-02-26 20:19:37 +00:00
snipe
a81c520d93 Follow up for #16341
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 20:15:09 +00:00
Godfrey M
8352e81228 fix unaccepted reminder test 2025-02-26 11:50:08 -08:00
Godfrey M
fd0174ff32 remove unwanted changes to livewire 2025-02-26 11:31:41 -08:00
Godfrey M
cc26aa02b2 fix acceptance reminder command no email list 2025-02-26 11:25:21 -08:00
snipe
616f3558dd Update example env
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 19:14:25 +00:00
spencerrlongg
d6e266cec1 make super safe 2025-02-26 13:11:49 -06:00
snipe
31516d7f24 Merge pull request #16356 from snipe/added_fields_for_model_search
Added name, model_number and notes for strict search
2025-02-26 12:46:13 +00:00
snipe
e79af255aa Added name, model_number and notes for strict search
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 12:43:54 +00:00
snipe
5b0d7f4064 One more chonk
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 12:01:50 +00:00
snipe
2f6af10c5d Bumped chunk for custom report
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 11:59:34 +00:00
snipe
afabda9235 Remove greater than 0 for alert threshold - fixes FD-47040
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 11:38:33 +00:00
snipe
1618c9ae8e Changed confirmation message
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:53:41 +00:00
snipe
5344ef4a1a Allow pending as an asset status that does not automatically check the asset in
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:46:38 +00:00
snipe
16420b1e00 Audit Log Number under Days to next Audit [sc-28530]
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:25:07 +00:00
snipe
62f66e724e Drop errors to warnings to stop pooping on rollbar
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 09:54:13 +00:00
snipe
9b0ea51d35 Moved composer clear commands to after composer install per #16334
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 09:37:31 +00:00
snipe
992214fc66 Check for adminuser withTrashed
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 08:25:22 +00:00
snipe
93dab12461 Merge pull request #16342 from snipe/nicer_upgrade_script
Nicer upgrade.php UI
2025-02-26 07:16:28 +00:00
snipe
ea0f105180 Merge pull request #16347 from marcusmoore/chore/migrate-checkbox-helpers-pt4
Replace calls to Form::checkbox pt4
2025-02-26 07:05:38 +00:00
snipe
5b6da0c1e8 Merge pull request #16348 from marcusmoore/chore/migrate-checkbox-helpers-pt5
Replace calls to Form::checkbox pt5
2025-02-26 07:05:22 +00:00
snipe
4d7655bbe1 Merge pull request #16346 from marcusmoore/chore/migrate-checkbox-helpers-pt3
Replace calls to Form::checkbox pt3
2025-02-26 07:04:27 +00:00
snipe
5e3855ee5b Merge pull request #16345 from marcusmoore/fixes/update-custom-fields
Fixed renaming custom fields
2025-02-26 07:03:40 +00:00
Marcus Moore
e01226a174 Replace Form::checkbox on saml settings page 2025-02-25 17:31:05 -08:00
Marcus Moore
f9ccf32af4 Replace Form::checkbox on ldap settings page 2025-02-25 17:22:44 -08:00
Marcus Moore
2c5170a218 Replace Form::checkbox on security settings page 2025-02-25 17:09:25 -08:00
Marcus Moore
15f842e2dc Replace Form::checkbox on bulk user edit page 2025-02-25 16:00:46 -08:00
Marcus Moore
46b31dfe14 Replace Form::checkbox on user create and edit page 2025-02-25 14:32:39 -08:00
Marcus Moore
d88c79366c Replace Form::checkbox on google settings page 2025-02-25 14:27:07 -08:00
Marcus Moore
de330a47cd Replace Form::checkbox on asset tag settings page 2025-02-25 14:25:02 -08:00
Marcus Moore
ecd7dc2094 Replace Form::checkbox on alert settings page 2025-02-25 14:23:26 -08:00
Marcus Moore
510946e0eb Replace Form::checkbox in logo upload partial 2025-02-25 14:20:43 -08:00
Marcus Moore
37e4a13979 Replace Form::checkbox in image upload partial 2025-02-25 14:15:12 -08:00
Marcus Moore
c73d64cdbc Remove manual doctrine mapping for enums 2025-02-25 13:37:23 -08:00
snipe
4a0410d969 Uncomment git stash
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:55:39 +00:00
snipe
668b9f8fb9 Nicer upgrade.php UI
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:51:32 +00:00
snipe
037d2d9e84 Merge pull request #16341 from uberbrady/fix_passport_install_no_interaction
Fixes #16331 - Don't make passport:install command require user input
2025-02-25 16:43:49 +00:00
Brady Wetherington
bce2007b97 Fixes #16331 - Don't make passport:install command require user input 2025-02-25 16:38:40 +00:00
Brady Wetherington
09a5e5b1bd Whoops! Need minimum 8.2, not 8.1 (probably mis-merge?) 2025-02-25 14:40:45 +00:00
snipe
7b4f4b6b7f Merge pull request #16337 from joakimbergros/develop
Fixed #16173: `useraccountcontrol` was not included in the ldap query attributes
2025-02-25 13:49:38 +00:00
Joakim Bergros
5c66334017 Added a check to see if the user has specified that is an ActiveDirectory server in the configuration before adding the useraccountcontrol attribute to the ldap query. 2025-02-25 14:22:22 +01:00
Joakim Bergros
ae82051b73 Fixed #16173: useraccountcontrol was not included in the ldap query attributes.
`$results` did not include the `useraccountcontrol` and thus rendered the fallback logic void when `active_flag` was blank.

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

[`elseif' will become true when `active_flag` is blank](b141945add/app/Console/Commands/LdapSync.php (L364))
2025-02-25 13:55:53 +01:00
Marcus Moore
e88bba51bb Merge branch 'develop' into acceptance-reminder-subject 2025-02-24 11:55:50 -08:00
Marcus Moore
f97211f6cd Remove unused language string 2025-02-24 11:45:58 -08:00
Marcus Moore
027c2b3627 Change subject to "You have Unaccepted Assets." 2025-02-24 11:45:23 -08:00
Godfrey M
4c43a06eee add overdue asset to test 2025-02-13 11:19:49 -08:00
Godfrey M
25c8449e86 remove unused 2025-02-13 11:14:18 -08:00
Godfrey M
13e1f4a127 adds mailable 2025-02-13 11:09:39 -08:00
Godfrey M
ed96fd766c refactors audit notification to mail, adds test, ads check to scheduler 2025-02-13 11:08:53 -08:00
Marcus Moore
7cbb3f7e07 Add assertion 2025-01-30 11:48:55 -08:00
Marcus Moore
7e9c564d0b Simplify test 2025-01-30 11:47:43 -08:00
Marcus Moore
fc88b2487f Extract method 2025-01-30 11:44:37 -08:00
Marcus Moore
e94ee48f74 Extract helper 2025-01-30 10:37:11 -08:00
Marcus Moore
6a4a5d1380 Add translation 2025-01-30 10:35:31 -08:00
Marcus Moore
ab9e9b66d2 Reduce complexity 2025-01-29 16:27:18 -08:00
Marcus Moore
c15c338ffd Merge if/else 2025-01-29 16:25:37 -08:00
Marcus Moore
d1197d015c Add another case scenario 2025-01-29 16:24:43 -08:00
Marcus Moore
ce31ce477e Inline additional variables 2025-01-29 16:16:47 -08:00
Marcus Moore
78f9292555 Inline variable 2025-01-29 16:15:27 -08:00
Marcus Moore
4e7c6bd2cf Fix relationship 2025-01-29 16:14:09 -08:00
Marcus Moore
70aed45bfe Improve naming 2025-01-29 15:56:20 -08:00
Marcus Moore
e2805f4033 Add "Reminder" to subject line 2025-01-29 15:36:45 -08:00
Marcus Moore
d254a40e0a Scaffold tests 2025-01-29 15:21:10 -08:00
Marcus Moore
fdcb891cbb Improve test case 2025-01-29 15:20:56 -08:00
Godfrey M
16d322d70e fix translation 2025-01-29 10:38:30 -08:00
Godfrey M
2163312997 adds translations for branding and general settings 2025-01-29 10:35:26 -08:00
Godfrey M
0dfb71cfe5 added some translations to branding and general setrting 2025-01-28 11:56:10 -08:00
Fiala06
bdb0e6c2a3 Update LdapSync.php
Fix for duplicate entries preventing the sync from continuing. 

  SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '13178-6' for key 'PRIMARY' (Connection: mysql, SQL: insert into users_groups (group_id, user_id) values (6, 13178))
2024-12-02 11:07:37 -08:00
70 changed files with 839 additions and 340 deletions

View File

@@ -3289,6 +3289,15 @@
"contributions": [ "contributions": [
"code" "code"
] ]
},
{
"login": "azmcnutt",
"name": "James M",
"avatar_url": "https://avatars.githubusercontent.com/u/31522486?v=4",
"profile": "https://github.com/azmcnutt",
"contributions": [
"code"
]
} }
] ]
} }

View File

@@ -99,7 +99,7 @@ PASSPORT_COOKIE_NAME='snipeit_passport_token'
COOKIE_DOMAIN=null COOKIE_DOMAIN=null
SECURE_COOKIES=false SECURE_COOKIES=false
API_TOKEN_EXPIRATION_YEARS=15 API_TOKEN_EXPIRATION_YEARS=15
BS_TABLE_STORAGE=cookieStorage BS_TABLE_STORAGE=localStorage
BS_TABLE_DEEPLINK=true BS_TABLE_DEEPLINK=true
# -------------------------------------------- # --------------------------------------------

View File

@@ -67,7 +67,7 @@ jobs:
run: | run: |
php artisan key:generate php artisan key:generate
php artisan migrate --force php artisan migrate --force
php artisan passport:install php artisan passport:install --no-interaction
chmod -R 777 storage bootstrap/cache chmod -R 777 storage bootstrap/cache
- name: Execute tests (Unit and Feature tests) via PHPUnit - name: Execute tests (Unit and Feature tests) via PHPUnit

View File

@@ -65,7 +65,7 @@ jobs:
run: | run: |
php artisan key:generate php artisan key:generate
php artisan migrate --force php artisan migrate --force
php artisan passport:install php artisan passport:install --no-interaction
chmod -R 777 storage bootstrap/cache chmod -R 777 storage bootstrap/cache
- name: Execute tests (Unit and Feature tests) via PHPUnit - name: Execute tests (Unit and Feature tests) via PHPUnit

View File

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

View File

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

View File

@@ -125,6 +125,10 @@ class LdapSync extends Command
*/ */
$attributes = array_values(array_filter($ldap_map)); $attributes = array_values(array_filter($ldap_map));
if (Setting::getSettings()->is_ad === 1 && is_null($ldap_map['active_flag'])) {
$attributes[] = 'useraccountcontrol';
}
$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes); $results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -357,9 +361,15 @@ class LdapSync extends Command
// (Specifically, we don't handle a value of '0.0' correctly) // (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_map["active_flag"]][0]; $raw_value = @$results[$i][$ldap_map["active_flag"]][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); $filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool) $raw_value; $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 if (Setting::getSettings()->ldap_invert_active_flag === 1) {
// Because ldap_active_flag is set, if filter_var is true or boolean_cast is true, then user is suspended
$user->activated = !($filter_var ?? $boolean_cast);
}else{
$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])) { } elseif (array_key_exists('useraccountcontrol', $results[$i])) {
// ....otherwise, (ie if no 'active' LDAP flag is defined), IF the UAC setting exists, // ....otherwise, (ie if no 'active' LDAP flag is defined), IF the UAC setting exists,
@@ -424,8 +434,12 @@ class LdapSync extends Command
$item['note'] = $item['createorupdate']; $item['note'] = $item['createorupdate'];
$item['status'] = 'success'; $item['status'] = 'success';
if ($item['createorupdate'] === 'created' && $ldap_default_group) { if ($item['createorupdate'] === 'created' && $ldap_default_group) {
$user->groups()->attach($ldap_default_group); // Check if the relationship already exists
if (!$user->groups()->where('group_id', $ldap_default_group)->exists()) {
$user->groups()->attach($ldap_default_group);
}
} }
//updates assets location based on user's location //updates assets location based on user's location
if ($user->wasChanged('location_id')) { if ($user->wasChanged('location_id')) {
foreach ($user->assets as $asset) { foreach ($user->assets as $asset) {

View File

@@ -64,28 +64,43 @@ class SendAcceptanceReminder extends Command
->groupBy(function($item) { ->groupBy(function($item) {
return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : ''; return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : '';
}); });
$no_email_list= [];
foreach($unacceptedAssetGroups as $unacceptedAssetGroup) { foreach($unacceptedAssetGroups as $unacceptedAssetGroup) {
// The [0] is weird, but it allows for the item_count to work and grabs the appropriate info for each user. // The [0] is weird, but it allows for the item_count to work and grabs the appropriate info for each user.
// Collapsing and flattening the collection doesn't work above. // Collapsing and flattening the collection doesn't work above.
$acceptance = $unacceptedAssetGroup[0]['acceptance']; $acceptance = $unacceptedAssetGroup[0]['acceptance'];
$locale = $acceptance->assignedTo?->locale; $locale = $acceptance->assignedTo?->locale;
$email = $acceptance->assignedTo?->email; $email = $acceptance->assignedTo?->email;
if(!$email){ if(!$email){
$this->info($acceptance->assignedTo?->present()->fullName().' has no email address.'); $no_email_list[] = [
'id' => $acceptance->assignedTo?->id,
'name' => $acceptance->assignedTo?->present()->fullName(),
];
} else {
$count++;
} }
$item_count = $unacceptedAssetGroup->count(); $item_count = $unacceptedAssetGroup->count();
if ($locale && $email) { if ($locale && $email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count))->locale($locale)); Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count))->locale($locale));
} elseif ($email) { } elseif ($email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count))); Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count)));
} }
$count++;
} }
$this->info($count.' users notified.'); $this->info($count.' users notified.');
$headers = ['ID', 'Name'];
$rows = [];
foreach ($no_email_list as $user) {
$rows[] = [$user['id'], $user['name']];
}
$this->info("The following users do not have an email address:");
$this->table($headers, $rows);
return 0; return 0;
} }

View File

@@ -2,13 +2,12 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Mail\SendUpcomingAuditMail;
use App\Models\Asset; use App\Models\Asset;
use App\Models\Recipients\AlertRecipient;
use App\Models\Setting; use App\Models\Setting;
use App\Notifications\SendUpcomingAuditNotification;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendUpcomingAuditReport extends Command class SendUpcomingAuditReport extends Command
{ {
@@ -48,19 +47,19 @@ class SendUpcomingAuditReport extends Command
$today = Carbon::now(); $today = Carbon::now();
$interval_date = $today->copy()->addDays($interval); $interval_date = $today->copy()->addDays($interval);
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get(); $assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
$this->info($assets->count().' assets must be audited in on or before '.$interval_date.' is deadline'); $this->info($assets->count() . ' assets must be audited in on or before ' . $interval_date . ' is deadline');
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) { if ((count($assets) !== 0) && ($assets->count() > 0) && ($settings->alert_email != '')) {
// Send a rollup to the admin, if settings dictate // Send a rollup to the admin, if settings dictate
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) { $recipients = collect(explode(',', $settings->alert_email))
return new AlertRecipient($item); ->map(fn($item) => trim($item))
}); ->all();
$this->info('Sending Admin SendUpcomingAuditNotification to: '.$settings->alert_email);
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
$this->info('Sending Admin SendUpcomingAuditNotification to: ' . $settings->alert_email);
Mail::to($recipients)->send(new SendUpcomingAuditMail($assets, $settings->audit_warning_days));
} }
} }

View File

@@ -5,6 +5,7 @@ namespace App\Console;
use App\Console\Commands\ImportLocations; use App\Console\Commands\ImportLocations;
use App\Console\Commands\ReEncodeCustomFieldNames; use App\Console\Commands\ReEncodeCustomFieldNames;
use App\Console\Commands\RestoreDeletedUsers; use App\Console\Commands\RestoreDeletedUsers;
use App\Models\Setting;
use Illuminate\Console\Scheduling\Schedule; use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -18,12 +19,14 @@ class Kernel extends ConsoleKernel
*/ */
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)
{ {
$schedule->command('snipeit:inventory-alerts')->daily(); if(Setting::getSettings()->alerts_enabled === 1) {
$schedule->command('snipeit:expiring-alerts')->daily(); $schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily(); $schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
}
$schedule->command('snipeit:backup')->weekly(); $schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily(); $schedule->command('backup:clean')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
$schedule->command('auth:clear-resets')->everyFifteenMinutes(); $schedule->command('auth:clear-resets')->everyFifteenMinutes();
$schedule->command('saml:clear_expired_nonces')->weekly(); $schedule->command('saml:clear_expired_nonces')->weekly();
} }

View File

@@ -77,6 +77,18 @@ class AssetModelsController extends Controller
$assetmodels->onlyTrashed(); $assetmodels->onlyTrashed();
} }
if ($request->filled('name')) {
$assetmodels = $assetmodels->where('models.name', '=', $request->input('name'));
}
if ($request->filled('model_number')) {
$assetmodels = $assetmodels->where('models.model_number', '=', $request->input('model_number'));
}
if ($request->filled('notes')) {
$assetmodels = $assetmodels->where('models.notes', '=', $request->input('notes'));
}
if ($request->filled('category_id')) { if ($request->filled('category_id')) {
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id')); $assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
} }

View File

@@ -66,25 +66,41 @@ class ImportController extends Controller
if (! ini_get('auto_detect_line_endings')) { if (! ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1'); ini_set('auto_detect_line_endings', '1');
} }
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it? if (function_exists('iconv')) {
$encoding = $detector->getEncoding($file_contents); $file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
$reader = null; $encoding = $detector->getEncoding($file_contents);
if (strcasecmp($encoding, 'UTF-8') != 0) { \Log::warning("Discovered encoding: $encoding in uploaded CSV");
$transliterated = iconv($encoding, 'UTF-8', $file_contents); $reader = null;
if ($transliterated !== false) { if (strcasecmp($encoding, 'UTF-8') != 0) {
$tmpname = tempnam(sys_get_temp_dir(), ''); $transliterated = false;
$tmpresults = file_put_contents($tmpname, $transliterated); try {
if ($tmpresults !== false) { $transliterated = iconv(strtoupper($encoding), 'UTF-8', $file_contents);
} catch (\Exception $e) {
$transliterated = false; //blank out the partially-decoded string
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.transliterate_failure', ["encoding" => $encoding])
),
422
);
}
if ($transliterated !== false) {
$tmpname = tempnam(sys_get_temp_dir(), '');
$tmpresults = file_put_contents($tmpname, $transliterated);
$transliterated = null; //save on memory? $transliterated = null; //save on memory?
$newfile = new UploadedFile($tmpname, $file->getClientOriginalName(), null, null, true); //WARNING: this is enabling 'test mode' - which is gross, but otherwise the file won't be treated as 'uploaded' if ($tmpresults !== false) {
if ($newfile->isValid()) { $newfile = new UploadedFile($tmpname, $file->getClientOriginalName(), null, null, true); //WARNING: this is enabling 'test mode' - which is gross, but otherwise the file won't be treated as 'uploaded'
$file = $newfile; if ($newfile->isValid()) {
$file = $newfile;
}
} }
} }
} }
$file_contents = null; //try to save on memory, I guess?
} }
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak? $reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$file_contents = null; //try to save on memory, I guess?
try { try {
$import->header_row = $reader->fetchOne(0); $import->header_row = $reader->fetchOne(0);

View File

@@ -290,10 +290,12 @@ class StatuslabelsController extends Controller
/** /**
* Returns a boolean response based on whether the status label * Returns a boolean response based on whether the status label
* is one that is deployable. * is one that is deployable or pending.
* *
* This is used by the hardware create/edit view to determine whether * This is used by the hardware create/edit view to determine whether
* we should provide a dropdown of users for them to check the asset out to. * we should provide a dropdown of users for them to check the asset out to,
* and whether we show a warning that the asset will be checked in if it's already
* assigned but the status is changed to one that isn't pending or deployable
* *
* @author [A. Gianotto] [<snipe@snipe.net>] * @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0] * @since [v4.0]
@@ -301,7 +303,7 @@ class StatuslabelsController extends Controller
public function checkIfDeployable($id) : string public function checkIfDeployable($id) : string
{ {
$statuslabel = Statuslabel::findOrFail($id); $statuslabel = Statuslabel::findOrFail($id);
if ($statuslabel->getStatuslabelType() == 'deployable') { if (($statuslabel->getStatuslabelType() == 'pending') || ($statuslabel->getStatuslabelType() == 'deployable')) {
return '1'; return '1';
} }

View File

@@ -340,15 +340,14 @@ class AssetsController extends Controller
$status = Statuslabel::find($request->input('status_id')); $status = Statuslabel::find($request->input('status_id'));
// This is a non-deployable status label - we should check the asset back in. // This is an archived or undeployable - we should check the asset back in.
if (($status && $status->getStatuslabelType() != 'deployable') && ($target = $asset->assignedTo)) { // Pending is allowed here
if (($status) && (($status->getStatuslabelType() != 'pending') && ($status->getStatuslabelType() != 'deployable')) && ($target = $asset->assignedTo)) {
$originalValues = $asset->getRawOriginal(); $originalValues = $asset->getRawOriginal();
$asset->assigned_to = null; $asset->assigned_to = null;
$asset->assigned_type = null; $asset->assigned_type = null;
$asset->accepted = null; $asset->accepted = null;
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues));
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update', date('Y-m-d H:i:s'), $originalValues));
} }
if ($asset->assigned_to == '') { if ($asset->assigned_to == '') {

View File

@@ -358,7 +358,11 @@ class BulkAssetsController extends Controller
* to someone/something. * to someone/something.
*/ */
if ($request->filled('status_id')) { if ($request->filled('status_id')) {
$updated_status = Statuslabel::find($request->input('status_id')); try {
$updated_status = Statuslabel::findOrFail($request->input('status_id'));
} catch (ModelNotFoundException $e) {
return redirect($bulk_back_url)->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
// We cannot assign a non-deployable status type if the asset is already assigned. // We cannot assign a non-deployable status type if the asset is already assigned.
// This could probably be added to a form request. // This could probably be added to a form request.
@@ -366,7 +370,7 @@ class BulkAssetsController extends Controller
// Otherwise we need to make sure the status type is still a deployable one. // Otherwise we need to make sure the status type is still a deployable one.
if ( if (
($asset->assigned_to == '') ($asset->assigned_to == '')
|| ($updated_status->deployable == '1') && ($asset->assetstatus->deployable == '1') || ($updated_status->deployable == '1') && ($asset->assetstatus?->deployable == '1')
) { ) {
$this->update_array['status_id'] = $updated_status->id; $this->update_array['status_id'] = $updated_status->id;
} }

View File

@@ -206,6 +206,7 @@ class LoginController extends Controller
$user->password = bcrypt($request->input('password')); $user->password = bcrypt($request->input('password'));
} }
$user->last_login = \Carbon::now();
$user->email = $ldap_attr['email']; $user->email = $ldap_attr['email'];
$user->first_name = $ldap_attr['firstname']; $user->first_name = $ldap_attr['firstname'];
$user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc. $user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc.
@@ -432,6 +433,7 @@ class LoginController extends Controller
if (Google2FA::verifyKey($user->two_factor_secret, $secret)) { if (Google2FA::verifyKey($user->two_factor_secret, $secret)) {
$user->two_factor_enrolled = 1; $user->two_factor_enrolled = 1;
$user->last_login = \Carbon::now();
$user->saveQuietly(); $user->saveQuietly();
$request->session()->put('2fa_authed', $user->id); $request->session()->put('2fa_authed', $user->id);

View File

@@ -40,7 +40,7 @@ class DashboardController extends Controller
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) { if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--force' => true]); Artisan::call('migrate', ['--force' => true]);
\Artisan::call('passport:install'); Artisan::call('passport:install', ['--no-interaction' => true]);
} }
return view('dashboard')->with('asset_stats', $asset_stats)->with('counts', $counts); return view('dashboard')->with('asset_stats', $asset_stats)->with('counts', $counts);

View File

@@ -266,7 +266,7 @@ class ReportsController extends Controller
$actionlogs = Actionlog::with('item', 'user', 'target', 'location', 'adminuser') $actionlogs = Actionlog::with('item', 'user', 'target', 'location', 'adminuser')
->orderBy('created_at', 'DESC') ->orderBy('created_at', 'DESC')
->chunk(20, function ($actionlogs) use ($handle) { ->chunk(500, function ($actionlogs) use ($handle) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']; $executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
Log::debug('Walking results: '.$executionTime); Log::debug('Walking results: '.$executionTime);
$count = 0; $count = 0;
@@ -748,7 +748,7 @@ class ReportsController extends Controller
} }
Log::debug($assets->toSql()); Log::debug($assets->toSql());
$assets->orderBy('assets.id', 'ASC')->chunk(20, function ($assets) use ($handle, $customfields, $request) { $assets->orderBy('assets.id', 'ASC')->chunk(500, function ($assets) use ($handle, $customfields, $request) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']; $executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
Log::debug('Walking results: '.$executionTime); Log::debug('Walking results: '.$executionTime);
@@ -1175,18 +1175,13 @@ class ReportsController extends Controller
} }
$email = $assetItem->assignedTo?->email; $email = $assetItem->assignedTo?->email;
$locale = $assetItem->assignedTo?->locale; $locale = $assetItem->assignedTo?->locale;
// Only send notification if assigned
if ($locale && $email) {
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note))->locale($locale));
} elseif ($email) { if (is_null($email) || $email === '') {
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)));
}
if ($email == ''){
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_email')); return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_email'));
} }
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note, firstTimeSending: false))->locale($locale));
return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent')); return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent'));
} }

3
app/Http/Controllers/SettingsController.php Executable file → Normal file
View File

@@ -256,7 +256,7 @@ class SettingsController extends Controller
Artisan::call('migrate', ['--force' => true]); Artisan::call('migrate', ['--force' => true]);
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) { if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]); Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
Artisan::call('passport:install'); Artisan::call('passport:install', ['--no-interaction' => true]);
} }
return view('setup/migrate') return view('setup/migrate')
@@ -851,6 +851,7 @@ class SettingsController extends Controller
$setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query'); $setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query');
$setting->ldap_version = $request->input('ldap_version', 3); $setting->ldap_version = $request->input('ldap_version', 3);
$setting->ldap_active_flag = $request->input('ldap_active_flag'); $setting->ldap_active_flag = $request->input('ldap_active_flag');
$setting->ldap_invert_active_flag = $request->input('ldap_invert_active_flag');
$setting->ldap_emp_num = $request->input('ldap_emp_num'); $setting->ldap_emp_num = $request->input('ldap_emp_num');
$setting->ldap_email = $request->input('ldap_email'); $setting->ldap_email = $request->input('ldap_email');
$setting->ldap_manager = $request->input('ldap_manager'); $setting->ldap_manager = $request->input('ldap_manager');

View File

@@ -26,7 +26,7 @@ class StoreNotificationSettings extends FormRequest
return [ return [
'alert_email' => 'email_array|nullable', 'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email_array|nullable', 'admin_cc_email' => 'email_array|nullable',
'alert_threshold' => 'numeric|nullable|gt:0', 'alert_threshold' => 'numeric|nullable',
'alert_interval' => 'numeric|nullable|gt:0', 'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable', 'audit_warning_days' => 'numeric|nullable',
'due_checkin_days' => 'numeric|nullable|gt:0', 'due_checkin_days' => 'numeric|nullable|gt:0',

View File

@@ -115,7 +115,7 @@ class CheckoutableListener
} }
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail') ); return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail') );
} catch (Exception $e) { } catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [ Log::warning(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint, 'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event, 'event' => $event,
@@ -211,7 +211,7 @@ class CheckoutableListener
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail')); return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
} }
} catch (Exception $e) { } catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [ Log::warning(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint, 'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event, 'event' => $event,

View File

@@ -12,11 +12,11 @@ class CategoryEditForm extends Component
public $originalSendCheckInEmailValue; public $originalSendCheckInEmailValue;
public $requireAcceptance; public bool $requireAcceptance;
public $sendCheckInEmail; public bool $sendCheckInEmail;
public $useDefaultEula; public bool $useDefaultEula;
public function mount() public function mount()
{ {

View File

@@ -20,10 +20,12 @@ class CheckoutAssetMail extends Mailable
{ {
use Queueable, SerializesModels; use Queueable, SerializesModels;
private bool $firstTimeSending;
/** /**
* Create a new message instance. * Create a new message instance.
*/ */
public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note) public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note, bool $firstTimeSending = true)
{ {
$this->item = $asset; $this->item = $asset;
$this->admin = $checkedOutBy; $this->admin = $checkedOutBy;
@@ -36,6 +38,8 @@ class CheckoutAssetMail extends Mailable
$this->last_checkout = ''; $this->last_checkout = '';
$this->expected_checkin = ''; $this->expected_checkin = '';
$this->firstTimeSending = $firstTimeSending;
if ($this->item->last_checkout) { if ($this->item->last_checkout) {
$this->last_checkout = Helper::getFormattedDateObject($this->item->last_checkout, 'date', $this->last_checkout = Helper::getFormattedDateObject($this->item->last_checkout, 'date',
false); false);
@@ -56,7 +60,7 @@ class CheckoutAssetMail extends Mailable
return new Envelope( return new Envelope(
from: $from, from: $from,
subject: trans('mail.Asset_Checkout_Notification'), subject: $this->getSubject(),
); );
} }
@@ -107,4 +111,13 @@ class CheckoutAssetMail extends Mailable
{ {
return []; return [];
} }
private function getSubject(): string
{
if ($this->firstTimeSending) {
return trans('mail.Asset_Checkout_Notification');
}
return trans('mail.unaccepted_asset_reminder');
}
} }

View File

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

View File

@@ -19,9 +19,10 @@ class UnacceptedAssetReminderMail extends Mailable
*/ */
public function __construct($checkout_info, $count) public function __construct($checkout_info, $count)
{ {
$this->count = $count; $this->count = $count;
$this->target = $checkout_info['acceptance']?->assignedTo; $this->target = $checkout_info?->assignedTo;
$this->acceptance = $checkout_info['acceptance']; $this->acceptance = $checkout_info;
} }
/** /**

View File

@@ -293,16 +293,22 @@ class Actionlog extends SnipeModel
public function daysUntilNextAudit($monthInterval = 12, $asset = null) public function daysUntilNextAudit($monthInterval = 12, $asset = null)
{ {
$now = Carbon::now(); $now = Carbon::now();
$last_audit_date = $this->created_at; $last_audit_date = $this->created_at; // this is the action log's created at, not the asset itself
$next_audit = $last_audit_date->addMonth($monthInterval); $next_audit = $last_audit_date->addMonth($monthInterval); // this actually *modifies* the $last_audit_date
$next_audit_days = $now->diffInDays($next_audit); $next_audit_days = round($now->diffInDays($next_audit, true));
$override_default_next = $next_audit;
// Override the default setting for interval if the asset has its own next audit date // Override the default setting for interval if the asset has its own next audit date
if (($asset) && ($asset->next_audit_date)) { if (($asset) && ($asset->next_audit_date)) {
$override_default_next = \Carbon::parse($asset->next_audit_date); $override_default_next = Carbon::parse($asset->next_audit_date);
$next_audit_days = $override_default_next->diffInDays($now); $next_audit_days = round($override_default_next->diffInDays($now, true));
} }
// Show as negative number if the next audit date is before the audit date we're looking at
if ($this->created_at > $override_default_next) {
$next_audit_days = '-'.$next_audit_days;
}
return $next_audit_days; return $next_audit_days;
} }

View File

@@ -234,7 +234,7 @@ class AssetModel extends SnipeModel
*/ */
public function adminuser() public function adminuser()
{ {
return $this->belongsTo(\App\Models\User::class, 'created_by'); return $this->belongsTo(\App\Models\User::class, 'created_by')->withTrashed();
} }

View File

@@ -149,11 +149,6 @@ class CustomField extends Model
return true; return true;
} }
// This is just a dumb thing we have to include because Laraval/Doctrine doesn't
// play well with enums or a table that EVER had enums. :(
$platform = Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('enum', 'string');
// Rename the field if the name has changed // Rename the field if the name has changed
Schema::table(self::$table_name, function ($table) use ($custom_field) { Schema::table(self::$table_name, function ($table) use ($custom_field) {
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug()); $table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug());

View File

@@ -90,12 +90,6 @@ class AssetMaintenancesPresenter extends Presenter
'searchable' => true, 'searchable' => true,
'sortable' => true, 'sortable' => true,
'title' => trans('admin/asset_maintenances/form.asset_maintenance_type'), 'title' => trans('admin/asset_maintenances/form.asset_maintenance_type'),
], [
'field' => 'title',
'searchable' => true,
'sortable' => true,
'switchable' => false,
'title' => trans('admin/asset_maintenances/form.title'),
], [ ], [
'field' => 'start_date', 'field' => 'start_date',
'searchable' => true, 'searchable' => true,

View File

@@ -105,4 +105,17 @@ $config = [
// (by default, the PUBLIC_FILESYSTEM DISK is 'local_public', in the public/uploads directory) // (by default, the PUBLIC_FILESYSTEM DISK is 'local_public', in the public/uploads directory)
$config['disks']['public'] = $config['disks'][env('PUBLIC_FILESYSTEM_DISK','local_public')]; $config['disks']['public'] = $config['disks'][env('PUBLIC_FILESYSTEM_DISK','local_public')];
// Handle the 'backup' disk for S3 consideration
if (env('PRIVATE_FILESYSTEM_DISK') == 's3_private') {
$config['disks']['backup']['driver'] = 's3';
$config['disks']['backup']['key'] = $config['disks']['s3_private']['key'];
$config['disks']['backup']['secret'] = $config['disks']['s3_private']['secret'];
$config['disks']['backup']['region'] = $config['disks']['s3_private']['region'];
$config['disks']['backup']['bucket'] = $config['disks']['s3_private']['bucket'];
$config['disks']['backup']['url'] = $config['disks']['s3_private']['url'];
$config['disks']['backup']['root'] = $config['disks']['s3_private']['root'];
$config['disks']['backup']['visibility'] = 'private';
}
return $config; return $config;

View File

@@ -1,10 +1,10 @@
<?php <?php
return array ( return array (
'app_version' => 'v8.0.1', 'app_version' => 'v8.0.2',
'full_app_version' => 'v8.0.1 - build 16992-g18c7cbbbb', 'full_app_version' => 'v8.0.2 - build 17048-g44dd06161',
'build_version' => '16992', 'build_version' => '17048',
'prerelease_version' => '', 'prerelease_version' => '',
'hash_version' => 'g18c7cbbbb', 'hash_version' => 'g44dd06161',
'full_hash' => 'v8.0.1-28-g18c7cbbbb', 'full_hash' => 'v8.0.2-54-g44dd06161',
'branch' => 'develop', 'branch' => 'develop',
); );

View File

@@ -27,6 +27,10 @@ class CheckoutAcceptanceFactory extends Factory
public function configure(): static public function configure(): static
{ {
return $this->afterCreating(function (CheckoutAcceptance $acceptance) { return $this->afterCreating(function (CheckoutAcceptance $acceptance) {
if ($acceptance->checkoutable instanceof Asset) {
$this->createdAssociatedActionLogEntry($acceptance);
}
if ($acceptance->checkoutable instanceof Asset && $acceptance->assignedTo instanceof User) { if ($acceptance->checkoutable instanceof Asset && $acceptance->assignedTo instanceof User) {
$acceptance->checkoutable->update([ $acceptance->checkoutable->update([
'assigned_to' => $acceptance->assigned_to_id, 'assigned_to' => $acceptance->assigned_to_id,
@@ -51,4 +55,23 @@ class CheckoutAcceptanceFactory extends Factory
'declined_at' => null, 'declined_at' => null,
]); ]);
} }
public function accepted()
{
return $this->state([
'accepted_at' => now()->subDay(),
'declined_at' => null,
]);
}
private function createdAssociatedActionLogEntry(CheckoutAcceptance $acceptance): void
{
$acceptance->checkoutable->assetlog()->create([
'action_type' => 'checkout',
'target_id' => $acceptance->assigned_to_id,
'target_type' => get_class($acceptance->assignedTo),
'item_id' => $acceptance->checkoutable_id,
'item_type' => $acceptance->checkoutable_type,
]);
}
} }

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('settings', function (Blueprint $table) {
$table->boolean('ldap_invert_active_flag')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('settings', function (Blueprint $table) {
$table->dropColumn('ldap_invert_active_flag');
});
}
};

View File

@@ -13,4 +13,8 @@ return [
'no_depreciations_warning' => '<strong>Warning: </strong> 'no_depreciations_warning' => '<strong>Warning: </strong>
You do not currently have any depreciations set up. You do not currently have any depreciations set up.
Please set up at least one depreciation to view the depreciation report.', Please set up at least one depreciation to view the depreciation report.',
'depreciation_method' => 'Depreciation Method',
'linear_depreciation' => 'Linear (Default)',
'half_1' => 'Half-year convention, always applied',
'half_2' => 'Half-year convention, applied with condition',
]; ];

View File

@@ -56,7 +56,7 @@ return [
'asset_location_update_actual' => 'Update only actual location', 'asset_location_update_actual' => 'Update only actual location',
'asset_not_deployable' => 'That asset status is not deployable. This asset cannot be checked out.', 'asset_not_deployable' => 'That asset status is not deployable. This asset cannot be checked out.',
'asset_not_deployable_checkin' => 'That asset status is not deployable. Using this status label will checkin the asset.', 'asset_not_deployable_checkin' => 'That asset status is not deployable. Using this status label will checkin the asset.',
'asset_deployable' => 'That status is deployable. This asset can be checked out.', 'asset_deployable' => 'This asset can be checked out.',
'processing_spinner' => 'Processing... (This might take a bit of time on large files)', 'processing_spinner' => 'Processing... (This might take a bit of time on large files)',
'optional_infos' => 'Optional Information', 'optional_infos' => 'Optional Information',
'order_details' => 'Order Related Information', 'order_details' => 'Order Related Information',

View File

@@ -66,6 +66,7 @@ return [
'file_already_deleted' => 'The file selected was already deleted', 'file_already_deleted' => 'The file selected was already deleted',
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters', 'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters', 'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
'transliterate_failure' => 'Transliteration from :encoding to UTF-8 failed due to invalid characters in input'
], ],

View File

@@ -4,6 +4,7 @@ return [
'info' => 'Select the options you want for your asset report.', 'info' => 'Select the options you want for your asset report.',
'deleted_user' => 'Deleted user', 'deleted_user' => 'Deleted user',
'send_reminder' => 'Send reminder', 'send_reminder' => 'Send reminder',
'cannot_send_reminder' => 'User has been deleted or does not have an email address so cannot receive a reminder',
'reminder_sent' => 'Reminder sent', 'reminder_sent' => 'Reminder sent',
'acceptance_deleted' => 'Acceptance request deleted', 'acceptance_deleted' => 'Acceptance request deleted',
'acceptance_request' => 'Acceptance request', 'acceptance_request' => 'Acceptance request',

View File

@@ -42,6 +42,7 @@ return [
'confirm_purge' => 'Confirm Purge', 'confirm_purge' => 'Confirm Purge',
'confirm_purge_help' => 'Enter the text "DELETE" in the box below to purge your deleted records. This action cannot be undone and will PERMANENTLY delete all soft-deleted items and users. (You should make a backup first, just to be safe.)', 'confirm_purge_help' => 'Enter the text "DELETE" in the box below to purge your deleted records. This action cannot be undone and will PERMANENTLY delete all soft-deleted items and users. (You should make a backup first, just to be safe.)',
'custom_css' => 'Custom CSS', 'custom_css' => 'Custom CSS',
'custom_css_placeholder' => 'Add your custom CSS',
'custom_css_help' => 'Enter any custom CSS overrides you would like to use. Do not include the &lt;style&gt;&lt;/style&gt; tags.', 'custom_css_help' => 'Enter any custom CSS overrides you would like to use. Do not include the &lt;style&gt;&lt;/style&gt; tags.',
'custom_forgot_pass_url' => 'Custom Password Reset URL', 'custom_forgot_pass_url' => 'Custom Password Reset URL',
'custom_forgot_pass_url_help' => 'This replaces the built-in forgotten password URL on the login screen, useful to direct people to internal or hosted LDAP password reset functionality. It will effectively disable local user forgotten password functionality.', 'custom_forgot_pass_url_help' => 'This replaces the built-in forgotten password URL on the login screen, useful to direct people to internal or hosted LDAP password reset functionality. It will effectively disable local user forgotten password functionality.',
@@ -69,6 +70,7 @@ return [
'favicon_size' => 'Favicons should be square images, 16x16 pixels.', 'favicon_size' => 'Favicons should be square images, 16x16 pixels.',
'footer_text' => 'Additional Footer Text ', 'footer_text' => 'Additional Footer Text ',
'footer_text_help' => 'This text will appear in the right-side footer. Links are allowed using <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>. Line breaks, headers, images, etc may result in unpredictable results.', 'footer_text_help' => 'This text will appear in the right-side footer. Links are allowed using <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>. Line breaks, headers, images, etc may result in unpredictable results.',
'footer_text_placeholder' => 'Optional footer text',
'general_settings' => 'General Settings', 'general_settings' => 'General Settings',
'general_settings_help' => 'Default EULA and more', 'general_settings_help' => 'Default EULA and more',
'generate_backup' => 'Generate Backup', 'generate_backup' => 'Generate Backup',
@@ -118,6 +120,8 @@ return [
'ldap_version' => 'LDAP Version', 'ldap_version' => 'LDAP Version',
'ldap_active_flag' => 'LDAP Active Flag', 'ldap_active_flag' => 'LDAP Active Flag',
'ldap_activated_flag_help' => 'This value is used to determine whether a synced user can login to Snipe-IT. <strong>It does not affect the ability to check items in or out to them</strong>, and should be the <strong>attribute name</strong> within your AD/LDAP, <strong>not the value</strong>. <br><br>If this field is set to a field name that does not exist in your AD/LDAP, or the value in the AD/LDAP field is set to <code>0</code> or <code>false</code>, <strong>user login will be disabled</strong>. If the value in the AD/LDAP field is set to <code>1</code> or <code>true</code> or <em>any other text</em> means the user can log in. When the field is blank in your AD, we respect the <code>userAccountControl</code> attribute, which usually allows non-suspended users to log in.', 'ldap_activated_flag_help' => 'This value is used to determine whether a synced user can login to Snipe-IT. <strong>It does not affect the ability to check items in or out to them</strong>, and should be the <strong>attribute name</strong> within your AD/LDAP, <strong>not the value</strong>. <br><br>If this field is set to a field name that does not exist in your AD/LDAP, or the value in the AD/LDAP field is set to <code>0</code> or <code>false</code>, <strong>user login will be disabled</strong>. If the value in the AD/LDAP field is set to <code>1</code> or <code>true</code> or <em>any other text</em> means the user can log in. When the field is blank in your AD, we respect the <code>userAccountControl</code> attribute, which usually allows non-suspended users to log in.',
'ldap_invert_active_flag' => 'LDAP Invert Active Flag',
'ldap_invert_active_flag_help' => 'If enabled: when the value returned by LDAP Active Flag is <code>0</code> or <code>false</code> the user account will be active.',
'ldap_emp_num' => 'LDAP Employee Number', 'ldap_emp_num' => 'LDAP Employee Number',
'ldap_email' => 'LDAP Email', 'ldap_email' => 'LDAP Email',
'ldap_test' => 'Test LDAP', 'ldap_test' => 'Test LDAP',
@@ -132,6 +136,7 @@ return [
'login_user_agent' => 'User Agent', 'login_user_agent' => 'User Agent',
'login_help' => 'List of attempted logins', 'login_help' => 'List of attempted logins',
'login_note' => 'Login Note', 'login_note' => 'Login Note',
'login_note_placeholder' => "If you do not have a login or have found a device belonging to this company, please call technical support at 888-555-1212. Thank you.",
'login_note_help' => 'Optionally include a few sentences on your login screen, for example to assist people who have found a lost or stolen device. This field accepts <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>', 'login_note_help' => 'Optionally include a few sentences on your login screen, for example to assist people who have found a lost or stolen device. This field accepts <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>',
'login_remote_user_text' => 'Remote User login options', 'login_remote_user_text' => 'Remote User login options',
'login_remote_user_enabled_text' => 'Enable Login with Remote User Header', 'login_remote_user_enabled_text' => 'Enable Login with Remote User Header',
@@ -345,6 +350,8 @@ return [
'setup_migration_create_user' => 'Next: Create User', 'setup_migration_create_user' => 'Next: Create User',
'ldap_settings_link' => 'LDAP Settings Page', 'ldap_settings_link' => 'LDAP Settings Page',
'slack_test' => 'Test <i class="fab fa-slack"></i> Integration', 'slack_test' => 'Test <i class="fab fa-slack"></i> Integration',
'status_label_name' => 'Status Label Name',
'super_admin_only' => 'Super Admin Only',
'label2_enable' => 'New Label Engine', 'label2_enable' => 'New Label Engine',
'label2_enable_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>', 'label2_enable_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>',
'label2_template' => 'Template', 'label2_template' => 'Template',
@@ -378,6 +385,7 @@ return [
'database_driver' => 'Database Driver', 'database_driver' => 'Database Driver',
'bs_table_storage' => 'Table Storage', 'bs_table_storage' => 'Table Storage',
'timezone' => 'Timezone', 'timezone' => 'Timezone',
'test_mail' => 'Test Mail',
'profile_edit' => 'Edit Profile', 'profile_edit' => 'Edit Profile',
'profile_edit_help' => 'Allow users to edit their own profiles.', 'profile_edit_help' => 'Allow users to edit their own profiles.',
'default_avatar' => 'Upload custom default avatar', 'default_avatar' => 'Upload custom default avatar',
@@ -387,6 +395,15 @@ return [
'due_checkin_days' => 'Due For Checkin Warning', 'due_checkin_days' => 'Due For Checkin Warning',
'due_checkin_days_help' => 'How many days before the expected checkin of an asset should it be listed in the "Due for checkin" page?', 'due_checkin_days_help' => 'How many days before the expected checkin of an asset should it be listed in the "Due for checkin" page?',
'no_groups' => 'No groups have been created yet. Visit <code>Admin Settings > Permission Groups</code> to add one.', 'no_groups' => 'No groups have been created yet. Visit <code>Admin Settings > Permission Groups</code> to add one.',
'text' => 'Text',
'logo_option_types' => [
'text' => 'Text',
'logo' => 'Logo',
'logo_and_text' => 'Logo and Text',
],
/* Keywords for settings overview help */ /* Keywords for settings overview help */

View File

@@ -599,5 +599,6 @@ return [
'generic_model_not_found' => 'That :model was not found or you do not have permission to access it', 'generic_model_not_found' => 'That :model was not found or you do not have permission to access it',
'deleted_models' => 'Deleted Asset Models', 'deleted_models' => 'Deleted Asset Models',
'deleted_users' => 'Deleted Users', 'deleted_users' => 'Deleted Users',
'cost_each' => ':amount each',
]; ];

View File

@@ -26,9 +26,9 @@
<livewire:category-edit-form <livewire:category-edit-form
:default-eula-text="$snipeSettings->default_eula_text" :default-eula-text="$snipeSettings->default_eula_text"
:eula-text="old('eula_text', $item->eula_text)" :eula-text="old('eula_text', $item->eula_text)"
:require-acceptance="old('require_acceptance', $item->require_acceptance)" :require-acceptance="(bool) old('require_acceptance', $item->require_acceptance)"
:send-check-in-email="old('checkin_email', $item->checkin_email)" :send-check-in-email="(bool) old('checkin_email', $item->checkin_email)"
:use-default-eula="old('use_default_eula', $item->use_default_eula)" :use-default-eula="(bool) old('use_default_eula', $item->use_default_eula)"
/> />
@include ('partials.forms.edit.image-upload', ['image_path' => app('categories_upload_path')]) @include ('partials.forms.edit.image-upload', ['image_path' => app('categories_upload_path')])

View File

@@ -1211,7 +1211,7 @@
<a href="{{ route('components.show', $component->id) }}">{{ $component->name }}</a> <a href="{{ route('components.show', $component->id) }}">{{ $component->name }}</a>
</td> </td>
<td>{{ $component->pivot->assigned_qty }}</td> <td>{{ $component->pivot->assigned_qty }}</td>
<td>{{ Helper::formatCurrencyOutput($component->purchase_cost) }} each</td> <td>{{ trans('general.cost_each', ['amount' => Helper::formatCurrencyOutput($component->purchase_cost)]) }} </td>
<td>{{ $component->serial }}</td> <td>{{ $component->serial }}</td>
<td> <td>
<a href="{{ route('components.checkin.show', $component->pivot->id) }}" class="btn btn-sm bg-purple hidden-print" data-tooltip="true">{{ trans('general.checkin') }}</a> <a href="{{ route('components.checkin.show', $component->pivot->id) }}" class="btn btn-sm bg-purple hidden-print" data-tooltip="true">{{ trans('general.checkin') }}</a>

View File

@@ -23,12 +23,25 @@
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
@if ($defaultEulaText!='') @if ($defaultEulaText!='')
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('use_default_eula', '1', $useDefaultEula, ['wire:model.live' => 'useDefaultEula', 'aria-label'=>'use_default_eula']) }} <input
type="checkbox"
name="use_default_eula"
value="1"
wire:model.live="useDefaultEula"
aria-label="use_default_eula"
/>
<span>{!! trans('admin/categories/general.use_default_eula') !!}</span> <span>{!! trans('admin/categories/general.use_default_eula') !!}</span>
</label> </label>
@else @else
<label class="form-control form-control--disabled"> <label class="form-control form-control--disabled">
{{ Form::checkbox('use_default_eula', '0', $useDefaultEula, ['wire:model.live' => 'useDefaultEula', 'class'=>'disabled','disabled' => 'disabled', 'aria-label'=>'use_default_eula']) }} <input
type="checkbox"
name="use_default_eula"
value="0"
wire:model.live="useDefaultEula"
aria-label="use_default_eula"
disabled
/>
<span>{!! trans('admin/categories/general.use_default_eula_disabled') !!}</span> <span>{!! trans('admin/categories/general.use_default_eula_disabled') !!}</span>
</label> </label>
@endif @endif
@@ -39,7 +52,13 @@
<div class="form-group"> <div class="form-group">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('require_acceptance', '1', $requireAcceptance, ['wire:model.live' => 'requireAcceptance', 'aria-label'=>'require_acceptance']) }} <input
type="checkbox"
name="require_acceptance"
value="1"
wire:model.live="requireAcceptance"
aria-label="require_acceptance"
/>
{{ trans('admin/categories/general.require_acceptance') }} {{ trans('admin/categories/general.require_acceptance') }}
</label> </label>
</div> </div>
@@ -49,7 +68,14 @@
<div class="form-group"> <div class="form-group">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('checkin_email', '1', $sendCheckInEmail, ['wire:model.live' => 'sendCheckInEmail', 'aria-label'=>'checkin_email', 'disabled' => $this->sendCheckInEmailDisabled]) }} <input
type="checkbox"
name="checkin_email"
value="1"
wire:model.live="sendCheckInEmail"
aria-label="checkin_email"
@disabled($this->sendCheckInEmailDisabled)
/>
{{ trans('admin/categories/general.checkin_email') }} {{ trans('admin/categories/general.checkin_email') }}
</label> </label>
@if ($this->shouldDisplayEmailMessage) @if ($this->shouldDisplayEmailMessage)

View File

@@ -10,8 +10,15 @@
<div class="col-md-3"> <div class="col-md-3">
@if ($fieldset_id) @if ($fieldset_id)
<label class="form-control"> <label class="form-control">
<input
{{ Form::checkbox('add_default_values', 1, old('add_default_values', $add_default_values), ['data-livewire-component' => $this->getId(), 'id' => 'add_default_values', 'wire:model.live' => 'add_default_values', 'disabled' => $this->fields->isEmpty()]) }} type="checkbox"
name="add_default_values"
value="1"
id="add_default_values"
wire:model.live="add_default_values"
data-livewire-component="{{ $this->getId() }}"
@disabled($this->fields->isEmpty())
/>
{{ trans('admin/models/general.add_default_values') }} {{ trans('admin/models/general.add_default_values') }}
</label> </label>
@endif @endif

View File

@@ -164,7 +164,7 @@
</li> </li>
@endif @endif
@if ($model->created_by) @if ($model->adminuser)
<li>{{ trans('general.created_by') }}: <li>{{ trans('general.created_by') }}:
{{ $model->adminuser->present()->name() }} {{ $model->adminuser->present()->name() }}
</li> </li>

View File

@@ -29,7 +29,16 @@
data_export_options = $(this).attr('data-export-options'); data_export_options = $(this).attr('data-export-options');
export_options = data_export_options ? JSON.parse(data_export_options) : {}; export_options = data_export_options ? JSON.parse(data_export_options) : {};
export_options['htmlContent'] = false; // this is already the default; but let's be explicit about it export_options['htmlContent'] = false; // this is already the default; but let's be explicit about it
export_options['jspdf']= {"orientation": "l"}; export_options['jspdf'] = {
"orientation": "l",
"autotable": {
"styles": {
overflow: 'linebreak'
},
tableWidth: 'wrap'
}
};
// tableWidth: 'wrap',
// the following callback method is necessary to prevent XSS vulnerabilities // the following callback method is necessary to prevent XSS vulnerabilities
// (this is taken from Bootstrap Tables's default wrapper around jQuery Table Export) // (this is taken from Bootstrap Tables's default wrapper around jQuery Table Export)
export_options['onCellHtmlData'] = function (cell, rowIndex, colIndex, htmlData) { export_options['onCellHtmlData'] = function (cell, rowIndex, colIndex, htmlData) {

View File

@@ -1,7 +1,7 @@
<div class="form-group {{ $errors->has('email') ? ' has-error' : '' }}"> <div class="form-group {{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-3 col-xs-12 control-label">{{ trans('admin/suppliers/table.email') }}</label> <label for="email" class="col-md-3 col-xs-12 control-label">{{ trans('admin/suppliers/table.email') }}</label>
<div class="col-md-8 col-xs-12"> <div class="col-md-8 col-xs-12">
<input type="text" name="email" id="email" value="{{ old('email', ($item->email ?? $user->email)) }}" class="form-control" maxlength="191" style="width:100%; display:flex;"> <input type="text" name="email" id="email" value="{{ old('email', $item->email) }}" class="form-control" maxlength="191" style="width:100%; display:flex;">
{!! $errors->first('email', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!} {!! $errors->first('email', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div> </div>
</div> </div>

View File

@@ -4,7 +4,7 @@
<div class="form-group{{ $errors->has('image_delete') ? ' has-error' : '' }}"> <div class="form-group{{ $errors->has('image_delete') ? ' has-error' : '' }}">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('image_delete', '1', old('image_delete'), ['aria-label'=>'image_delete']) }} <input type="checkbox" name="image_delete" value="1" @checked(old('image_delete')) aria-label="image_delete">
{{ trans('general.image_delete') }} {{ trans('general.image_delete') }}
{!! $errors->first('image_delete', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('image_delete', '<span class="alert-msg">:message</span>') !!}
</label> </label>

View File

@@ -47,7 +47,7 @@
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label id="{{ $logoId }}-deleteCheckbox" for="{{ $logoClearVariable }}" style="font-weight: normal" class="form-control"> <label id="{{ $logoId }}-deleteCheckbox" for="{{ $logoClearVariable }}" style="font-weight: normal" class="form-control">
{{ Form::checkbox($logoClearVariable, '1', old($logoClearVariable)) }} <input type="checkbox" name="{{ $logoClearVariable }}" value="1" @checked(old($logoClearVariable))>
Remove current {{ ucwords(str_replace('_', ' ', $logoVariable)) }} image Remove current {{ ucwords(str_replace('_', ' ', $logoVariable)) }} image
</label> </label>
</div> </div>

View File

@@ -35,13 +35,12 @@
<thead> <thead>
<tr> <tr>
<th class="col-sm-1" data-field="file" data-visible="false" data-formatter="auditImageFormatter">{{ trans('admin/hardware/table.image') }}</th> <th class="col-sm-1" data-field="file" data-visible="false" data-formatter="auditImageFormatter">{{ trans('admin/hardware/table.image') }}</th>
<th class="col-sm-2" data-field="created_at" data-formatter="dateDisplayFormatter" data-sortable="true" data-searchable="true">{{ trans('general.audit') }}</th> <th class="col-sm-2" data-field="created_by" data-sortable="true" data-searchable="true" data-formatter="usersLinkObjFormatter">{{ trans('general.created_by') }}</th>
<th class="col-sm-2" data-field="created_by" data-sortable="true" data-searchable="true" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
<th class="col-sm-2" data-field="item" data-sortable="true" data-searchable="true" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th> <th class="col-sm-2" data-field="item" data-sortable="true" data-searchable="true" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
<th class="col-sm-1" data-field="location" data-sortable="true" data-searchable="true" data-formatter="locationsLinkObjFormatter">{{ trans('general.location') }}</th> <th class="col-sm-1" data-field="location" data-sortable="true" data-searchable="true" data-formatter="locationsLinkObjFormatter">{{ trans('general.location') }}</th>
<th class="col-sm-2" data-field="created_at" data-formatter="dateDisplayFormatter" data-sortable="true" data-searchable="true">{{ trans('general.last_audit') }}</th>
<th class="col-sm-2" data-field="next_audit_date" data-formatter="dateDisplayFormatter">{{ trans('general.next_audit_date') }}</th> <th class="col-sm-2" data-field="next_audit_date" data-formatter="dateDisplayFormatter">{{ trans('general.next_audit_date') }}</th>
<th class="col-sm-1" data-field="days_to_next_audit">{{ trans('general.days_to_next_audit') }}</th> <th class="col-sm-1" data-field="days_to_next_audit">{{ trans('general.days_to_next_audit') }}</th>
<th class="col-sm-2" data-field="note" data-sortable="true" data-searchable="true">{{ trans('general.notes') }}</th> <th class="col-sm-2" data-field="note" data-sortable="true" data-searchable="true">{{ trans('general.notes') }}</th>
</tr> </tr>
</thead> </thead>

View File

@@ -93,152 +93,152 @@
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('id', '1', $template->checkmarkValue('id')) }} <input type="checkbox" name="id" value="1" @checked($template->checkmarkValue('id')) />
{{ trans('general.id') }} {{ trans('general.id') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('company', '1', $template->checkmarkValue('company')) }} <input type="checkbox" name="company" value="1" @checked($template->checkmarkValue('company')) />
{{ trans('general.company') }} {{ trans('general.company') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('asset_tag', '1', $template->checkmarkValue('asset_tag')) }} <input type="checkbox" name="asset_tag" value="1" @checked($template->checkmarkValue('asset_tag')) />
{{ trans('general.asset_tag') }} {{ trans('general.asset_tag') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('asset_name', '1', $template->checkmarkValue('asset_name')) }} <input type="checkbox" name="asset_name" value="1" @checked($template->checkmarkValue('asset_name')) />
{{ trans('admin/hardware/form.name') }} {{ trans('admin/hardware/form.name') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('manufacturer', '1', $template->checkmarkValue('manufacturer')) }} <input type="checkbox" name="manufacturer" value="1" @checked($template->checkmarkValue('manufacturer')) />
{{ trans('general.manufacturer') }} {{ trans('general.manufacturer') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('model', '1', $template->checkmarkValue('model')) }} <input type="checkbox" name="model" value="1" @checked($template->checkmarkValue('model')) />
{{ trans('general.asset_models') }} {{ trans('general.asset_models') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('category', '1', $template->checkmarkValue('category')) }} <input type="checkbox" name="category" value="1" @checked($template->checkmarkValue('category')) />
{{ trans('general.category') }} {{ trans('general.category') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('serial', '1', $template->checkmarkValue('serial')) }} <input type="checkbox" name="serial" value="1" @checked($template->checkmarkValue('serial')) />
{{ trans('admin/hardware/table.serial') }} {{ trans('admin/hardware/table.serial') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('purchase_date', '1', $template->checkmarkValue('purchase_date')) }} <input type="checkbox" name="purchase_date" value="1" @checked($template->checkmarkValue('purchase_date')) />
{{ trans('admin/licenses/table.purchase_date') }} {{ trans('admin/licenses/table.purchase_date') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('purchase_cost', '1', $template->checkmarkValue('purchase_cost')) }} <input type="checkbox" name="purchase_cost" value="1" @checked($template->checkmarkValue('purchase_cost')) />
{{ trans('admin/hardware/form.cost') }} {{ trans('admin/hardware/form.cost') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('eol', '1', $template->checkmarkValue('eol')) }} <input type="checkbox" name="eol" value="1" @checked($template->checkmarkValue('eol')) />
{{ trans('admin/hardware/form.eol_date') }} {{ trans('admin/hardware/form.eol_date') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('order', '1', $template->checkmarkValue('order')) }} <input type="checkbox" name="order" value="1" @checked($template->checkmarkValue('order')) />
{{ trans('admin/hardware/form.order') }} {{ trans('admin/hardware/form.order') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('supplier', '1', $template->checkmarkValue('supplier')) }} <input type="checkbox" name="supplier" value="1" @checked($template->checkmarkValue('supplier')) />
{{ trans('general.suppliers') }} {{ trans('general.suppliers') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('location', '1', $template->checkmarkValue('location')) }} <input type="checkbox" name="location" value="1" @checked($template->checkmarkValue('location')) />
{{ trans('general.location') }} {{ trans('general.location') }}
</label> </label>
<label class="form-control" style="margin-left: 25px;"> <label class="form-control" style="margin-left: 25px;">
{{ Form::checkbox('location_address', '1', $template->checkmarkValue('location_address')) }} <input type="checkbox" name="location_address" value="1" @checked($template->checkmarkValue('location_address')) />
{{ trans('general.address') }} {{ trans('general.address') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('rtd_location', '1', $template->checkmarkValue('rtd_location')) }} <input type="checkbox" name="rtd_location" value="1" @checked($template->checkmarkValue('rtd_location')) />
{{ trans('admin/hardware/form.default_location') }} {{ trans('admin/hardware/form.default_location') }}
</label> </label>
<label class="form-control" style="margin-left: 25px;"> <label class="form-control" style="margin-left: 25px;">
{{ Form::checkbox('rtd_location_address', '1', $template->checkmarkValue('rtd_location_address')) }} <input type="checkbox" name="rtd_location_address" value="1" @checked($template->checkmarkValue('rtd_location_address')) />
{{ trans('general.address') }} {{ trans('general.address') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('status', '1', $template->checkmarkValue('status')) }} <input type="checkbox" name="status" value="1" @checked($template->checkmarkValue('status')) />
{{ trans('general.status') }} {{ trans('general.status') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('warranty', '1', $template->checkmarkValue('warranty')) }} <input type="checkbox" name="warranty" value="1" @checked($template->checkmarkValue('warranty')) />
{{ trans('admin/hardware/form.warranty') }} {{ trans('admin/hardware/form.warranty') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('depreciation', '1', $template->checkmarkValue('depreciation')) }} <input type="checkbox" name="depreciation" value="1" @checked($template->checkmarkValue('depreciation')) />
{{ trans('general.depreciation') }} {{ trans('general.depreciation') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('checkout_date', '1', $template->checkmarkValue('checkout_date')) }} <input type="checkbox" name="checkout_date" value="1" @checked($template->checkmarkValue('checkout_date')) />
{{ trans('admin/hardware/table.checkout_date') }} {{ trans('admin/hardware/table.checkout_date') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('checkin_date', '1', $template->checkmarkValue('checkin_date')) }} <input type="checkbox" name="checkin_date" value="1" @checked($template->checkmarkValue('checkin_date')) />
{{ trans('admin/hardware/table.last_checkin_date') }} {{ trans('admin/hardware/table.last_checkin_date') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('expected_checkin', '1', $template->checkmarkValue('expected_checkin')) }} <input type="checkbox" name="expected_checkin" value="1" @checked($template->checkmarkValue('expected_checkin')) />
{{ trans('admin/hardware/form.expected_checkin') }} {{ trans('admin/hardware/form.expected_checkin') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('created_at', '1', $template->checkmarkValue('created_at')) }} <input type="checkbox" name="created_at" value="1" @checked($template->checkmarkValue('created_at')) />
{{ trans('general.created_at') }} {{ trans('general.created_at') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('updated_at', '1', $template->checkmarkValue('updated_at')) }} <input type="checkbox" name="updated_at" value="1" @checked($template->checkmarkValue('updated_at')) />
{{ trans('general.updated_at') }} {{ trans('general.updated_at') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('deleted_at', '1', $template->checkmarkValue('deleted_at')) }} <input type="checkbox" name="deleted_at" value="1" @checked($template->checkmarkValue('deleted_at')) />
{{ trans('general.deleted') }} {{ trans('general.deleted') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('last_audit_date', '1', $template->checkmarkValue('last_audit_date')) }} <input type="checkbox" name="last_audit_date" value="1" @checked($template->checkmarkValue('last_audit_date')) />
{{ trans('general.last_audit') }} {{ trans('general.last_audit') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('next_audit_date', '1', $template->checkmarkValue('next_audit_date')) }} <input type="checkbox" name="next_audit_date" value="1" @checked($template->checkmarkValue('next_audit_date')) />
{{ trans('general.next_audit_date') }} {{ trans('general.next_audit_date') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('notes', '1', $template->checkmarkValue('notes')) }} <input type="checkbox" name="notes" value="1" @checked($template->checkmarkValue('notes')) />
{{ trans('general.notes') }} {{ trans('general.notes') }}
</label> </label>
<label class="form-control" style="margin-left: 25px;"> <label class="form-control" style="margin-left: 25px;">
{{ Form::checkbox('url', '1', $template->checkmarkValue('url')) }} <input type="checkbox" name="url" value="1" @checked($template->checkmarkValue('url')) />
{{ trans('general.url') }} {{ trans('general.url') }}
</label> </label>
@@ -248,64 +248,64 @@
<h2>{{ trans('general.checked_out_to_fields') }}: </h2> <h2>{{ trans('general.checked_out_to_fields') }}: </h2>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('assigned_to', '1', $template->checkmarkValue('assigned_to')) }} <input type="checkbox" name="assigned_to" value="1" @checked($template->checkmarkValue('assigned_to')) />
{{ trans('admin/licenses/table.assigned_to') }} {{ trans('admin/licenses/table.assigned_to') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('username', '1', $template->checkmarkValue('username')) }} <input type="checkbox" name="username" value="1" @checked($template->checkmarkValue('username')) />
{{ trans('admin/users/table.username') }} {{ trans('admin/users/table.username') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('employee_num', '1', $template->checkmarkValue('employee_num')) }} <input type="checkbox" name="employee_num" value="1" @checked($template->checkmarkValue('employee_num')) />
{{ trans('general.employee_number') }} {{ trans('general.employee_number') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('manager', '1', $template->checkmarkValue('manager')) }} <input type="checkbox" name="manager" value="1" @checked($template->checkmarkValue('manager')) />
{{ trans('admin/users/table.manager') }} {{ trans('admin/users/table.manager') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('department', '1', $template->checkmarkValue('department')) }} <input type="checkbox" name="department" value="1" @checked($template->checkmarkValue('department')) />
{{ trans('general.department') }} {{ trans('general.department') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('title', '1', $template->checkmarkValue('title')) }} <input type="checkbox" name="title" value="1" @checked($template->checkmarkValue('title')) />
{{ trans('admin/users/table.title') }} {{ trans('admin/users/table.title') }}
</label> </label>
<!-- new --> <!-- new -->
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('phone', '1', $template->checkmarkValue('phone')) }} <input type="checkbox" name="phone" value="1" @checked($template->checkmarkValue('phone')) />
{{ trans('admin/users/table.phone') }} {{ trans('admin/users/table.phone') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('user_address', '1', $template->checkmarkValue('user_address')) }} <input type="checkbox" name="user_address" value="1" @checked($template->checkmarkValue('user_address')) />
{{ trans('general.address') }} {{ trans('general.address') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{Form::checkbox('user_city', '1', $template->checkmarkValue('user_city'))}} <input type="checkbox" name="user_city" value="1" @checked($template->checkmarkValue('user_city')) />
{{ trans('general.city') }} {{ trans('general.city') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{Form::checkbox('user_state', '1', $template->checkmarkValue('user_state'))}} <input type="checkbox" name="user_state" value="1" @checked($template->checkmarkValue('user_state')) />
{{ trans('general.state') }} {{ trans('general.state') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{Form::checkbox('user_country', '1', $template->checkmarkValue('user_country'))}} <input type="checkbox" name="user_country" value="1" @checked($template->checkmarkValue('user_country')) />
{{ trans('general.country') }} {{ trans('general.country') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{Form::checkbox('user_zip', '1', $template->checkmarkValue('user_zip'))}} <input type="checkbox" name="user_zip" value="1" @checked($template->checkmarkValue('user_zip')) />
{{ trans('general.zip') }} {{ trans('general.zip') }}
</label> </label>
@@ -318,7 +318,7 @@
@foreach ($customfields as $customfield) @foreach ($customfields as $customfield)
<label class="form-control"> <label class="form-control">
{{ Form::checkbox($customfield->db_column_name(), '1', $template->checkmarkValue($customfield->db_column_name())) }} <input type="checkbox" name="{{ $customfield->db_column_name() }}" value="1" @checked($template->checkmarkValue($customfield->db_column_name())) />
{{ $customfield->name }} {{ $customfield->name }}
</label> </label>
@@ -549,13 +549,13 @@
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('exclude_archived', '1', $template->checkmarkValue('exclude_archived', '0')) }} <input type="checkbox" name="exclude_archived" value="1" @checked($template->checkmarkValue('exclude_archived', '0')) />
{{ trans('general.exclude_archived') }} {{ trans('general.exclude_archived') }}
</label> </label>
</div> </div>
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('use_bom', '1', $template->checkmarkValue('use_bom', '0')) }} <input type="checkbox" name="use_bom" value="1" @checked($template->checkmarkValue('use_bom', '0')) />
{{ trans('general.bom_remark') }} {{ trans('general.bom_remark') }}
</label> </label>
</div> </div>

View File

@@ -68,7 +68,7 @@
@foreach ($assetsForReport as $item) @foreach ($assetsForReport as $item)
@if ($item['assetItem']) @if ($item['assetItem'])
<tr @if($item['acceptance']->trashed()) style="text-decoration: line-through" @endif> <tr @if($item['acceptance']->trashed()) style="text-decoration: line-through" @endif>
<td>{{ $item['acceptance']->created_at }}</td> <td>{{ Helper::getFormattedDateObject($item['acceptance']->created_at, 'datetime', false) }}</td>
<td>{{ ($item['assetItem']->company) ? $item['assetItem']->company->name : '' }}</td> <td>{{ ($item['assetItem']->company) ? $item['assetItem']->company->name : '' }}</td>
<td>{!! $item['assetItem']->model->category->present()->nameUrl() !!}</td> <td>{!! $item['assetItem']->model->category->present()->nameUrl() !!}</td>
<td>{!! $item['assetItem']->present()->modelUrl() !!}</td> <td>{!! $item['assetItem']->present()->modelUrl() !!}</td>
@@ -79,13 +79,18 @@
<nobr> <nobr>
@if(!$item['acceptance']->trashed()) @if(!$item['acceptance']->trashed())
<form method="post" class="white-space: nowrap;" action="{{ route('reports/unaccepted_assets_sent_reminder') }}"> <form method="post" class="white-space: nowrap;" action="{{ route('reports/unaccepted_assets_sent_reminder') }}">
@if ($item['acceptance']->assignedTo) @if (($item['acceptance']->assignedTo) && ($item['acceptance']->assignedTo->email))
@csrf @csrf
<input type="hidden" name="acceptance_id" value="{{ $item['acceptance']->id }}"> <input type="hidden" name="acceptance_id" value="{{ $item['acceptance']->id }}">
<button class="btn btn-sm btn-warning" data-tooltip="true" data-title="{{ trans('admin/reports/general.send_reminder') }}"> <button class="btn btn-sm btn-warning" data-tooltip="true" data-title="{{ trans('admin/reports/general.send_reminder') }}">
<i class="fa fa-repeat" aria-hidden="true"></i> <i class="fa fa-repeat" aria-hidden="true"></i>
</button> </button>
@else
<span data-tooltip="true" data-title="{{ trans('admin/reports/general.cannot_send_reminder') }}">
<a class="btn btn-sm btn-warning disabled" href="#">
<i class="fa fa-repeat" aria-hidden="true"></i>
</a>
</span>
@endif @endif
<a href="{{ route('reports/unaccepted_assets_delete', ['acceptanceId' => $item['acceptance']->id]) }}" class="btn btn-sm btn-danger delete-asset" data-tooltip="true" data-toggle="modal" data-content="{{ trans('general.delete_confirm', ['item' =>trans('admin/reports/general.acceptance_request')]) }}" data-title="{{ trans('general.delete') }}" onClick="return false;"><i class="fa fa-trash"></i></a> <a href="{{ route('reports/unaccepted_assets_delete', ['acceptanceId' => $item['acceptance']->id]) }}" class="btn btn-sm btn-danger delete-asset" data-tooltip="true" data-toggle="modal" data-content="{{ trans('general.delete_confirm', ['item' =>trans('admin/reports/general.acceptance_request')]) }}" data-title="{{ trans('general.delete') }}" onClick="return false;"><i class="fa fa-trash"></i></a>
</form> </form>

View File

@@ -45,7 +45,7 @@
<div class="form-group {{ $errors->has('alerts_enabled') ? 'error' : '' }}"> <div class="form-group {{ $errors->has('alerts_enabled') ? 'error' : '' }}">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('alerts_enabled', '1', old('alerts_enabled', $setting->alerts_enabled)) }} <input type="checkbox" name="alerts_enabled" value="1" @checked(old('alerts_enabled', $setting->alerts_enabled))>
{{ trans('admin/settings/general.alerts_enabled') }} {{ trans('admin/settings/general.alerts_enabled') }}
</label> </label>
</div> </div>
@@ -55,7 +55,7 @@
<div class="form-group {{ $errors->has('show_alerts_in_menu') ? 'error' : '' }}"> <div class="form-group {{ $errors->has('show_alerts_in_menu') ? 'error' : '' }}">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_alerts_in_menu', '1', old('show_alerts_in_menu', $setting->show_alerts_in_menu)) }} <input type="checkbox" name="show_alerts_in_menu" value="1" @checked(old('show_alerts_in_menu', $setting->show_alerts_in_menu))>
{{ trans('admin/settings/general.show_alerts_in_menu') }} {{ trans('admin/settings/general.show_alerts_in_menu') }}
</label> </label>
</div> </div>

View File

@@ -47,7 +47,7 @@
</div> </div>
<div class="col-md-7"> <div class="col-md-7">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('auto_increment_assets', '1', old('auto_increment_assets', $setting->auto_increment_assets),array('aria-label'=>'auto_increment_assets')) }} <input type="checkbox" name="auto_increment_assets" value="1" @checked(old('auto_increment_assets', $setting->auto_increment_assets)) aria-label="auto_increment_assets">
{{ trans('admin/settings/general.enabled') }} {{ trans('admin/settings/general.enabled') }}
</label> </label>
</div> </div>

View File

@@ -68,7 +68,9 @@
</div> </div>
</div> </div>
@php
$optionTypes = trans('admin/settings/general.logo_option_types');
@endphp
<!-- Branding --> <!-- Branding -->
<div class="form-group {{ $errors->has('brand') ? 'error' : '' }}"> <div class="form-group {{ $errors->has('brand') ? 'error' : '' }}">
@@ -76,8 +78,13 @@
<label for="brand">{{ trans('admin/settings/general.web_brand') }}</label> <label for="brand">{{ trans('admin/settings/general.web_brand') }}</label>
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{!! Form::select('brand', array('1'=>'Text','2'=>'Logo','3'=>'Logo + Text'), old('brand', $setting->brand), array('class' => 'form-control select2', 'style'=>'width: 150px ;')) !!} <select name="brand" id="brand" class="form-control select2 minimumResultsForSearch" style="width: 150px;">
{!! $errors->first('brand', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} @foreach($optionTypes as $value => $label)
<option value="{{ $value }}" {{ old('brand', $setting->brand) == $value ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
</div> </div>
</div> </div>
@@ -135,7 +142,7 @@
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('restore_default_avatar', '1', old('restore_default_avatar', $setting->restore_default_avatar)) }} <input type="checkbox" name="restore_default_avatar" value="1" @checked(old('restore_default_avatar', $setting->restore_default_avatar)) />
<span>{!! trans('admin/settings/general.restore_default_avatar', ['default_avatar'=> Storage::disk('public')->url('default.png')]) !!}</span> <span>{!! trans('admin/settings/general.restore_default_avatar', ['default_avatar'=> Storage::disk('public')->url('default.png')]) !!}</span>
</label> </label>
<p class="help-block"> <p class="help-block">
@@ -152,7 +159,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('load_remote', '1', old('load_remote', $setting->load_remote)) }} <input type="checkbox" name="load_remote" value="1" @checked(old('load_remote', $setting->load_remote)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
{!! $errors->first('load_remote', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('load_remote', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label> </label>
@@ -172,7 +179,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('logo_print_assets', '1', old('logo_print_assets', $setting->logo_print_assets),array('aria-label'=>'logo_print_assets')) }} <input type="checkbox" name="logo_print_assets" value="1" @checked(old('logo_print_assets', $setting->logo_print_assets)) aria-label="logo_print_assets"/>
{{ trans('admin/settings/general.logo_print_assets_help') }} {{ trans('admin/settings/general.logo_print_assets_help') }}
</label> </label>
@@ -187,7 +194,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_url_in_emails', '1', old('show_url_in_emails', $setting->show_url_in_emails),array('aria-label'=>'show_url_in_emails')) }} <input type="checkbox" name="show_url_in_emails" value="1" @checked(old('show_url_in_emails', $setting->show_url_in_emails)) aria-label="show_url_in_emails" />
{{ trans('general.yes') }} {{ trans('general.yes') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.show_url_in_emails_help_text') }}</p> <p class="help-block">{{ trans('admin/settings/general.show_url_in_emails_help_text') }}</p>
@@ -228,7 +235,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('allow_user_skin', '1', old('allow_user_skin', $setting->allow_user_skin)) }} <input type="checkbox" name="allow_user_skin" value="1" @checked(old('allow_user_skin', $setting->allow_user_skin))/>
{{ trans('general.yes') }} {{ trans('general.yes') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.allow_user_skin_help_text') }}</p> <p class="help-block">{{ trans('admin/settings/general.allow_user_skin_help_text') }}</p>
@@ -272,10 +279,10 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
@if (config('app.lock_passwords')===true) @if (config('app.lock_passwords')===true)
{!! Form::select('support_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), old('support_footer', $setting->support_footer), ['class' => 'form-control select2 disabled', 'style'=>'width: 150px ;', 'disabled' => 'disabled']) !!} {!! Form::select('support_footer', array('on'=>trans('admin/settings/general.enabled'),'off'=>trans('admin/settings/general.two_factor_disabled'),'admin'=>trans('admin/settings/general.super_admin_only')), old('support_footer', $setting->support_footer), ['class' => 'form-control select2 disabled', 'style'=>'width: 150px ;', 'disabled' => 'disabled']) !!}
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p> <p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else @else
{!! Form::select('support_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), old('support_footer', $setting->support_footer), array('class' => 'form-control select2', 'style'=>'width: 150px ;')) !!} {!! Form::select('support_footer', array('on'=>trans('admin/settings/general.enabled'),'off'=>trans('admin/settings/general.two_factor_disabled'),'admin'=>trans('admin/settings/general.super_admin_only')), old('support_footer', $setting->support_footer), array('class' => 'form-control select2', 'style'=>'width: 150px ;')) !!}
@endif @endif
@@ -291,10 +298,10 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
@if (config('app.lock_passwords')===true) @if (config('app.lock_passwords')===true)
{!! Form::select('version_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), old('version_footer', $setting->version_footer), ['class' => 'form-control select2 disabled', 'style'=>'width: 150px ;', 'disabled' => 'disabled']) !!} {!! Form::select('version_footer', array('on'=>trans('admin/settings/general.enabled'),'off'=>trans('admin/settings/general.two_factor_disabled'),'admin'=>trans('admin/settings/general.super_admin_only')), old('version_footer', $setting->version_footer), ['class' => 'form-control select2 disabled', 'style'=>'width: 150px ;', 'disabled' => 'disabled']) !!}
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p> <p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else @else
{!! Form::select('version_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), old('version_footer', $setting->version_footer), array('class' => 'form-control select2', 'style'=>'width: 150px ;')) !!} {!! Form::select('version_footer', array('on'=>trans('admin/settings/general.enabled'),'off'=>trans('admin/settings/general.two_factor_disabled'),'admin'=>trans('admin/settings/general.super_admin_only')), old('version_footer', $setting->version_footer), array('class' => 'form-control select2', 'style'=>'width: 150px ;')) !!}
@endif @endif
<p class="help-block">{{ trans('admin/settings/general.version_footer_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.version_footer_help') }}</p>

View File

@@ -45,7 +45,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('full_multiple_companies_support', '1', old('full_multiple_companies_support', $setting->full_multiple_companies_support),array('aria-label'=>'full_multiple_companies_support')) }} <input type="checkbox" name="full_multiple_companies_support" value="1" @checked(old('full_multiple_companies_support', $setting->full_multiple_companies_support)) aria-label="full_multiple_companies_support" />
{{ trans('admin/settings/general.full_multiple_companies_support_text') }} {{ trans('admin/settings/general.full_multiple_companies_support_text') }}
</label> </label>
{!! $errors->first('full_multiple_companies_support', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('full_multiple_companies_support', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -64,7 +64,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('require_accept_signature', '1', old('require_accept_signature', $setting->require_accept_signature)) }} <input type="checkbox" name="require_accept_signature" value="1" @checked(old('require_accept_signature', $setting->require_accept_signature)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
</label> </label>
{!! $errors->first('require_accept_signature', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('require_accept_signature', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -136,7 +136,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_images_in_email', '1', old('show_images_in_email', $setting->show_images_in_email)) }} <input type="checkbox" name="show_images_in_email" value="1" @checked(old('show_images_in_email', $setting->show_images_in_email)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
{!! $errors->first('show_images_in_email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('show_images_in_email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label> </label>
@@ -152,7 +152,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('unique_serial', '1', old('unique_serial', $setting->unique_serial),array('class' => 'minimal')) }} <input type="checkbox" name="unique_serial" value="1" @checked(old('unique_serial', $setting->unique_serial)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
{!! $errors->first('unique_serial', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('unique_serial', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label> </label>
@@ -245,11 +245,11 @@
<div class="col-md-9"> <div class="col-md-9">
@if (config('app.lock_passwords')) @if (config('app.lock_passwords'))
<textarea class="form-control disabled" name="login_note" placeholder="If you do not have a login or have found a device belonging to this company, please call technical support at 888-555-1212. Thank you." rows="2" aria-label="login_note" readonly>{{ old('login_note', $setting->login_note) }}</textarea> <textarea class="form-control disabled" name="login_note" placeholder="{{trans('admin/settings/general.login_note_placeholder')}}" rows="2" aria-label="login_note" readonly>{{ old('login_note', $setting->login_note) }}</textarea>
{!! $errors->first('login_note', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('login_note', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p> <p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else @else
<textarea class="form-control" name="login_note" aria-label="login_note" placeholder="If you do not have a login or have found a device belonging to this company, please call technical support at 888-555-1212. Thank you." rows="2">{{ old('login_note', $setting->login_note) }}</textarea> <textarea class="form-control" name="login_note" aria-label="login_note" placeholder="{{trans('admin/settings/general.login_note_placeholder')}}" rows="2">{{ old('login_note', $setting->login_note) }}</textarea>
{!! $errors->first('login_note', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('login_note', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@endif @endif
<p class="help-block">{!! trans('admin/settings/general.login_note_help') !!}</p> <p class="help-block">{!! trans('admin/settings/general.login_note_help') !!}</p>
@@ -259,7 +259,7 @@
<!-- Mail test --> <!-- Mail test -->
<div class="form-group"> <div class="form-group">
<div class="col-md-3"> <div class="col-md-3">
<label for="login_note">Test Mail</label> <label for="login_note">{{trans('admin/settings/general.test_mail')}}</label>
</div> </div>
<div class="col-md-9" id="mailtestrow"> <div class="col-md-9" id="mailtestrow">
<a class="btn btn-default btn-sm pull-left" id="mailtest" style="margin-right: 10px;"> <a class="btn btn-default btn-sm pull-left" id="mailtest" style="margin-right: 10px;">
@@ -311,7 +311,7 @@
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_archived_in_list', '1', old('show_archived_in_list', $setting->show_archived_in_list),array('aria-label'=>'show_archived_in_list')) }} <input type="checkbox" name="show_archived_in_list" value="1" @checked(old('show_archived_in_list', $setting->show_archived_in_list)) aria-label="show_archived_in_list" />
{{ trans('admin/settings/general.show_archived_in_list_text') }} {{ trans('admin/settings/general.show_archived_in_list_text') }}
</label> </label>
{!! $errors->first('show_archived_in_list', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('show_archived_in_list', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -325,7 +325,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_assigned_assets', '1', old('show_assigned_assets', $setting->show_assigned_assets),array('class' => 'minimal')) }} <input type="checkbox" name="show_assigned_assets" value="1" @checked(old('show_assigned_assets', $setting->show_assigned_assets)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.show_assigned_assets_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.show_assigned_assets_help') }}</p>
@@ -340,15 +340,19 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_in_model_list[]', 'image', old('show_in_model_list', $snipeSettings->modellistCheckedValue('image')),array('class' => 'minimal', 'aria-label'=>'show_in_model_list' )) }} {{ trans('general.image') }} <input type="checkbox" name="show_in_model_list[]" value="image" @checked(old('show_in_model_list', $snipeSettings->modellistCheckedValue('image'))) aria-label="show_in_model_list"/>
{{ trans('general.image') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_in_model_list[]', 'category', old('show_in_model_list', $snipeSettings->modellistCheckedValue('category')),array('class' => 'minimal', 'aria-label'=>'show_in_model_list' )) }} {{ trans('general.category') }} <input type="checkbox" name="show_in_model_list[]" value="category" @checked(old('show_in_model_list', $snipeSettings->modellistCheckedValue('category'))) aria-label="show_in_model_list"/>
{{ trans('general.category') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_in_model_list[]', 'manufacturer', old('show_in_model_list', $snipeSettings->modellistCheckedValue('manufacturer')),array('class' => 'minimal', 'aria-label'=>'show_in_model_list' )) }} {{ trans('general.manufacturer') }} </label> <input type="checkbox" name="show_in_model_list[]" value="manufacturer" @checked(old('show_in_model_list', $snipeSettings->modellistCheckedValue('manufacturer'))) aria-label="show_in_model_list"/>
{{ trans('general.manufacturer') }} </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('show_in_model_list[]', 'model_number', old('show_in_model_list', $snipeSettings->modellistCheckedValue('model_number')),array('class' => 'minimal', 'aria-label'=>'show_in_model_list' )) }} {{ trans('general.model_no') }} <input type="checkbox" name="show_in_model_list[]" value="model_number" @checked(old('show_in_model_list', $snipeSettings->modellistCheckedValue('model_number'))) aria-label="show_in_model_list"/>
{{ trans('general.model_no') }}
</label> </label>
</div> </div>
</div> </div>
@@ -370,13 +374,13 @@
<!-- Depreciation method --> <!-- Depreciation method -->
<div class="form-group {{ $errors->has('depreciation_method') ? 'error' : '' }}"> <div class="form-group {{ $errors->has('depreciation_method') ? 'error' : '' }}">
<div class="col-md-3"> <div class="col-md-3">
<label for="depreciation_method">{{ trans('Depreciation method') }}</label> <label for="depreciation_method">{{ trans('admin/depreciations/general.depreciation_method') }}</label>
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::select('depreciation_method', array( {{ Form::select('depreciation_method', array(
'default' => 'Linear (default)', 'default' => trans('admin/depreciations/general.linear_depreciation'),
'half_1' => 'Half-year convention, always applied', 'half_1' => trans('admin/depreciations/general.half_1'),
'half_2' => 'Half-year convention, applied with condition', 'half_2' => trans('admin/depreciations/general.half_2'),
), old('username_format', $setting->depreciation_method), ['class' =>'select2', 'style' => 'width: 80%']) }} ), old('username_format', $setting->depreciation_method), ['class' =>'select2', 'style' => 'width: 80%']) }}
</div> </div>
</div> </div>

View File

@@ -54,7 +54,7 @@
<div class="col-md-8 col-md-offset-3"> <div class="col-md-8 col-md-offset-3">
<label class="form-control{{ (config('app.lock_passwords')===true) ? ' form-control--disabled': '' }}"> <label class="form-control{{ (config('app.lock_passwords')===true) ? ' form-control--disabled': '' }}">
<span class="sr-only">{{ trans('admin/settings/general.pwd_secure_uncommon') }}</span> <span class="sr-only">{{ trans('admin/settings/general.pwd_secure_uncommon') }}</span>
{{ Form::checkbox('google_login', '1', old('google_login', $setting->google_login),array('aria-label'=>'google_login', (config('app.lock_passwords')===true) ? 'disabled': '')) }} <input type="checkbox" name="google_login" value="1" @checked(old('google_login', $setting->google_login)) @disabled(config('app.lock_passwords')) aria-label="google_login">
{{ trans('admin/settings/general.enable_google_login') }} {{ trans('admin/settings/general.enable_google_login') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.enable_google_login_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.enable_google_login_help') }}</p>

View File

@@ -144,7 +144,7 @@
<div class="form-group"> <div class="form-group">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('alt_barcode_enabled', '1', old('alt_barcode_enabled', $setting->alt_barcode_enabled),array( 'aria-label'=>'alt_barcode_enabled')) }} <input type="checkbox" name="alt_barcode_enabled" value="1" @checked(old('alt_barcode_enabled', $setting->alt_barcode_enabled)) aria-label="alt_barcode_enabled"/>
{{ trans('admin/settings/general.display_alt_barcode') }} {{ trans('admin/settings/general.display_alt_barcode') }}
</label> </label>
</div> </div>
@@ -189,7 +189,7 @@
<div class="form-group"> <div class="form-group">
<div class="col-md-9 col-md-offset-3"> <div class="col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('qr_code', '1', old('qr_code', $setting->qr_code),array('aria-label'=>'qr_code')) }} <input type="checkbox" name="qr_code" value="1" @checked(old('qr_code', $setting->qr_code)) aria-label="qr_code" />
{{ trans('admin/settings/general.display_qr') }} {{ trans('admin/settings/general.display_qr') }}
</label> </label>
</div> </div>
@@ -480,23 +480,23 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('labels_display_name', '1', old('labels_display_name', $setting->labels_display_name),['class' => 'minimal', 'aria-label'=>'labels_display_name']) }} <input type="checkbox" name="labels_display_name" value="1" @checked(old('labels_display_name', $setting->labels_display_name)) aria-label="labels_display_name" />
{{ trans('admin/hardware/form.name') }} {{ trans('admin/hardware/form.name') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('labels_display_serial', '1', old('labels_display_serial', $setting->labels_display_serial),['class' => 'minimal', 'aria-label'=>'labels_display_serial']) }} <input type="checkbox" name="labels_display_serial" value="1" @checked(old('labels_display_serial', $setting->labels_display_serial)) aria-label="labels_display_serial" />
{{ trans('admin/hardware/form.serial') }} {{ trans('admin/hardware/form.serial') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('labels_display_tag', '1', old('labels_display_tag', $setting->labels_display_tag),['class' => 'minimal', 'aria-label'=>'labels_display_tag']) }} <input type="checkbox" name="labels_display_tag" value="1" @checked(old('labels_display_tag', $setting->labels_display_tag)) aria-label="labels_display_tag" />
{{ trans('admin/hardware/form.tag') }} {{ trans('admin/hardware/form.tag') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('labels_display_model', '1', old('labels_display_model', $setting->labels_display_model),['class' => 'minimal', 'aria-label'=>'labels_display_model']) }} <input type="checkbox" name="labels_display_model" value="1" @checked(old('labels_display_model', $setting->labels_display_model)) aria-label="labels_display_model" />
{{ trans('admin/hardware/form.model') }} {{ trans('admin/hardware/form.model') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('labels_display_company_name', '1', old('labels_display_company_name', $setting->labels_display_company_name),['class' => 'minimal', 'aria-label'=>'labels_display_company_name']) }} <input type="checkbox" name="labels_display_company_name" value="1" @checked(old('labels_display_company_name', $setting->labels_display_company_name)) aria-label="labels_display_company_name"/>
{{ trans('admin/companies/table.name') }} {{ trans('admin/companies/table.name') }}
</label> </label>
</div> <!--/.col-md-9--> </div> <!--/.col-md-9-->

View File

@@ -75,7 +75,7 @@
<div class="col-md-8"> <div class="col-md-8">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('ldap_enabled', '1', old('ldap_enabled', $setting->ldap_enabled)) }} <input type="checkbox" name="ldap_enabled" value="1" id="ldap_enabled" @checked(old('ldap_enabled', $setting->ldap_enabled)) />
{{ trans('admin/settings/general.ldap_enabled') }} {{ trans('admin/settings/general.ldap_enabled') }}
</label> </label>
@@ -96,7 +96,7 @@
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('is_ad', '1', old('is_ad', $setting->is_ad)) }} <input type="checkbox" name="is_ad" value="1" id="is_ad" @checked(old('is_ad', $setting->is_ad))/>
{{ trans('admin/settings/general.is_ad') }} {{ trans('admin/settings/general.is_ad') }}
</label> </label>
@error('is_ad') @error('is_ad')
@@ -122,7 +122,7 @@
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('ldap_pw_sync', '1', old('ldap_pw_sync', $setting->ldap_pw_sync)) }} <input type="checkbox" name="ldap_pw_sync" value="1" id="ldap_pw_sync" @checked(old('ldap_pw_sync', $setting->ldap_pw_sync)) />
{{ trans('general.yes') }} {{ trans('general.yes') }}
</label> </label>
@@ -255,7 +255,7 @@
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('ldap_tls', '1', old('ldap_tls', $setting->ldap_tls)) }} <input type="checkbox" name="ldap_tls" value="1" id="ldap_tls" @checked(old('ldap_tls', $setting->ldap_tls)) />
{{ trans('admin/settings/general.ldap_tls_help') }} {{ trans('admin/settings/general.ldap_tls_help') }}
</label> </label>
@error('ldap_tls') @error('ldap_tls')
@@ -281,7 +281,7 @@
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('ldap_server_cert_ignore', '1', old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore)) }} <input type="checkbox" name="ldap_server_cert_ignore" value="1" id="ldap_server_cert_ignore" @checked(old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore)) />
{{ trans('admin/settings/general.ldap_server_cert_ignore') }} {{ trans('admin/settings/general.ldap_server_cert_ignore') }}
</label> </label>
@error('ldap_server_cert_ignore') @error('ldap_server_cert_ignore')
@@ -554,6 +554,32 @@
</div> </div>
</div> </div>
<!-- LDAP invert active flag -->
<div class="form-group">
<div class="col-md-3">
{{ Form::label('ldap_invert_active_flag', trans('admin/settings/general.ldap_invert_active_flag')) }}
</div>
<div class="col-md-8">
<label class="form-control">
<input type="checkbox" name="ldap_invert_active_flag" value="1" id="ldap_invert_active_flag" @checked(old('ldap_invert_active_flag', $setting->ldap_invert_active_flag)) />
<p class="help-block">{!! trans('admin/settings/general.ldap_invert_active_flag_help') !!}</p>
</label>
@error('ldap_invert_active_flag')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
<!-- LDAP emp number --> <!-- LDAP emp number -->
<div class="form-group {{ $errors->has('ldap_emp_num') ? 'error' : '' }}"> <div class="form-group {{ $errors->has('ldap_emp_num') ? 'error' : '' }}">
<div class="col-md-3"> <div class="col-md-3">

View File

@@ -52,7 +52,7 @@
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}"> <label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}">
{{ Form::checkbox('saml_enabled', '1', old('saml_enabled', $setting->saml_enabled), ['class' => config('app.lock_passwords') === true ? 'disabled ': '', config('app.lock_passwords') === true ? 'disabled ': '', ]) }} <input type="checkbox" name="saml_enabled" value="1" @checked(old('saml_enabled', $setting->saml_enabled)) @disabled(config('app.lock_passwords')) @class(['disabled' => config('app.lock_passwords')])/>
{{ trans('admin/settings/general.saml_enabled') }} {{ trans('admin/settings/general.saml_enabled') }}
</label> </label>
@@ -146,7 +146,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}"> <label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}">
{{ Form::checkbox('saml_forcelogin', '1', old('saml_forcelogin', $setting->saml_forcelogin),['class' => $setting->demoMode, $setting->demoMode]) }} <input type="checkbox" name="saml_forcelogin" value="1" @checked(old('saml_forcelogin', $setting->saml_forcelogin)) @disabled(config('app.lock_passwords')) @class(['disabled' => config('app.lock_passwords')]) />
{{ trans('admin/settings/general.saml_forcelogin') }} {{ trans('admin/settings/general.saml_forcelogin') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.saml_forcelogin_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.saml_forcelogin_help') }}</p>
@@ -162,7 +162,7 @@
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}"> <label class="form-control{{ config('app.lock_passwords') === true ? ' form-control--disabled': '' }}">
{{ Form::checkbox('saml_slo', '1', old('saml_slo', $setting->saml_slo),['class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }} <input type="checkbox" name="saml_slo" value="1" @checked(old('saml_slo', $setting->saml_slo)) @disabled(config('app.lock_passwords')) @class(['minimal', 'disabled' => config('app.lock_passwords')])/>
{{ trans('admin/settings/general.saml_slo') }} {{ trans('admin/settings/general.saml_slo') }}
</label> </label>
<p class="help-block">{{ trans('admin/settings/general.saml_slo_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.saml_slo_help') }}</p>

View File

@@ -83,27 +83,27 @@
<div class="col-md-9"> <div class="col-md-9">
<label class="form-control"> <label class="form-control">
<span class="sr-only">{{ trans('admin/settings/general.pwd_secure_uncommon') }}</span> <span class="sr-only">{{ trans('admin/settings/general.pwd_secure_uncommon') }}</span>
{{ Form::checkbox('pwd_secure_uncommon', '1', old('pwd_secure_uncommon', $setting->pwd_secure_uncommon),array( 'aria-label'=>'pwd_secure_uncommon')) }} <input type="checkbox" name="pwd_secure_uncommon" value="1" @checked(old('pwd_secure_uncommon', $setting->pwd_secure_uncommon)) aria-label="pwd_secure_uncommon"/>
{{ trans('admin/settings/general.pwd_secure_uncommon') }} {{ trans('admin/settings/general.pwd_secure_uncommon') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox("pwd_secure_complexity['disallow_same_pwd_as_user_fields']", 'disallow_same_pwd_as_user_fields', old('disallow_same_pwd_as_user_fields', strpos($setting->pwd_secure_complexity, 'disallow_same_pwd_as_user_fields')!==false), array('aria-label'=>'pwd_secure_complexity')) }} <input type="checkbox" name="pwd_secure_complexity['disallow_same_pwd_as_user_fields']" value="disallow_same_pwd_as_user_fields" @checked(old('disallow_same_pwd_as_user_fields', strpos($setting->pwd_secure_complexity, 'disallow_same_pwd_as_user_fields')!==false)) aria-label="pwd_secure_complexity"/>
{{ trans('admin/settings/general.pwd_secure_complexity_disallow_same_pwd_as_user_fields') }} {{ trans('admin/settings/general.pwd_secure_complexity_disallow_same_pwd_as_user_fields') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox("pwd_secure_complexity['letters']", 'letters', old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'letters')!==false), array('aria-label'=>'pwd_secure_complexity')) }} <input type="checkbox" name="pwd_secure_complexity['letters']" value="letters" @checked(old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'letters')!==false)) aria-label="pwd_secure_complexity"/>
{{ trans('admin/settings/general.pwd_secure_complexity_letters') }} {{ trans('admin/settings/general.pwd_secure_complexity_letters') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox("pwd_secure_complexity['numbers']", 'numbers', old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'numbers')!==false), array('aria-label'=>'pwd_secure_complexity')) }} <input type="checkbox" name="pwd_secure_complexity['numbers']" value="numbers" @checked(old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'numbers')!==false)) aria-label="pwd_secure_complexity"/>
{{ trans('admin/settings/general.pwd_secure_complexity_numbers') }} {{ trans('admin/settings/general.pwd_secure_complexity_numbers') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox("pwd_secure_complexity['symbols']", 'symbols', old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'symbols')!==false), array('aria-label'=>'pwd_secure_complexity')) }} <input type="checkbox" name="pwd_secure_complexity['symbols']" value="symbols" @checked(old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'symbols')!==false)) aria-label="pwd_secure_complexity"/>
{{ trans('admin/settings/general.pwd_secure_complexity_symbols') }} {{ trans('admin/settings/general.pwd_secure_complexity_symbols') }}
</label> </label>
<label class="form-control"> <label class="form-control">
{{ Form::checkbox("pwd_secure_complexity['case_diff']", 'case_diff', old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'case_diff')!==false), array('aria-label'=>'pwd_secure_complexity')) }} <input type="checkbox" name="pwd_secure_complexity['case_diff']" value="case_diff" @checked(old('pwd_secure_uncommon', strpos($setting->pwd_secure_complexity, 'case_diff')!==false)) aria-label="pwd_secure_complexity"/>
{{ trans('admin/settings/general.pwd_secure_complexity_case_diff') }} {{ trans('admin/settings/general.pwd_secure_complexity_case_diff') }}
</label> </label>
@@ -129,7 +129,7 @@
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p> <p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else @else
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('login_remote_user_enabled', '1', old('login_remote_user_enabled', $setting->login_remote_user_enabled),array('aria-label'=>'login_remote_user')) }} <input type="checkbox" name="login_remote_user_enabled" value="1" @checked(old('login_remote_user_enabled', $setting->login_remote_user_enabled)) aria-label="login_remote_user"/>
<label for="login_remote_user_enabled">{{ trans('admin/settings/general.login_remote_user_enabled_text') }}</label> <label for="login_remote_user_enabled">{{ trans('admin/settings/general.login_remote_user_enabled_text') }}</label>
</label> </label>
@@ -158,7 +158,7 @@
<!-- Disable other logins mechanism --> <!-- Disable other logins mechanism -->
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('login_common_disabled', '1', old('login_common_disabled', $setting->login_common_disabled),array('aria-label'=>'login_common_disabled')) }} <input type="checkbox" name="login_common_disabled" value="1" @checked(old('login_common_disabled', $setting->login_common_disabled)) aria-label="login_common_disabled"/>
{{ trans('admin/settings/general.login_common_disabled_text') }} {{ trans('admin/settings/general.login_common_disabled_text') }}
</label> </label>
{!! $errors->first('login_common_disabled', '<span class="alert-msg" aria-hidden="true">:message</span>') !!} {!! $errors->first('login_common_disabled', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}

View File

@@ -42,7 +42,7 @@
<div class="form-group"> <div class="form-group">
<div class=" col-md-9 col-md-offset-3"> <div class=" col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_department_id', '1', false) }} <input type="checkbox" name="null_department_id" value="1" />
{{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.department'), 'user_count' => count($users)]) }} {{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.department'), 'user_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -55,7 +55,7 @@
<div class="form-group"> <div class="form-group">
<div class=" col-md-9 col-md-offset-3"> <div class=" col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_location_id', '1', false) }} <input type="checkbox" name="null_location_id" value="1" />
{{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.location'), 'user_count' => count($users)]) }} {{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.location'), 'user_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -69,7 +69,7 @@
<div class="form-group"> <div class="form-group">
<div class=" col-md-9 col-md-offset-3"> <div class=" col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_company_id', '1', false) }} <input type="checkbox" name="null_company_id" value="1" />
{{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.company'), 'user_count' => count($users)]) }} {{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.company'), 'user_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -83,7 +83,7 @@
<div class="form-group"> <div class="form-group">
<div class=" col-md-9 col-md-offset-3"> <div class=" col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_manager_id', '1', false) }} <input type="checkbox" name="null_manager_id" value="1" />
{{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('admin/users/table.manager'), 'user_count' => count($users)]) }} {{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('admin/users/table.manager'), 'user_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -102,7 +102,7 @@
<div class="form-group"> <div class="form-group">
<div class=" col-md-9 col-md-offset-3"> <div class=" col-md-9 col-md-offset-3">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_locale', '1', false) }} <input type="checkbox" name="null_locale" value="1" />
{{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.language'), 'user_count' => count($users)]) }} {{ trans_choice('general.set_users_field_to_null', count($users), ['field' => trans('general.language'), 'user_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -246,7 +246,7 @@
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_start_date', '1', false) }} <input type="checkbox" name="null_start_date" value="1" />
{{ trans_choice('general.set_to_null', count($users),['selection_count' => count($users)]) }} {{ trans_choice('general.set_to_null', count($users),['selection_count' => count($users)]) }}
</label> </label>
</div> </div>
@@ -264,7 +264,7 @@
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
<label class="form-control"> <label class="form-control">
{{ Form::checkbox('null_end_date', '1', false) }} <input type="checkbox" name="null_end_date" value="1" />
{{ trans_choice('general.set_to_null', count($users),['selection_count' => count($users)]) }} {{ trans_choice('general.set_to_null', count($users),['selection_count' => count($users)]) }}
</label> </label>
</div> </div>

View File

@@ -213,7 +213,7 @@
@elseif ($user->id === Auth::user()->id) @elseif ($user->id === Auth::user()->id)
<!-- disallow the user from editing their own login status --> <!-- disallow the user from editing their own login status -->
<label class="form-control form-control--disabled"> <label class="form-control form-control--disabled">
{{ Form::checkbox('activated', '1', old('activated', $user->activated), ['disabled' => true, 'checked'=> 'checked', 'aria-label'=>'update_real_loc']) }} <input type="checkbox" name="activated" value="1" checked disabled aria-label="activated">
{{ trans('admin/users/general.activated_help_text') }} {{ trans('admin/users/general.activated_help_text') }}
</label> </label>
<p class="text-warning">{{ trans('admin/users/general.activated_disabled_help_text') }}</p> <p class="text-warning">{{ trans('admin/users/general.activated_disabled_help_text') }}</p>
@@ -259,7 +259,7 @@
<div class="col-md-8 col-md-offset-3"> <div class="col-md-8 col-md-offset-3">
<label class="form-control form-control--disabled"> <label class="form-control form-control--disabled">
{{ Form::checkbox('email_user', '1', old('email_user'), ['id' => "email_user_checkbox", 'aria-label'=>'email_user']) }} <input type="checkbox" name="email_user" value="1" id="email_user_checkbox" @checked(old('email_user')) aria-label="email_user">
{{ trans('admin/users/general.email_user_creds_on_create') }} {{ trans('admin/users/general.email_user_creds_on_create') }}
</label> </label>

View File

@@ -43,9 +43,13 @@ class SendAcceptanceReminderTest extends TestCase
CheckoutAcceptance::factory()->pending()->create([ CheckoutAcceptance::factory()->pending()->create([
'assigned_to_id' => $userA->id, 'assigned_to_id' => $userA->id,
]); ]);
$headers = ['ID', 'Name'];
$rows = [
[$userA->id, $userA->present()->fullName()],
];
$this->artisan('snipeit:acceptance-reminder') $this->artisan('snipeit:acceptance-reminder')
->expectsOutput($userA->present()->fullName().' has no email address.') ->expectsOutput("The following users do not have an email address:")
->expectsTable($headers, $rows)
->assertExitCode(0); ->assertExitCode(0);
Mail::assertNotSent(UnacceptedAssetReminderMail::class); Mail::assertNotSent(UnacceptedAssetReminderMail::class);

View File

@@ -45,4 +45,24 @@ class ImportTest extends TestCase
]); ]);
$this->assertEquals($evil_string, $results->json()['files'][0]['first_row'][0]); $this->assertEquals($evil_string, $results->json()['files'][0]['first_row'][0]);
} }
public function testStoreInternationalAssetMisparse(): void
{
$evil_maker = function ($arr) {
$results = '';
foreach ($arr as $thing) {
$results .= chr($thing);
}
return $results;
};
// 0xC0 makes it 'not unicode', and 0xFF makes it 'likely WINDOWS-1251', and 0x98 at the end makes it 'not-valid-Windows-1251'
$evil_content = $evil_maker([0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x98]);
$this->actingAsForApi(User::factory()->superuser()->create());
$results = $this->post(route('api.imports.store'), ['files' => [UploadedFile::fake()->createWithContent("myname.csv", $evil_content)]])
->assertStatus(422)
->assertStatusMessageIs('error')
->assertMessagesAre(trans('admin/hardware/message.import.transliterate_failure', ["encoding" => "windows-1251"]));
}
} }

View File

@@ -10,7 +10,10 @@ class CategoryEditFormTest extends TestCase
{ {
public function testTheComponentCanRender() public function testTheComponentCanRender()
{ {
Livewire::test(CategoryEditForm::class)->assertStatus(200); Livewire::test(CategoryEditForm::class, [
'sendCheckInEmail' => true,
'useDefaultEula' => true,
])->assertStatus(200);
} }
public function testSendEmailCheckboxIsCheckedOnLoadWhenSendEmailIsExistingSetting() public function testSendEmailCheckboxIsCheckedOnLoadWhenSendEmailIsExistingSetting()

View File

@@ -0,0 +1,108 @@
<?php
namespace Tests\Feature\Notifications\Email;
use App\Mail\CheckoutAssetMail;
use App\Models\CheckoutAcceptance;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
class AssetAcceptanceReminderTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
Mail::fake();
}
public function testMustHavePermissionToSendReminder()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
$userWithoutPermission = User::factory()->create();
$this->actingAs($userWithoutPermission)
->post($this->routeFor($checkoutAcceptance))
->assertForbidden();
Mail::assertNotSent(CheckoutAssetMail::class);
}
public function testReminderNotSentIfAcceptanceDoesNotExist()
{
$this->actingAs(User::factory()->canViewReports()->create())
->post(route('reports/unaccepted_assets_sent_reminder', [
'acceptance_id' => 999999,
]));
Mail::assertNotSent(CheckoutAssetMail::class);
}
public function testReminderNotSentIfAcceptanceAlreadyAccepted()
{
$checkoutAcceptanceAlreadyAccepted = CheckoutAcceptance::factory()->accepted()->create();
$this->actingAs(User::factory()->canViewReports()->create())
->post($this->routeFor($checkoutAcceptanceAlreadyAccepted));
Mail::assertNotSent(CheckoutAssetMail::class);
}
public static function CheckoutAcceptancesToUsersWithoutEmailAddresses()
{
yield 'User with null email address' => [
function () {
return CheckoutAcceptance::factory()
->pending()
->forAssignedTo(['email' => null])
->create();
}
];
yield 'User with empty string email address' => [
function () {
return CheckoutAcceptance::factory()
->pending()
->forAssignedTo(['email' => ''])
->create();
}
];
}
#[DataProvider('CheckoutAcceptancesToUsersWithoutEmailAddresses')]
public function testUserWithoutEmailAddressHandledGracefully($callback)
{
$checkoutAcceptance = $callback();
$this->actingAs(User::factory()->canViewReports()->create())
->post($this->routeFor($checkoutAcceptance))
// check we didn't crash...
->assertRedirect();
Mail::assertNotSent(CheckoutAssetMail::class);
}
public function testReminderIsSentToUser()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
$this->actingAs(User::factory()->canViewReports()->create())
->post($this->routeFor($checkoutAcceptance))
->assertRedirect(route('reports/unaccepted_assets'));
Mail::assertSent(CheckoutAssetMail::class, 1);
Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) use ($checkoutAcceptance) {
return $mail->hasTo($checkoutAcceptance->assignedTo->email)
&& $mail->hasSubject(trans('mail.unaccepted_asset_reminder'));
});
}
private function routeFor(CheckoutAcceptance $checkoutAcceptance): string
{
return route('reports/unaccepted_assets_sent_reminder', [
'acceptance_id' => $checkoutAcceptance->id,
]);
}
}

View File

@@ -4,6 +4,7 @@ namespace Tests\Feature\Notifications\Email;
use App\Mail\ExpiringAssetsMail; use App\Mail\ExpiringAssetsMail;
use App\Mail\ExpiringLicenseMail; use App\Mail\ExpiringLicenseMail;
use App\Mail\SendUpcomingAuditMail;
use App\Models\Asset; use App\Models\Asset;
use App\Models\License; use App\Models\License;
use App\Models\Setting; use App\Models\Setting;
@@ -88,4 +89,38 @@ class ExpiringAlertsNotificationTest extends TestCase
return $mail->licenses->contains($expiredLicense) || $mail->licenses->contains($notExpiringLicense); return $mail->licenses->contains($expiredLicense) || $mail->licenses->contains($notExpiringLicense);
}); });
} }
public function testAuditWarningThresholdEmailNotification()
{
$this->markIncompleteIfSqlite();
Mail::fake();
$this->settings->enableAlertEmail('admin@example.com');
$this->settings->setAuditWarningDays(15);
$alert_email = Setting::first()->alert_email;
$upcomingAuditableAsset = Asset::factory()->create([
'next_audit_date' => now()->addDays(14)->format('Y-m-d'),
'deleted_at' => null,
]);
$overDueForAuditableAsset = Asset::factory()->create([
'next_audit_date' => now()->subDays(1)->format('Y-m-d'),
'deleted_at' => null,
]);
$notAuditableAsset = Asset::factory()->create([
'next_audit_date' => now()->addDays(30)->format('Y-m-d'),
'deleted_at' => null,
]);
$this->artisan('snipeit:upcoming-audits')->assertExitCode(0);
Mail::assertSent(SendUpcomingAuditMail::class, function($mail) use ($alert_email, $upcomingAuditableAsset, $overDueForAuditableAsset) {
return $mail->hasTo($alert_email) && ($mail->assets->contains($upcomingAuditableAsset) && $mail->assets->contains($overDueForAuditableAsset));
});
Mail::assertNotSent(SendUpcomingAuditMail::class, function($mail) use ($alert_email, $notAuditableAsset) {
return $mail->hasTo($alert_email) && $mail->assets->contains($notAuditableAsset);
});
}
} }

View File

@@ -32,6 +32,12 @@ class Settings
'alert_threshold' => $days, 'alert_threshold' => $days,
]); ]);
} }
public function setAuditWarningDays(int $days): Settings
{
return $this->update([
'audit_warning_days' => $days,
]);
}
public function disableAlertEmail(): Settings public function disableAlertEmail(): Settings
{ {
return $this->update([ return $this->update([

View File

@@ -7,9 +7,7 @@ use App\Models\Asset;
use App\Models\AssetModel; use App\Models\AssetModel;
use App\Models\Category; use App\Models\Category;
use Carbon\Carbon; use Carbon\Carbon;
use App\Notifications\CheckoutAssetNotification;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase; use Tests\TestCase;
class NotificationTest extends TestCase class NotificationTest extends TestCase
@@ -33,8 +31,8 @@ class NotificationTest extends TestCase
Mail::fake(); Mail::fake();
$asset->checkOut($user, $admin->id); $asset->checkOut($user, $admin->id);
Mail::assertSent(CheckoutAssetMail::class, function ($mail) use ($user) { Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) use ($user) {
return $mail->hasTo($user->email); return $mail->hasTo($user->email) && $mail->hasSubject(trans('mail.Asset_Checkout_Notification'));
}); });
} }
public function testDefaultEulaIsSentWhenSetInCategory() public function testDefaultEulaIsSentWhenSetInCategory()

View File

@@ -1,4 +1,9 @@
<?php <?php
$error_icon = "\e[91m✘\e[0m";
$success_icon = "\e[92m√\e[0m";
$info_icon = "\e[93mⓘ\e[0m";
(PHP_SAPI !== 'cli' || isset($_SERVER['HTTP_USER_AGENT'])) && die('Access denied.'); (PHP_SAPI !== 'cli' || isset($_SERVER['HTTP_USER_AGENT'])) && die('Access denied.');
// We define this because we can't reliably use file_get_contents because some // We define this because we can't reliably use file_get_contents because some
@@ -25,7 +30,7 @@ function url_get_contents ($Url) {
$output = curl_exec($ch); $output = curl_exec($ch);
curl_close($ch); curl_close($ch);
if ($output === false) { if ($output === false) {
print("Error retrieving PHP requirements!\n"); print("\e[91mError retrieving PHP requirements!\e[39m\n");
print("Error was: " . curl_error($ch) . "\n"); print("Error was: " . curl_error($ch) . "\n");
print("Try enabling allow_url_fopen in php.ini, or fixing your curl/OpenSSL setup, or try rerunning with --skip-php-compatibility-checks"); print("Try enabling allow_url_fopen in php.ini, or fixing your curl/OpenSSL setup, or try rerunning with --skip-php-compatibility-checks");
return '{}'; return '{}';
@@ -38,6 +43,7 @@ $skip_php_checks = false;
$branch = 'master'; $branch = 'master';
$branch_override = false; $branch_override = false;
$no_interactive = false; $no_interactive = false;
$skip_backup = false;
// Check for branch or other overrides // Check for branch or other overrides
if ($argc > 1){ if ($argc > 1){
@@ -46,6 +52,9 @@ if ($argc > 1){
case '--skip-php-compatibility-checks': case '--skip-php-compatibility-checks':
$skip_php_checks = true; $skip_php_checks = true;
break; break;
case '--skip-backup':
$skip_backup = true;
break;
case '--branch': case '--branch':
$arg++; $arg++;
$branch = $argv[$arg]; $branch = $argv[$arg];
@@ -62,7 +71,7 @@ if ($argc > 1){
} }
} }
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "WELCOME TO THE SNIPE-IT UPGRADER! \n"; echo "WELCOME TO THE SNIPE-IT UPGRADER! \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\n\n";
echo "This script will attempt to: \n\n"; echo "This script will attempt to: \n\n";
@@ -73,7 +82,7 @@ echo "- do a git pull to bring you to the latest version \n";
echo "- run composer install to get your vendors up to date \n"; echo "- run composer install to get your vendors up to date \n";
echo "- run a backup \n"; echo "- run a backup \n";
echo "- run migrations to get your schema up to date \n"; echo "- run migrations to get your schema up to date \n";
echo "- clear out old cache settings\n\n"; echo "- clear out old cache settings\e[39m\n\n";
// Fetching most current upgrade requirements from github. Read more here: https://github.com/snipe/snipe-it/pull/14127 // Fetching most current upgrade requirements from github. Read more here: https://github.com/snipe/snipe-it/pull/14127
@@ -82,29 +91,29 @@ $upgrade_requirements_raw = url_get_contents($remote_requirements_file);
$upgrade_requirements = json_decode($upgrade_requirements_raw, true); $upgrade_requirements = json_decode($upgrade_requirements_raw, true);
if (! $upgrade_requirements) { if (! $upgrade_requirements) {
if(!$skip_php_checks){ if(!$skip_php_checks){
echo "\nERROR: Failed to retrieve remote requirements from $remote_requirements_file\n\n"; echo "\n\e[91mERROR: Failed to retrieve remote requirements from $remote_requirements_file \e[39m\n\n";
if ($branch_override){ if ($branch_override){
echo "NOTE: You passed a custom branch: $branch\n"; echo "\e[93mNOTE: You passed a custom branch: $branch\n";
echo " If the above URL doesn't work, that may be why. Please check you branch spelling/existence\n\n"; echo "If the above URL doesn't work, that may be why. Please check the branch spelling/existence\e[39m\n\n";
} }
if (json_last_error()) { if (json_last_error()) {
print "JSON DECODE ERROR DETECTED:\n"; print "\e[91mJSON DECODE ERROR DETECTED:\n";
print json_last_error_msg() . "\n\n"; print json_last_error_msg() . "\n\n";
print "Raw curl output:\n"; print "Raw curl output:\n";
print $upgrade_requirements_raw . "\n\n"; print $upgrade_requirements_raw . "\e[39m\n\n";
} }
echo "We suggest correcting this, but if you can't, please verify that your requirements conform to those at that url.\n\n"; echo "\e[93mWe suggest correcting this, but if you can't, please verify that your requirements conform to those at that url.\n\n";
echo " -- DANGER -- DO AT YOUR OWN RISK --\n"; echo "\e[91m-- DANGER -- DO AT YOUR OWN RISK --\n";
echo " IF YOU ARE SURE, re-run this script with --skip-php-compatibility-checks to skip this check.\n"; echo "IF YOU ARE SURE, re-run this script with --skip-php-compatibility-checks to skip this check.\n";
echo " -- DANGER -- THIS COULD BREAK YOUR INSTALLATION"; echo "-- DANGER -- THIS COULD BREAK YOUR INSTALLATION\e[39m\n\n";
die("Exiting.\n\n"); die("Aborting upgrade.\n\n");
} }
echo "NOTICE: Unable to fetch upgrade requirements, but continuing because you passed --skip-php-compatibility-checks...\n"; echo "\e[93mNOTICE: Unable to fetch upgrade requirements, but continuing because you passed --skip-php-compatibility-checks...e[39m\n";
} }
echo "Launching using branch: $branch\n"; echo "Launching using branch: $branch\e[39m\n";
if($upgrade_requirements){ if($upgrade_requirements){
$php_min_works = $upgrade_requirements['php_min_version']; $php_min_works = $upgrade_requirements['php_min_version'];
@@ -134,22 +143,22 @@ if ((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') || (!function_exists('posix_get
$username = $pwu_data['name']; $username = $pwu_data['name'];
if (($username=='root') || ($username=='admin')) { if (($username=='root') || ($username=='admin')) {
die("\nERROR: This script should not be run as root/admin. Exiting.\n\n"); die("\n".$error_icon."ERROR: This script should not be run as root/admin. Exiting.\n\n");
} }
} }
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 1: Checking .env file: \n"; echo "STEP 1: Checking .env file: \n";
echo "- Your .env is located at ".getcwd()."/.env \n"; echo "- Your .env is located at ".getcwd()."/.env \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\\n\n";
// Check the .env looks ok // Check the .env looks ok
$env = file('.env'); $env = file('.env');
if (! $env){ if (! $env){
echo "\n!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n"; echo "\n\e[91m!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n";
echo "Your .env file doesn't seem to exist in this directory or isn't readable! Please look into that.\n"; echo "Your .env file doesn't seem to exist in this directory or isn't readable! Please look into that.\n";
exit(1); exit(1);
} }
@@ -199,32 +208,32 @@ foreach ($env as $line_num => $line) {
if ($env_key == 'APP_KEY') { if ($env_key == 'APP_KEY') {
if (($env_value=='') || (strlen($env_value) < 20)) { if (($env_value=='') || (strlen($env_value) < 20)) {
$env_bad .= " APP_KEY ERROR in your .env on line #'.{$show_line_num}.': Your APP_KEY should not be blank. Run `php artisan key:generate` to generate one.\n"; $env_bad .= $error_icon." APP_KEY ERROR in your .env on line #'.{$show_line_num}.': Your APP_KEY should not be blank. Run `php artisan key:generate` to generate one.\n";
} else { } else {
$env_good .= " Your APP_KEY is not blank. \n"; $env_good .= $success_icon." Your APP_KEY is not blank. \n";
} }
} }
if ($env_key == 'APP_URL') { if ($env_key == 'APP_URL') {
if (($env_value!="null") && ($env_value!="")) { if (($env_value!="null") && ($env_value!="")) {
$env_good .= ' Your APP_URL is not null or blank. It is set to '.$env_value."\n"; $env_good .= $success_icon.' Your APP_URL is not null or blank. It is set to '.$env_value."\n";
if (!str_begins(trim($env_value), 'http://') && (!str_begins($env_value, 'https://'))) { if (!str_begins(trim($env_value), 'http://') && (!str_begins($env_value, 'https://'))) {
$env_bad .= ' APP_URL ERROR in your .env on line #'.$show_line_num.': Your APP_URL should start with https:// or http://!! It is currently set to: '.$env_value; $env_bad .= $error_icon.' APP_URL ERROR in your .env on line #'.$show_line_num.': Your APP_URL should start with https:// or http://!! It is currently set to: '.$env_value;
} else { } else {
$env_good .= ' Your APP_URL is set to '.$env_value.' and starts with the protocol (https:// or http://)'."\n"; $env_good .= $success_icon.' Your APP_URL is set to '.$env_value.' and starts with the protocol (https:// or http://)'."\n";
} }
if (str_ends(trim($env_value), "/")) { if (str_ends(trim($env_value), "/")) {
$env_bad .= ' APP_URL ERROR in your .env on line #'.$show_line_num.': Your APP_URL should NOT end with a trailing slash. It is currently set to: '.$env_value; $env_bad .= $error_icon.' APP_URL ERROR in your .env on line #'.$show_line_num.': Your APP_URL should NOT end with a trailing slash. It is currently set to: '.$env_value;
} else { } else {
$env_good .= ' Your APP_URL ('.$env_value.') does not have a trailing slash.'."\n"; $env_good .= $success_icon.' Your APP_URL ('.$env_value.') does not have a trailing slash.'."\n";
} }
} else { } else {
$env_bad .= " APP_URL ERROR in your .env on line #".$show_line_num.": Your APP_URL CANNOT be set to null or left blank.\n"; $env_bad .= $error_icon." APP_URL ERROR in your .env on line #".$show_line_num.": Your APP_URL CANNOT be set to null or left blank.\n";
} }
} }
@@ -238,34 +247,34 @@ echo $env_good;
if ($env_bad !='') { if ($env_bad !='') {
echo "!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n"; echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n";
echo "Your .env file is misconfigured. Upgrade cannot continue.\n"; echo "\e[91mYour .env file is misconfigured. Upgrade cannot continue.\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\n\n";
echo $env_bad; echo $env_bad;
echo "\n\n--------------------------------------------------------\n"; echo "\n\n--------------------------------------------------------\n";
echo "!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n"; echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
echo "Please correct the issues above in ".getcwd()."/.env and try again.\n"; echo "\e[91mPlease correct the issues above in ".getcwd()."/.env and try again.\n";
echo "--------------------------------------------------------\n"; echo "\e[91m--------------------------------------------------------\n";
exit(1); exit(1);
} }
if(!$skip_php_checks){ if(!$skip_php_checks){
echo "\n--------------------------------------------------------\n"; echo "\n\e[95m--------------------------------------------------------\n";
echo "STEP 2: Checking PHP requirements: (Required PHP >=". $php_min_works. " - <".$php_max_wontwork.") \n"; echo "STEP 2: Checking PHP requirements: (Required PHP >=". $php_min_works. " - <".$php_max_wontwork.")\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
if ((version_compare(phpversion(), $php_min_works, '>=')) && (version_compare(phpversion(), $php_max_wontwork, '<'))) { if ((version_compare(phpversion(), $php_min_works, '>=')) && (version_compare(phpversion(), $php_max_wontwork, '<'))) {
echo " Current PHP version: (" . phpversion() . ") is at least " . $php_min_works . " and less than ".$php_max_wontwork."! Continuing... \n"; echo $success_icon." Current PHP version: (" . phpversion() . ") is at least " . $php_min_works . " and less than ".$php_max_wontwork."! Continuing... \n";
echo sprintf("FYI: The php.ini used by this PHP is: %s\n\n", get_cfg_var('cfg_file_path')); echo sprintf("FYI: The php.ini used by this PHP is: %s\n\n", get_cfg_var('cfg_file_path'));
} else { } else {
echo "!!!!!!!!!!!!!!!!!!!!!!!!! PHP VERSION ERROR !!!!!!!!!!!!!!!!!!!!!!!!!\n"; echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!! PHP VERSION ERROR !!!!!!!!!!!!!!!!!!!!!!!!!\n";
echo "This version of PHP (".phpversion().") is NOT compatible with Snipe-IT.\n"; echo "This version of PHP (".phpversion().") is NOT compatible with Snipe-IT.\n";
echo "Snipe-IT requires PHP versions between ".$php_min_works." and ".$php_max_wontwork.".\n"; echo "Snipe-IT requires PHP versions between ".$php_min_works." and ".$php_max_wontwork.".\n";
echo "Please install a compatible version of PHP and re-run this script again. \n"; echo "Please install a compatible version of PHP and re-run this script again. \n";
echo "!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n"; echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
exit(1); exit(1);
} }
} }
@@ -319,7 +328,7 @@ foreach ($required_exts_array as $required_ext) {
foreach ($require_either as $require_either_value) { foreach ($require_either as $require_either_value) {
if (in_array($require_either_value, $loaded_exts_array)) { if (in_array($require_either_value, $loaded_exts_array)) {
$ext_installed .= ' '.$require_either_value." is installed!\n"; $ext_installed .= $success_icon.' '.$require_either_value." is installed!\n";
$has_one_required_ext = true; $has_one_required_ext = true;
break; break;
} }
@@ -327,20 +336,20 @@ foreach ($required_exts_array as $required_ext) {
// If no match, add it to the string for errors // If no match, add it to the string for errors
if (!$has_one_required_ext) { if (!$has_one_required_ext) {
$ext_missing .= ' MISSING PHP EXTENSION: '.str_replace("|", " OR ", $required_ext)."\n"; $ext_missing .= $error_icon.' MISSING PHP EXTENSION: '.str_replace("|", " OR ", $required_ext)."\n";
break; break;
} }
// If this isn't an either/or option, just add it to the string of errors conventionally // If this isn't an either/or option, just add it to the string of errors conventionally
} elseif (!in_array($required_ext, $recommended_exts_array)){ } elseif (!in_array($required_ext, $recommended_exts_array)){
$ext_missing .= ' MISSING PHP EXTENSION: '.$required_ext."\n"; $ext_missing .= $error_icon.' MISSING PHP EXTENSION: '.$required_ext."\n";
} else { } else {
$ext_installed .= '- '.$required_ext." is *NOT* installed, but is recommended...\n"; $ext_installed .= '- '.$required_ext." is *NOT* installed, but is recommended...\n";
} }
// The required extension string was found in the array of installed extensions - yay! // The required extension string was found in the array of installed extensions - yay!
} else { } else {
$ext_installed .= ' '.$required_ext." is installed!\n"; $ext_installed .= $success_icon.' '.$required_ext." is installed!\n";
} }
} }
@@ -351,15 +360,15 @@ if ($ext_missing!='') {
echo "--------------------------------------------------------\n"; echo "--------------------------------------------------------\n";
foreach ($loaded_exts_array as $loaded_ext) { foreach ($loaded_exts_array as $loaded_ext) {
echo "- ".$loaded_ext."\n"; echo $success_icon.' '.$loaded_ext."\n";
} }
echo "--------------------- !! ERROR !! ----------------------\n"; echo "\e[91m--------------------- !! ERROR !! ----------------------\n";
echo $ext_missing; echo $ext_missing;
echo "--------------------------------------------------------\n"; echo "\e[91m--------------------------------------------------------\n";
echo "ABORTING THE INSTALLER \n"; echo "\e[91mABORTING THE INSTALLER \n";
echo "Please install the extensions above and re-run this script.\n"; echo "\e[91mPlease install the extensions above and re-run this script.\n";
echo "--------------------------------------------------------\n"; echo "\e[91m--------------------------------------------------------\n";
exit(1); exit(1);
} else { } else {
echo $ext_installed."\n"; echo $ext_installed."\n";
@@ -368,9 +377,9 @@ if ($ext_missing!='') {
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 3: Checking directory permissions: \n"; echo "STEP 3: Checking directory permissions: \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
$writable_dirs_array = $writable_dirs_array =
@@ -396,9 +405,9 @@ $dirs_not_writable = '';
// Loop through the directories that need to be writable // Loop through the directories that need to be writable
foreach ($writable_dirs_array as $writable_dir) { foreach ($writable_dirs_array as $writable_dir) {
if (is_writable($writable_dir)) { if (is_writable($writable_dir)) {
$dirs_writable .= ' '.getcwd().'/'.$writable_dir." is writable \n"; $dirs_writable .= $success_icon.' '.getcwd().'/'.$writable_dir." is writable \n";
} else { } else {
$dirs_not_writable .= ' PERMISSIONS ERROR: '.getcwd().'/'.$writable_dir." is NOT writable\n"; $dirs_not_writable .= $error_icon.' PERMISSIONS ERROR: '.getcwd().'/'.$writable_dir." is NOT writable\n";
} }
} }
@@ -406,24 +415,24 @@ echo $dirs_writable."\n";
// Print out a useful error message // Print out a useful error message
if ($dirs_not_writable!='') { if ($dirs_not_writable!='') {
echo "--------------------------------------------------------\n"; echo "\e[91m--------------------------------------------------------\n";
echo "The following directories/files do not seem writable: \n"; echo "\eThe following directories/files do not seem writable: \n";
echo "--------------------------------------------------------\n"; echo "\e--------------------------------------------------------\e[39m\n";
echo $dirs_not_writable; echo $dirs_not_writable;
echo "--------------------- !! ERROR !! ----------------------\n"; echo "\e[91m--------------------- !! ERROR !! ----------------------\n";
echo "Please check the permissions on the directories above and re-run this script.\n"; echo "\ePlease check the permissions on the directories above and re-run this script.\n";
echo "------------------------- :( ---------------------------\n\n"; echo "\e------------------------- :( ---------------------------\e[39m\n\n";
exit(1); exit(1);
} }
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 4: Pulling latest from Git (".$branch." branch): \n"; echo "STEP 4: Pulling latest from Git (".$branch." branch): \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
$git_version = shell_exec('git --version'); $git_version = shell_exec('git --version');
if ((strpos('git version', $git_version)) === false) { if ((strpos('git version', $git_version)) === false) {
@@ -447,9 +456,9 @@ if ((strpos('git version', $git_version)) === false) {
} }
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 5: Cleaning up old cached files:\n"; echo "STEP 5: Cleaning up old cached files:\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
// Build an array of the files we generally want to delete because they // Build an array of the files we generally want to delete because they
// can cause issues with funky caching // can cause issues with funky caching
@@ -462,39 +471,28 @@ $unused_files = [
foreach ($unused_files as $unused_file) { foreach ($unused_files as $unused_file) {
if (file_exists($unused_file)) { if (file_exists($unused_file)) {
echo " Deleting ".$unused_file.". It is no longer used.\n"; echo $success_icon." Deleting ".$unused_file.". It is no longer used.\n";
@unlink($unused_file); @unlink($unused_file);
} else { } else {
echo " No ".$unused_file.", so nothing to delete.\n"; echo $success_icon." No ".$unused_file.", so nothing to delete.\n";
} }
} }
echo "\n"; echo "\n";
$config_clear = shell_exec('php artisan config:clear');
$cache_clear = shell_exec('php artisan cache:clear');
$route_clear = shell_exec('php artisan route:clear');
$view_clear = shell_exec('php artisan view:clear');
echo '-- '.$config_clear;
echo '-- '.$cache_clear;
echo '-- '.$route_clear;
echo '-- '.$view_clear;
echo "\n";
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 6: Updating composer dependencies:\n"; echo "STEP 6: Updating composer dependencies:\n";
echo "(This may take a moment.)\n"; echo "(This may take a moment.)\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
echo "-- Running the app in ".$app_environment." mode.\n"; echo "-- Running the app in ".$app_environment." mode.\n";
// Composer install // Composer install
if (file_exists('composer.phar')) { if (file_exists('composer.phar')) {
echo " Local composer.phar detected, so we'll use that.\n\n"; echo $success_icon." Local composer.phar detected, so we'll use that.\n\n";
echo "-- Updating local composer.phar\n\n"; echo "-- Updating local composer.phar\n\n";
$composer_update = shell_exec('php composer.phar self-update'); $composer_update = shell_exec('php composer.phar self-update');
echo $composer_update."\n\n"; echo $composer_update."\n\n";
// Use --no-dev only if we are in production mode. // Use --no-dev only if we are in production mode.
// This will cause errors otherwise, if the user is in develop or local for their APP_ENV // This will cause errors otherwise, if the user is in develop or local for their APP_ENV
if ($app_environment == 'production') { if ($app_environment == 'production') {
@@ -502,10 +500,9 @@ if (file_exists('composer.phar')) {
} else { } else {
$composer = shell_exec('php composer.phar install --prefer-source'); $composer = shell_exec('php composer.phar install --prefer-source');
} }
$composer_dump = shell_exec('php composer.phar dump'); $composer_dump = shell_exec('php composer.phar dump');
} else { } else {
echo "-- We couldn't find a local composer.phar. No worries, trying globally.\n"; echo "-- We couldn't find a local composer.phar. No worries, trying globally.\n";
@@ -522,72 +519,87 @@ if (file_exists('composer.phar')) {
$composer_dump = shell_exec('composer dump'); $composer_dump = shell_exec('composer dump');
} }
echo $composer_dump."\n"; echo $composer_dump."\n";
echo $composer; echo $composer;
$config_clear = shell_exec('php artisan config:clear');
$cache_clear = shell_exec('php artisan cache:clear');
$route_clear = shell_exec('php artisan route:clear');
$view_clear = shell_exec('php artisan view:clear');
echo $success_icon.' '.trim($config_clear)."\n";
echo $success_icon.' '.trim($cache_clear)."\n";
echo $success_icon.' '.trim($route_clear)."\n";
echo $success_icon.' '.trim($view_clear)."\n";
echo "\n";
echo "\e[95m--------------------------------------------------------\n";
echo "--------------------------------------------------------\n";
echo "STEP 7: Putting application into maintenance mode: \n"; echo "STEP 7: Putting application into maintenance mode: \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
exec('php artisan down', $down_results, $return_code); exec('php artisan down', $down_results, $return_code);
echo '-- ' . implode("\n", $down_results) . "\n"; echo '-- ' . implode("\n", $down_results) . "\n";
if ($return_code > 0) { if ($return_code > 0) {
die("Something went wrong with downing your site. This can't be good. Please investigate the error. Aborting!n\n"); die("Something went wrong with downing your site. This can't be good. Please investigate the error. Aborting!\n\n");
} }
unset($return_code); unset($return_code);
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 8: Backing up database: \n"; echo "STEP 8: Backing up database: \n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
$backup = exec('php artisan snipeit:backup', $backup_results, $return_code);
echo '-- ' . implode("\n", $backup_results) . "\n\n"; if (!$skip_backup) {
if ($return_code > 0) { $backup = exec('php artisan snipeit:backup', $backup_results, $return_code);
die("Something went wrong with your backup. Aborting!\n\n");
if ($return_code > 0) {
die($error_icon." Something went wrong with your backup. Aborting!\n\n");
} else {
echo '-- ' . implode("\n", $backup_results) . "\n\n";
}
unset($return_code);
} else {
echo "Upgrade was run with --skip-backup, so no backup will be run.\n\n";
} }
unset($return_code);
echo "--------------------------------------------------------\n";
echo "\e[95m--------------------------------------------------------\n";
echo "STEP 9: Migrating database:\n"; echo "STEP 9: Migrating database:\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
$migrations = shell_exec('php artisan migrate --force'); $migrations = shell_exec('php artisan migrate --force');
echo $migrations."\n"; echo $migrations."\n";
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 10: Checking for OAuth keys:\n"; echo "STEP 10: Checking for OAuth keys:\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
if ((!file_exists('storage/oauth-public.key')) || (!file_exists('storage/oauth-private.key'))) { if ((!file_exists('storage/oauth-public.key')) || (!file_exists('storage/oauth-private.key'))) {
echo "- No OAuth keys detected. Running passport install now.\n\n"; echo $info_icon." No OAuth keys detected. Running passport install now.\n\n";
$passport = shell_exec('php artisan passport:install'); $passport = shell_exec('php artisan passport:install --no-interaction');
echo $passport; echo $passport;
} else { } else {
echo " OAuth keys detected. Skipping passport install.\n\n"; echo $success_icon." OAuth keys detected. Skipping passport install.\n\n";
} }
echo "--------------------------------------------------------\n"; echo "\e[95m--------------------------------------------------------\n";
echo "STEP 11: Taking application out of maintenance mode:\n"; echo "STEP 11: Taking application out of maintenance mode:\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
$up = shell_exec('php artisan up'); $up = shell_exec('php artisan up');
echo '-- '.$up."\n"; echo $success_icon.' '.trim($up)."\n\n";
echo "---------------------- FINISHED! -----------------------\n"; echo "\e[92m---------------------- FINISHED! -----------------------\n";
echo "All done! Clear your browser cookies and re-login to use \n"; echo "All done! Clear your browser cookies and re-login to use \n";
echo "your upgraded Snipe-IT!\n"; echo "your upgraded Snipe-IT!\n";
echo "--------------------------------------------------------\n\n"; echo "--------------------------------------------------------\e[39m\n\n";
function str_begins($haystack, $needle) { function str_begins($haystack, $needle) {
@@ -597,6 +609,3 @@ function str_begins($haystack, $needle) {
function str_ends($haystack, $needle) { function str_ends($haystack, $needle) {
return (substr_compare($haystack, $needle, -strlen($needle)) === 0); return (substr_compare($haystack, $needle, -strlen($needle)) === 0);
} }