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": [
"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
SECURE_COOKIES=false
API_TOKEN_EXPIRATION_YEARS=15
BS_TABLE_STORAGE=cookieStorage
BS_TABLE_STORAGE=localStorage
BS_TABLE_DEEPLINK=true
# --------------------------------------------

View File

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

View File

@@ -65,7 +65,7 @@ jobs:
run: |
php artisan key:generate
php artisan migrate --force
php artisan passport:install
php artisan passport:install --no-interaction
chmod -R 777 storage bootstrap/cache
- 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",
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
"DOC4": "You should really just ignore it and run upgrade.php. Really",
"php_min_version": "8.1.0",
"php_min_version": "8.2.0",
"php_max_major_minor": "8.4",
"php_max_wontwork": "8.5.0",
"current_snipeit_version": "8.0"

View File

@@ -53,7 +53,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") |
| [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/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 -->
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));
if (Setting::getSettings()->is_ad === 1 && is_null($ldap_map['active_flag'])) {
$attributes[] = 'useraccountcontrol';
}
$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);
} catch (\Exception $e) {
@@ -357,9 +361,15 @@ class LdapSync extends Command
// (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_map["active_flag"]][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool) $raw_value;
$user->activated = $filter_var ?? $boolean_cast; // if filter_var() was true or false, use that. If it's null, use the $boolean_cast
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])) {
// ....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['status'] = 'success';
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
if ($user->wasChanged('location_id')) {
foreach ($user->assets as $asset) {

View File

@@ -64,28 +64,43 @@ class SendAcceptanceReminder extends Command
->groupBy(function($item) {
return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : '';
});
$no_email_list= [];
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.
// Collapsing and flattening the collection doesn't work above.
$acceptance = $unacceptedAssetGroup[0]['acceptance'];
$locale = $acceptance->assignedTo?->locale;
$email = $acceptance->assignedTo?->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();
if ($locale && $email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count))->locale($locale));
} elseif ($email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count)));
}
$count++;
}
$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;
}

View File

@@ -2,13 +2,12 @@
namespace App\Console\Commands;
use App\Mail\SendUpcomingAuditMail;
use App\Models\Asset;
use App\Models\Recipients\AlertRecipient;
use App\Models\Setting;
use App\Notifications\SendUpcomingAuditNotification;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendUpcomingAuditReport extends Command
{
@@ -48,19 +47,19 @@ class SendUpcomingAuditReport extends Command
$today = Carbon::now();
$interval_date = $today->copy()->addDays($interval);
$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');
$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');
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
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
return new AlertRecipient($item);
});
$recipients = collect(explode(',', $settings->alert_email))
->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\ReEncodeCustomFieldNames;
use App\Console\Commands\RestoreDeletedUsers;
use App\Models\Setting;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -18,12 +19,14 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
if(Setting::getSettings()->alerts_enabled === 1) {
$schedule->command('snipeit:inventory-alerts')->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('backup:clean')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
$schedule->command('auth:clear-resets')->everyFifteenMinutes();
$schedule->command('saml:clear_expired_nonces')->weekly();
}

View File

@@ -77,6 +77,18 @@ class AssetModelsController extends Controller
$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')) {
$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')) {
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?
$encoding = $detector->getEncoding($file_contents);
$reader = null;
if (strcasecmp($encoding, 'UTF-8') != 0) {
$transliterated = iconv($encoding, 'UTF-8', $file_contents);
if ($transliterated !== false) {
$tmpname = tempnam(sys_get_temp_dir(), '');
$tmpresults = file_put_contents($tmpname, $transliterated);
if ($tmpresults !== false) {
if (function_exists('iconv')) {
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
$encoding = $detector->getEncoding($file_contents);
\Log::warning("Discovered encoding: $encoding in uploaded CSV");
$reader = null;
if (strcasecmp($encoding, 'UTF-8') != 0) {
$transliterated = false;
try {
$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?
$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 ($newfile->isValid()) {
$file = $newfile;
if ($tmpresults !== false) {
$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 ($newfile->isValid()) {
$file = $newfile;
}
}
}
}
$file_contents = null; //try to save on memory, I guess?
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$file_contents = null; //try to save on memory, I guess?
try {
$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
* is one that is deployable.
* is one that is deployable or pending.
*
* 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>]
* @since [v4.0]
@@ -301,7 +303,7 @@ class StatuslabelsController extends Controller
public function checkIfDeployable($id) : string
{
$statuslabel = Statuslabel::findOrFail($id);
if ($statuslabel->getStatuslabelType() == 'deployable') {
if (($statuslabel->getStatuslabelType() == 'pending') || ($statuslabel->getStatuslabelType() == 'deployable')) {
return '1';
}

View File

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

View File

@@ -358,7 +358,11 @@ class BulkAssetsController extends Controller
* to someone/something.
*/
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.
// 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.
if (
($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;
}

View File

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

View File

@@ -266,7 +266,7 @@ class ReportsController extends Controller
$actionlogs = Actionlog::with('item', 'user', 'target', 'location', 'adminuser')
->orderBy('created_at', 'DESC')
->chunk(20, function ($actionlogs) use ($handle) {
->chunk(500, function ($actionlogs) use ($handle) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
Log::debug('Walking results: '.$executionTime);
$count = 0;
@@ -748,7 +748,7 @@ class ReportsController extends Controller
}
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'];
Log::debug('Walking results: '.$executionTime);
@@ -1175,18 +1175,13 @@ class ReportsController extends Controller
}
$email = $assetItem->assignedTo?->email;
$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) {
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)));
}
if ($email == ''){
if (is_null($email) || $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'));
}

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]);
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('passport:install');
Artisan::call('passport:install', ['--no-interaction' => true]);
}
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_version = $request->input('ldap_version', 3);
$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_email = $request->input('ldap_email');
$setting->ldap_manager = $request->input('ldap_manager');

View File

@@ -26,7 +26,7 @@ class StoreNotificationSettings extends FormRequest
return [
'alert_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',
'audit_warning_days' => 'numeric|nullable',
'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') );
} 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(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'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'));
}
} 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(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event,

View File

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

View File

@@ -20,10 +20,12 @@ class CheckoutAssetMail extends Mailable
{
use Queueable, SerializesModels;
private bool $firstTimeSending;
/**
* 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->admin = $checkedOutBy;
@@ -36,6 +38,8 @@ class CheckoutAssetMail extends Mailable
$this->last_checkout = '';
$this->expected_checkin = '';
$this->firstTimeSending = $firstTimeSending;
if ($this->item->last_checkout) {
$this->last_checkout = Helper::getFormattedDateObject($this->item->last_checkout, 'date',
false);
@@ -56,7 +60,7 @@ class CheckoutAssetMail extends Mailable
return new Envelope(
from: $from,
subject: trans('mail.Asset_Checkout_Notification'),
subject: $this->getSubject(),
);
}
@@ -107,4 +111,13 @@ class CheckoutAssetMail extends Mailable
{
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)
{
$this->count = $count;
$this->target = $checkout_info['acceptance']?->assignedTo;
$this->acceptance = $checkout_info['acceptance'];
$this->target = $checkout_info?->assignedTo;
$this->acceptance = $checkout_info;
}
/**

View File

@@ -293,16 +293,22 @@ class Actionlog extends SnipeModel
public function daysUntilNextAudit($monthInterval = 12, $asset = null)
{
$now = Carbon::now();
$last_audit_date = $this->created_at;
$next_audit = $last_audit_date->addMonth($monthInterval);
$next_audit_days = $now->diffInDays($next_audit);
$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); // this actually *modifies* the $last_audit_date
$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
if (($asset) && ($asset->next_audit_date)) {
$override_default_next = \Carbon::parse($asset->next_audit_date);
$next_audit_days = $override_default_next->diffInDays($now);
$override_default_next = Carbon::parse($asset->next_audit_date);
$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;
}

View File

@@ -234,7 +234,7 @@ class AssetModel extends SnipeModel
*/
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;
}
// 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
Schema::table(self::$table_name, function ($table) use ($custom_field) {
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug());

View File

@@ -90,12 +90,6 @@ class AssetMaintenancesPresenter extends Presenter
'searchable' => true,
'sortable' => true,
'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',
'searchable' => true,

View File

@@ -105,4 +105,17 @@ $config = [
// (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')];
// 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;

View File

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

View File

@@ -27,6 +27,10 @@ class CheckoutAcceptanceFactory extends Factory
public function configure(): static
{
return $this->afterCreating(function (CheckoutAcceptance $acceptance) {
if ($acceptance->checkoutable instanceof Asset) {
$this->createdAssociatedActionLogEntry($acceptance);
}
if ($acceptance->checkoutable instanceof Asset && $acceptance->assignedTo instanceof User) {
$acceptance->checkoutable->update([
'assigned_to' => $acceptance->assigned_to_id,
@@ -51,4 +55,23 @@ class CheckoutAcceptanceFactory extends Factory
'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>
You do not currently have any depreciations set up.
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_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_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)',
'optional_infos' => 'Optional Information',
'order_details' => 'Order Related Information',

View File

@@ -66,6 +66,7 @@ return [
'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',
'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.',
'deleted_user' => 'Deleted user',
'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',
'acceptance_deleted' => 'Acceptance request deleted',
'acceptance_request' => 'Acceptance request',

View File

@@ -42,6 +42,7 @@ return [
'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.)',
'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_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.',
@@ -69,6 +70,7 @@ return [
'favicon_size' => 'Favicons should be square images, 16x16 pixels.',
'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_placeholder' => 'Optional footer text',
'general_settings' => 'General Settings',
'general_settings_help' => 'Default EULA and more',
'generate_backup' => 'Generate Backup',
@@ -118,6 +120,8 @@ return [
'ldap_version' => 'LDAP Version',
'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_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_email' => 'LDAP Email',
'ldap_test' => 'Test LDAP',
@@ -132,6 +136,7 @@ return [
'login_user_agent' => 'User Agent',
'login_help' => 'List of attempted logins',
'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_remote_user_text' => 'Remote User login options',
'login_remote_user_enabled_text' => 'Enable Login with Remote User Header',
@@ -345,6 +350,8 @@ return [
'setup_migration_create_user' => 'Next: Create User',
'ldap_settings_link' => 'LDAP Settings Page',
'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_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>',
'label2_template' => 'Template',
@@ -378,6 +385,7 @@ return [
'database_driver' => 'Database Driver',
'bs_table_storage' => 'Table Storage',
'timezone' => 'Timezone',
'test_mail' => 'Test Mail',
'profile_edit' => 'Edit Profile',
'profile_edit_help' => 'Allow users to edit their own profiles.',
'default_avatar' => 'Upload custom default avatar',
@@ -387,6 +395,15 @@ return [
'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?',
'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 */

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',
'deleted_models' => 'Deleted Asset Models',
'deleted_users' => 'Deleted Users',
'cost_each' => ':amount each',
];

View File

@@ -26,9 +26,9 @@
<livewire:category-edit-form
:default-eula-text="$snipeSettings->default_eula_text"
:eula-text="old('eula_text', $item->eula_text)"
:require-acceptance="old('require_acceptance', $item->require_acceptance)"
:send-check-in-email="old('checkin_email', $item->checkin_email)"
:use-default-eula="old('use_default_eula', $item->use_default_eula)"
:require-acceptance="(bool) old('require_acceptance', $item->require_acceptance)"
:send-check-in-email="(bool) old('checkin_email', $item->checkin_email)"
:use-default-eula="(bool) old('use_default_eula', $item->use_default_eula)"
/>
@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>
</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>
<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">
@if ($defaultEulaText!='')
<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>
</label>
@else
<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>
</label>
@endif
@@ -39,7 +52,13 @@
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>
@@ -49,7 +68,14 @@
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
@if ($this->shouldDisplayEmailMessage)

View File

@@ -10,8 +10,15 @@
<div class="col-md-3">
@if ($fieldset_id)
<label class="form-control">
{{ 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()]) }}
<input
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') }}
</label>
@endif

View File

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

View File

@@ -29,7 +29,16 @@
data_export_options = $(this).attr('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['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
// (this is taken from Bootstrap Tables's default wrapper around jQuery Table Export)
export_options['onCellHtmlData'] = function (cell, rowIndex, colIndex, htmlData) {

View File

@@ -1,7 +1,7 @@
<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>
<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>') !!}
</div>
</div>
</div>

View File

@@ -4,7 +4,7 @@
<div class="form-group{{ $errors->has('image_delete') ? ' has-error' : '' }}">
<div class="col-md-9 col-md-offset-3">
<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') }}
{!! $errors->first('image_delete', '<span class="alert-msg">:message</span>') !!}
</label>

View File

@@ -47,7 +47,7 @@
<div class="col-md-9 col-md-offset-3">
<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
</label>
</div>

View File

@@ -35,13 +35,12 @@
<thead>
<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-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.admin') }}</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="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-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-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>
</tr>
</thead>

View File

@@ -93,152 +93,152 @@
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
@@ -248,64 +248,64 @@
<h2>{{ trans('general.checked_out_to_fields') }}: </h2>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<!-- new -->
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
@@ -318,7 +318,7 @@
@foreach ($customfields as $customfield)
<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 }}
</label>
@@ -549,13 +549,13 @@
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>

View File

@@ -68,7 +68,7 @@
@foreach ($assetsForReport as $item)
@if ($item['assetItem'])
<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']->model->category->present()->nameUrl() !!}</td>
<td>{!! $item['assetItem']->present()->modelUrl() !!}</td>
@@ -79,13 +79,18 @@
<nobr>
@if(!$item['acceptance']->trashed())
<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
<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') }}">
<i class="fa fa-repeat" aria-hidden="true"></i>
</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
<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>

View File

@@ -45,7 +45,7 @@
<div class="form-group {{ $errors->has('alerts_enabled') ? 'error' : '' }}">
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>
@@ -55,7 +55,7 @@
<div class="form-group {{ $errors->has('show_alerts_in_menu') ? 'error' : '' }}">
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>

View File

@@ -47,7 +47,7 @@
</div>
<div class="col-md-7">
<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') }}
</label>
</div>

View File

@@ -68,7 +68,9 @@
</div>
</div>
@php
$optionTypes = trans('admin/settings/general.logo_option_types');
@endphp
<!-- Branding -->
<div class="form-group {{ $errors->has('brand') ? 'error' : '' }}">
@@ -76,8 +78,13 @@
<label for="brand">{{ trans('admin/settings/general.web_brand') }}</label>
</div>
<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 ;')) !!}
{!! $errors->first('brand', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<select name="brand" id="brand" class="form-control select2 minimumResultsForSearch" style="width: 150px;">
@foreach($optionTypes as $value => $label)
<option value="{{ $value }}" {{ old('brand', $setting->brand) == $value ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
</div>
</div>
@@ -135,7 +142,7 @@
<div class="col-md-9 col-md-offset-3">
<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>
</label>
<p class="help-block">
@@ -152,7 +159,7 @@
</div>
<div class="col-md-9">
<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') }}
{!! $errors->first('load_remote', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label>
@@ -172,7 +179,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
@@ -187,7 +194,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.show_url_in_emails_help_text') }}</p>
@@ -228,7 +235,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.allow_user_skin_help_text') }}</p>
@@ -272,10 +279,10 @@
</div>
<div class="col-md-9">
@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>
@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
@@ -291,10 +298,10 @@
</div>
<div class="col-md-9">
@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>
@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
<p class="help-block">{{ trans('admin/settings/general.version_footer_help') }}</p>

View File

@@ -45,7 +45,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
{!! $errors->first('full_multiple_companies_support', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -64,7 +64,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
{!! $errors->first('require_accept_signature', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -136,7 +136,7 @@
</div>
<div class="col-md-9">
<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') }}
{!! $errors->first('show_images_in_email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label>
@@ -152,7 +152,7 @@
</div>
<div class="col-md-9">
<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') }}
{!! $errors->first('unique_serial', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</label>
@@ -245,11 +245,11 @@
<div class="col-md-9">
@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>') !!}
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@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>') !!}
@endif
<p class="help-block">{!! trans('admin/settings/general.login_note_help') !!}</p>
@@ -259,7 +259,7 @@
<!-- Mail test -->
<div class="form-group">
<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 class="col-md-9" id="mailtestrow">
<a class="btn btn-default btn-sm pull-left" id="mailtest" style="margin-right: 10px;">
@@ -311,7 +311,7 @@
<div class="col-md-9">
<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') }}
</label>
{!! $errors->first('show_archived_in_list', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@@ -325,7 +325,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.show_assigned_assets_help') }}</p>
@@ -340,15 +340,19 @@
</div>
<div class="col-md-9">
<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 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 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">
{{ 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>
</div>
</div>
@@ -370,13 +374,13 @@
<!-- Depreciation method -->
<div class="form-group {{ $errors->has('depreciation_method') ? 'error' : '' }}">
<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 class="col-md-9">
{{ Form::select('depreciation_method', array(
'default' => 'Linear (default)',
'half_1' => 'Half-year convention, always applied',
'half_2' => 'Half-year convention, applied with condition',
'default' => trans('admin/depreciations/general.linear_depreciation'),
'half_1' => trans('admin/depreciations/general.half_1'),
'half_2' => trans('admin/depreciations/general.half_2'),
), old('username_format', $setting->depreciation_method), ['class' =>'select2', 'style' => 'width: 80%']) }}
</div>
</div>

View File

@@ -54,7 +54,7 @@
<div class="col-md-8 col-md-offset-3">
<label class="form-control{{ (config('app.lock_passwords')===true) ? ' form-control--disabled': '' }}">
<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') }}
</label>
<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="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>
@@ -189,7 +189,7 @@
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<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') }}
</label>
</div>
@@ -480,23 +480,23 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
</div> <!--/.col-md-9-->

View File

@@ -75,7 +75,7 @@
<div class="col-md-8">
<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') }}
</label>
@@ -96,7 +96,7 @@
</div>
<div class="col-md-8">
<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') }}
</label>
@error('is_ad')
@@ -122,7 +122,7 @@
</div>
<div class="col-md-8">
<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') }}
</label>
@@ -255,7 +255,7 @@
</div>
<div class="col-md-8">
<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') }}
</label>
@error('ldap_tls')
@@ -281,7 +281,7 @@
</div>
<div class="col-md-8">
<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') }}
</label>
@error('ldap_server_cert_ignore')
@@ -554,6 +554,32 @@
</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 -->
<div class="form-group {{ $errors->has('ldap_emp_num') ? 'error' : '' }}">
<div class="col-md-3">

View File

@@ -52,7 +52,7 @@
<div class="col-md-9">
<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') }}
</label>
@@ -146,7 +146,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.saml_forcelogin_help') }}</p>
@@ -162,7 +162,7 @@
</div>
<div class="col-md-9">
<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') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.saml_slo_help') }}</p>

View File

@@ -83,27 +83,27 @@
<div class="col-md-9">
<label class="form-control">
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
<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') }}
</label>
@@ -129,7 +129,7 @@
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else
<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>
@@ -158,7 +158,7 @@
<!-- Disable other logins mechanism -->
<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') }}
</label>
{!! $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=" col-md-9 col-md-offset-3">
<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)]) }}
</label>
</div>
@@ -55,7 +55,7 @@
<div class="form-group">
<div class=" col-md-9 col-md-offset-3">
<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)]) }}
</label>
</div>
@@ -69,7 +69,7 @@
<div class="form-group">
<div class=" col-md-9 col-md-offset-3">
<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)]) }}
</label>
</div>
@@ -83,7 +83,7 @@
<div class="form-group">
<div class=" col-md-9 col-md-offset-3">
<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)]) }}
</label>
</div>
@@ -102,7 +102,7 @@
<div class="form-group">
<div class=" col-md-9 col-md-offset-3">
<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)]) }}
</label>
</div>
@@ -246,7 +246,7 @@
</div>
<div class="col-md-5">
<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)]) }}
</label>
</div>
@@ -264,7 +264,7 @@
</div>
<div class="col-md-5">
<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)]) }}
</label>
</div>

View File

@@ -213,7 +213,7 @@
@elseif ($user->id === Auth::user()->id)
<!-- disallow the user from editing their own login status -->
<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') }}
</label>
<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">
<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') }}
</label>

View File

@@ -43,9 +43,13 @@ class SendAcceptanceReminderTest extends TestCase
CheckoutAcceptance::factory()->pending()->create([
'assigned_to_id' => $userA->id,
]);
$headers = ['ID', 'Name'];
$rows = [
[$userA->id, $userA->present()->fullName()],
];
$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);
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]);
}
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()
{
Livewire::test(CategoryEditForm::class)->assertStatus(200);
Livewire::test(CategoryEditForm::class, [
'sendCheckInEmail' => true,
'useDefaultEula' => true,
])->assertStatus(200);
}
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\ExpiringLicenseMail;
use App\Mail\SendUpcomingAuditMail;
use App\Models\Asset;
use App\Models\License;
use App\Models\Setting;
@@ -88,4 +89,38 @@ class ExpiringAlertsNotificationTest extends TestCase
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,
]);
}
public function setAuditWarningDays(int $days): Settings
{
return $this->update([
'audit_warning_days' => $days,
]);
}
public function disableAlertEmail(): Settings
{
return $this->update([

View File

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

View File

@@ -1,4 +1,9 @@
<?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.');
// 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);
curl_close($ch);
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("Try enabling allow_url_fopen in php.ini, or fixing your curl/OpenSSL setup, or try rerunning with --skip-php-compatibility-checks");
return '{}';
@@ -38,6 +43,7 @@ $skip_php_checks = false;
$branch = 'master';
$branch_override = false;
$no_interactive = false;
$skip_backup = false;
// Check for branch or other overrides
if ($argc > 1){
@@ -46,6 +52,9 @@ if ($argc > 1){
case '--skip-php-compatibility-checks':
$skip_php_checks = true;
break;
case '--skip-backup':
$skip_backup = true;
break;
case '--branch':
$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 "--------------------------------------------------------\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 a backup \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
@@ -82,29 +91,29 @@ $upgrade_requirements_raw = url_get_contents($remote_requirements_file);
$upgrade_requirements = json_decode($upgrade_requirements_raw, true);
if (! $upgrade_requirements) {
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){
echo "NOTE: 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 "\e[93mNOTE: You passed a custom branch: $branch\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()) {
print "JSON DECODE ERROR DETECTED:\n";
print "\e[91mJSON DECODE ERROR DETECTED:\n";
print json_last_error_msg() . "\n\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 " -- 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 " -- DANGER -- THIS COULD BREAK YOUR INSTALLATION";
die("Exiting.\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 "\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 "-- DANGER -- THIS COULD BREAK YOUR INSTALLATION\e[39m\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){
$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'];
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 "- Your .env is located at ".getcwd()."/.env \n";
echo "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\\n\n";
// Check the .env looks ok
$env = file('.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";
exit(1);
}
@@ -199,32 +208,32 @@ foreach ($env as $line_num => $line) {
if ($env_key == 'APP_KEY') {
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 {
$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_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://'))) {
$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 {
$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), "/")) {
$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 {
$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 {
$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 !='') {
echo "!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n";
echo "Your .env file is misconfigured. Upgrade cannot continue.\n";
echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!!! .ENV FILE ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!\n";
echo "\e[91mYour .env file is misconfigured. Upgrade cannot continue.\n";
echo "--------------------------------------------------------\n\n";
echo $env_bad;
echo "\n\n--------------------------------------------------------\n";
echo "!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
echo "Please correct the issues above in ".getcwd()."/.env and try again.\n";
echo "--------------------------------------------------------\n";
echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
echo "\e[91mPlease correct the issues above in ".getcwd()."/.env and try again.\n";
echo "\e[91m--------------------------------------------------------\n";
exit(1);
}
if(!$skip_php_checks){
echo "\n--------------------------------------------------------\n";
echo "STEP 2: Checking PHP requirements: (Required PHP >=". $php_min_works. " - <".$php_max_wontwork.") \n";
echo "--------------------------------------------------------\n\n";
echo "\n\e[95m--------------------------------------------------------\n";
echo "STEP 2: Checking PHP requirements: (Required PHP >=". $php_min_works. " - <".$php_max_wontwork.")\n";
echo "--------------------------------------------------------\e[39m\n\n";
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'));
} 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 "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 "!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
echo "\e[91m!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n";
exit(1);
}
}
@@ -319,7 +328,7 @@ foreach ($required_exts_array as $required_ext) {
foreach ($require_either as $require_either_value) {
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;
break;
}
@@ -327,20 +336,20 @@ foreach ($required_exts_array as $required_ext) {
// If no match, add it to the string for errors
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;
}
// 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)){
$ext_missing .= ' MISSING PHP EXTENSION: '.$required_ext."\n";
$ext_missing .= $error_icon.' MISSING PHP EXTENSION: '.$required_ext."\n";
} else {
$ext_installed .= '- '.$required_ext." is *NOT* installed, but is recommended...\n";
}
// The required extension string was found in the array of installed extensions - yay!
} 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";
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 "--------------------------------------------------------\n";
echo "ABORTING THE INSTALLER \n";
echo "Please install the extensions above and re-run this script.\n";
echo "--------------------------------------------------------\n";
echo "\e[91m--------------------------------------------------------\n";
echo "\e[91mABORTING THE INSTALLER \n";
echo "\e[91mPlease install the extensions above and re-run this script.\n";
echo "\e[91m--------------------------------------------------------\n";
exit(1);
} else {
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 "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
$writable_dirs_array =
@@ -396,9 +405,9 @@ $dirs_not_writable = '';
// Loop through the directories that need to be writable
foreach ($writable_dirs_array as $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 {
$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
if ($dirs_not_writable!='') {
echo "--------------------------------------------------------\n";
echo "The following directories/files do not seem writable: \n";
echo "--------------------------------------------------------\n";
echo "\e[91m--------------------------------------------------------\n";
echo "\eThe following directories/files do not seem writable: \n";
echo "\e--------------------------------------------------------\e[39m\n";
echo $dirs_not_writable;
echo "--------------------- !! ERROR !! ----------------------\n";
echo "Please check the permissions on the directories above and re-run this script.\n";
echo "------------------------- :( ---------------------------\n\n";
echo "\e[91m--------------------- !! ERROR !! ----------------------\n";
echo "\ePlease check the permissions on the directories above and re-run this script.\n";
echo "\e------------------------- :( ---------------------------\e[39m\n\n";
exit(1);
}
echo "--------------------------------------------------------\n";
echo "\e[95m--------------------------------------------------------\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');
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 "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
// Build an array of the files we generally want to delete because they
// can cause issues with funky caching
@@ -462,39 +471,28 @@ $unused_files = [
foreach ($unused_files as $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);
} else {
echo " No ".$unused_file.", so nothing to delete.\n";
echo $success_icon." No ".$unused_file.", so nothing to delete.\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 "(This may take a moment.)\n";
echo "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
echo "-- Running the app in ".$app_environment." mode.\n";
// Composer install
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";
$composer_update = shell_exec('php composer.phar self-update');
echo $composer_update."\n\n";
// 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
if ($app_environment == 'production') {
@@ -502,10 +500,9 @@ if (file_exists('composer.phar')) {
} else {
$composer = shell_exec('php composer.phar install --prefer-source');
}
$composer_dump = shell_exec('php composer.phar dump');
} else {
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');
}
echo $composer_dump."\n";
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 "--------------------------------------------------------\n";
echo "\e[95m--------------------------------------------------------\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);
echo '-- ' . implode("\n", $down_results) . "\n";
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);
echo "--------------------------------------------------------\n";
echo "\e[95m--------------------------------------------------------\n";
echo "STEP 8: Backing up database: \n";
echo "--------------------------------------------------------\n\n";
$backup = exec('php artisan snipeit:backup', $backup_results, $return_code);
echo '-- ' . implode("\n", $backup_results) . "\n\n";
if ($return_code > 0) {
die("Something went wrong with your backup. Aborting!\n\n");
echo "--------------------------------------------------------\e[39m\n\n";
if (!$skip_backup) {
$backup = exec('php artisan snipeit:backup', $backup_results, $return_code);
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 "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
$migrations = shell_exec('php artisan migrate --force');
echo $migrations."\n";
echo "--------------------------------------------------------\n";
echo "\e[95m--------------------------------------------------------\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'))) {
echo "- No OAuth keys detected. Running passport install now.\n\n";
$passport = shell_exec('php artisan passport:install');
echo $info_icon." No OAuth keys detected. Running passport install now.\n\n";
$passport = shell_exec('php artisan passport:install --no-interaction');
echo $passport;
} 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 "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
$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 "your upgraded Snipe-IT!\n";
echo "--------------------------------------------------------\n\n";
echo "--------------------------------------------------------\e[39m\n\n";
function str_begins($haystack, $needle) {
@@ -597,6 +609,3 @@ function str_begins($haystack, $needle) {
function str_ends($haystack, $needle) {
return (substr_compare($haystack, $needle, -strlen($needle)) === 0);
}