Compare commits

..

518 Commits

Author SHA1 Message Date
snipe
3a7cef15bd Merge pull request #10423 from misilot/automated-image-build-github-actions
Automatic Building of Docker Images and Pushing to DockerHub
2021-12-13 11:32:57 -08:00
snipe
44d3a425cb Merge pull request #10422 from misilot/docker-alpine-build-automatic
Adds an automatic build for Alpine Linux based Image
2021-12-13 11:32:42 -08:00
snipe
1854d7d668 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 11:28:01 -08:00
snipe
e5f4048e9e Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-12-13 11:01:02 -08:00
Thomas Misilo
5e58f60845 Adds an automatic build for Alpine Linux based Image
This Fixes #10339, and allows for automatic building of the Alpine Linux
image, and push to docker-hub.

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

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

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

`DOCKER_USERNAME` and `DOCKER_ACCESS_TOKEN` do both need
to be added to the repository as secrets.
2021-12-13 10:39:04 -06:00
snipe
39b0dc136c Added LDAP strings back
Signed-off-by: snipe <snipe@snipe.net>
2021-12-11 10:14:35 -08:00
snipe
d0e7879c89 Merge pull request #10415 from uberbrady/fix_actionlog_memory_exhaustion
Remove 'actionlog' from the ::with() clause in the asset query API
2021-12-10 19:10:40 -08:00
Brady Wetherington
acfb41f129 Remove 'actionlog' from the ::with() clause in the asset query API 2021-12-10 18:42:56 -08:00
snipe
5381aa3fbd Merge branch 'master' of https://github.com/snipe/snipe-it 2021-12-10 15:17:45 -08:00
snipe
e20a10a6a1 Add @Haxatron as a contributor 2021-12-10 15:17:26 -08:00
snipe
949141a8e7 Merge pull request #10414 from snipe/added_model_to_accessory_report
Added model number to accessory report
2021-12-10 15:10:02 -08:00
snipe
e1bf3b50f4 Added model number to accessory report
Signed-off-by: snipe <snipe@snipe.net>
2021-12-10 15:09:29 -08:00
snipe
cf5e3da3a5 Merge pull request #10406 from Haxatron/fix-access-control
security fix
2021-12-09 11:23:35 -08:00
Haxatron
1699c09758 Update AssetModelsController.php 2021-12-09 21:42:18 +08:00
Haxatron
918e7c8dae Fix access control - https://huntr.dev/bounties/19453ef1-4d77-4cff-b7e8-1bc8f3af0862/ 2021-12-09 12:57:04 +08:00
snipe
86afe6c4b1 Cleanup slack validation
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 18:03:56 -08:00
snipe
ff97b359ad Removed form request on ajax, cleaned up some other things
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:58:46 -08:00
snipe
81b66d0039 Change validation failure to 422 to make it consistent with Laravel's default
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:54:35 -08:00
snipe
8fa690b635 Reverting form request because it doesn't seem to work (????!!)
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 17:54:15 -08:00
snipe
8c1cd87831 Added slacksettingsrequest as use statement
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:56:22 -08:00
snipe
cde2bad297 Small mods to slack jquery
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:56:05 -08:00
snipe
80d36cd72b Added slack settings request
Signed-off-by: snipe <snipe@snipe.net>
2021-12-08 15:53:05 -08:00
snipe
a579353198 Add @bestlong as a contributor 2021-11-24 20:04:26 -08:00
snipe
7360e15d4e Add @sneak-it as a contributor 2021-11-24 20:04:05 -08:00
snipe
9dc2fa61b8 Add @adamboutcher as a contributor 2021-11-24 20:03:52 -08:00
snipe
80fd49a59e Add @leitwerk-ag as a contributor 2021-11-24 20:03:40 -08:00
snipe
d30fa9199c Merge branch 'master' of https://github.com/snipe/snipe-it 2021-11-24 19:58:52 -08:00
snipe
8028b39b43 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:58:43 -08:00
snipe
ff81e6d536 Merge pull request #10361 from snipe/fixes/xss_in_accessories_checkout_notes
Escape notes in transformCheckedOutAccessory
2021-11-24 19:56:36 -08:00
snipe
00fad35c2a Escape notes in transformCheckedOutAccessory
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:54:45 -08:00
snipe
3b68a6f1be Merge pull request #10345 from leitwerk-ag/master
Fixed #10344 and #9135: don't prepand fields with a whitespace in text based export formats
2021-11-24 19:43:21 -08:00
snipe
bc91aef47d Merge pull request #10352 from adamboutcher/install_rocky
Improved Installer: Added Rocky Linux Support
2021-11-24 19:42:37 -08:00
snipe
3debe78574 Merge pull request #10350 from inietov/fixes/trim_custom_fields_names
Apply trim() function when storing Custom Fields names
2021-11-24 19:42:04 -08:00
snipe
fc1b3b31b5 Merge pull request #10358 from sneak-it/bullseye
Improved Installer: Add Debian 11 (Bullseye) install script support
2021-11-24 19:41:37 -08:00
snipe
4afd598df7 Merge pull request #10356 from bestlong/fix_modal_dialog_html_typo
fix modal-title html tag unpaired.
2021-11-24 19:39:58 -08:00
snipe
d1d3f893ac Merge pull request #10360 from snipe/fixes/escaped_characters_on_asset_create_checkout
Removed escaping on input save for asset checkout on creation
2021-11-24 19:20:54 -08:00
snipe
830d07f84f Removed escaping on input save for asset checkout on creation
Signed-off-by: snipe <snipe@snipe.net>
2021-11-24 19:19:32 -08:00
snipe
0e30b9aef7 Merge pull request #10355 from inietov/fixes/customfields_with_date_format_doesnt_display_default_value_master
Fixes Default Values - Date not applying for master branch
2021-11-24 18:22:02 -08:00
sneaK
b937aedc30 Add Debian 11 (Bullseye) install script support 2021-11-24 10:24:05 -05:00
Shao Yu-Lung
55d05eeae3 fix modal-title html tag unpaired. 2021-11-24 10:28:10 +08:00
Ivan Nieto Vivanco
d95d3dc282 Add the call to defaultValue() function in custom fields with date format 2021-11-23 17:21:46 -06:00
Adam
ab06c26527 Rocky Linux Support
Addition to enable Rocky Linux installation.
2021-11-23 16:13:38 +00:00
Ivan Nieto Vivanco
1ca770895a Apply trim() function when storing Custom Fields names 2021-11-22 18:43:21 -06:00
Klaus J. Mueller
a85fa14f9c fix #10344 and #9135 2021-11-22 17:58:26 +01:00
snipe
b058d84f2c Merge pull request #10322 from snipe/uberbrady-patch-2
Change the `[END]` directive in `.htaccess` to `[L]`
2021-11-17 18:01:52 -08:00
Brady Wetherington
5fb05d8b1c Change the [END] directive in .htaccess to [L]
This allows backwards-compatibility with older Apache versions (which we _used_ to have), and should do the exact same thing.
2021-11-17 15:29:51 -08:00
snipe
78809c0fe7 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-11-16 12:02:45 -08:00
snipe
7ce5993f5a Merge pull request #10315 from snipe/fixes/escape_custom_fields_in_api_response
Escape custom field values in API response
2021-11-15 20:33:51 -08:00
snipe
f7b483358f Escape custom field values in API response
Signed-off-by: snipe <snipe@snipe.net>
2021-11-15 20:32:59 -08:00
snipe
e75a5f13ec Merge pull request #10303 from inietov/fixes/weird_field_showing_up
Added the current_value string to correspondig 'en' language directory
2021-11-15 14:29:34 -08:00
snipe
cf4e13f4df Merge pull request #10312 from andrewshulgin/patch-1
Fixed: #10311: Docker: ldap_client_tls.{key,cert} are located in /var/www/html/storage instead of /var/lib/snipeit/keys
2021-11-15 14:28:59 -08:00
snipe
8e7565cbe9 Merge pull request #10313 from snipe/snyk-fix-d1fb08ebb2899913c99652bb6e188696
[Snyk] Security upgrade bootstrap-table from 1.18.3 to 1.19.1
2021-11-15 14:28:37 -08:00
snyk-bot
4839b0e008 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-BOOTSTRAPTABLE-1657597
2021-11-13 05:19:33 +00:00
Andrew Shulgin
d3ddafdff4 Dockerfile: symlink for ldap_client_tls.{cert,key} 2021-11-13 03:00:09 +02:00
Ivan Nieto Vivanco
b07db3b324 Added the current_value string to correspondig 'en' language directory 2021-11-11 14:43:47 -06:00
snipe
9ed1442bd1 Merge pull request #10286 from uberbrady/fix_bulk_audit_xss
Escape asset_tag attribute at controller level for bulk checkout
2021-11-08 20:32:02 -08:00
Brady Wetherington
3ea209a507 Escape asset_tag attribute at controller level for consumption in bulk checkout 2021-11-08 20:27:43 -08:00
snipe
edf98cb795 Merge pull request #10279 from snipe/fixes/turn_get_into_post_for_custom_field_required
Turn custom fields required/optional/remove into POST requests
2021-11-08 14:37:36 -08:00
snipe
16d18bc7eb Merge pull request #10283 from snipe/fixes/remove_get_logout_route 2021-11-08 12:55:19 -08:00
snipe
38c36af6fc Changes logout to POST
Signed-off-by: snipe <snipe@snipe.net>
2021-11-08 12:53:11 -08:00
snipe
b5855e7be5 Removed get route for logout
Signed-off-by: snipe <snipe@snipe.net>
2021-11-08 12:35:15 -08:00
snipe
0d811d067c Turn cusotm fields required/optional/remove into POST requests
Signed-off-by: snipe <snipe@snipe.net>
2021-11-05 10:53:48 -07:00
snipe
fba0e2b712 Revert tableexport
(It broke the npm run prod build)

Signed-off-by: snipe <snipe@snipe.net>
2021-11-03 16:17:19 -07:00
snipe
608c2f91a8 Updated package lock
Signed-off-by: snipe <snipe@snipe.net>
2021-11-03 16:04:48 -07:00
snipe
960028b376 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-11-03 16:04:39 -07:00
snipe
6690a0f1df Merge pull request #10257 from Wouter0100/patch-1
fix(Docker): use correct python binary for exit listener
2021-11-02 14:53:35 -07:00
Wouter van Os
2c49c32e72 Fixed #10231: use correct python binary for exit listener
This fixes #10231, without creating an own Dockerfile.
2021-11-02 13:06:36 +01:00
snipe
76cc46c419 Merge pull request #9814 from 01ste02/importMinAmt
Improved Consumable Import: Import min_amt for consumables
2021-10-28 17:49:44 -07:00
snipe
dc71f6ddc6 Merge pull request #9871 from jethron/patch-1
Fixed: double slashes in branding logo URL path
2021-10-28 17:36:43 -07:00
snipe
7470fdb605 Merge pull request #9912 from snipe/snyk-upgrade-1377cc2d38a76585c814757398543f5f
[Snyk] Upgrade tableexport.jquery.plugin from 1.10.21 to 1.10.26
2021-10-28 17:15:10 -07:00
snipe
930e220cf1 Merge pull request #9915 from snipe/snyk-upgrade-b2b26cf8ec7a697fe0094f699652a345
[Snyk] Upgrade bootstrap-table from 1.18.2 to 1.18.3
2021-10-28 17:12:47 -07:00
snipe
2f9e5f79af Merge pull request #10139 from FliegenKLATSCH/patch-1
API: Do not include deleted items per default on lookup by serial
2021-10-28 17:09:20 -07:00
snipe
927fba179d Merge pull request #10241 from snipe/snyk-fix-a23047e623395f58c0f4d50feb55a3a3
[Snyk] Security upgrade jquery-ui from 1.12.1 to 1.13.0
2021-10-28 16:35:32 -07:00
snyk-bot
dfde50732b fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-JQUERYUI-1767167
- https://snyk.io/vuln/SNYK-JS-JQUERYUI-1767175
- https://snyk.io/vuln/SNYK-JS-JQUERYUI-1767767
2021-10-28 07:28:38 +00:00
snipe
7455318fcf Merge pull request #10225 from snipe/fixes/default_label_in_status_label_api
Set default_label to 0 instead of null in API
2021-10-25 20:18:37 -07:00
snipe
17bf899a17 Set default_label to 0 instead of null in API
Signed-off-by: snipe <snipe@snipe.net>
2021-10-25 20:14:01 -07:00
snipe
a5230319b8 Merge pull request #10223 from snipe/fixes/fixed_missing_clone_button
Fixed #10222 - fixed permissions array to handle missing clone button
2021-10-25 15:39:28 -07:00
snipe
8b1c60a17a Make gates a little more consistent
Signed-off-by: snipe <snipe@snipe.net>
2021-10-25 15:34:22 -07:00
snipe
033c3253bb Fixed permissions array to handle missing clone button
Signed-off-by: snipe <snipe@snipe.net>
2021-10-25 14:10:17 -07:00
snipe
a88f622ec3 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-10-18 16:45:51 -07:00
snipe
f87ffb84d5 Merge pull request #10201 from snipe/fixes/xss_on_export
Fixes possible XSS on all-file-types export
2021-10-15 09:54:52 -07:00
snipe
bda23bb1e6 Fixes possible XSS on all-file-types export
Signed-off-by: snipe <snipe@snipe.net>
2021-10-15 11:50:52 -05:00
FliegenKLATSCH
24c484303e Do not include deleted assets by default when doing lookup by serial
This commit introduces a new query parameter `deleted`, which can be set to `true` to include deleted assets in the response.
2021-10-09 08:56:31 +02:00
snipe
5d94b99035 Switched to 5 in one minute
Signed-off-by: snipe <snipe@snipe.net>
2021-10-08 15:53:32 -07:00
snipe
c4856c8aed Merge pull request #10180 from snipe/fixes/add_rate_limiting_to_forgotten_password
Throttle password reset requests to 5 every 60 seconds
2021-10-08 15:44:43 -07:00
snipe
0674ef5a3d Fixed number to 1 (for minutes)
Signed-off-by: snipe <snipe@snipe.net>
2021-10-08 15:43:32 -07:00
snipe
702791210e Throttle password reset requests to 5 every 60 seconds
Signed-off-by: snipe <snipe@snipe.net>
2021-10-08 14:26:30 -07:00
snipe
1c77fd0d09 Merge pull request #10178 from inietov/bug/sc-17520/symfony_component_debug_exception_fatalthrowableerror
Fixed typo when setting the headers
2021-10-08 12:04:45 -07:00
Ivan Nieto Vivanco
d184da8611 Fixed typo (thanks @ssddanbrown) 2021-10-08 13:39:49 -05:00
snipe
ac76364140 Merge pull request #10172 from snipe/fixes/S3_upload_preview
Fixed models preview - Use Storage:: facade
2021-10-06 13:14:02 -07:00
snipe
7848a3c3dc Use Storage:: facade for image preview for models
Signed-off-by: snipe <snipe@snipe.net>
2021-10-06 13:12:42 -07:00
snipe
f41ec640fe Added Huntr.dev badge
Signed-off-by: snipe <snipe@snipe.net>
2021-10-06 12:49:30 -07:00
snipe
fc5efd857f Merge pull request #10171 from snipe/fixes/xss_svg_in_file_uploads
Fixed SVG XSS vuln
2021-10-06 12:38:51 -07:00
snipe
ccd430ce07 Switched back down to debug level
Signed-off-by: snipe <snipe@snipe.net>
2021-10-06 12:38:21 -07:00
snipe
f306401e7e Fixed SVG XSS vuln
Signed-off-by: snipe <snipe@snipe.net>
2021-10-06 12:26:45 -07:00
snipe
c06a93ef13 Removed extra brace in assets for components
Signed-off-by: snipe <snipe@snipe.net>
2021-10-06 10:38:13 -07:00
snipe
17d4e25e60 Merge pull request #10167 from inietov/bug/sc-17520/symfony_component_debug_exception_fatalthrowableerror
Set headers in a different manner in the middleware [sc-17520]
2021-10-05 14:06:39 -07:00
Ivan Nieto Vivanco
ef6eea67d8 Set headers in a different manner in the middleware 2021-10-05 14:09:35 -05:00
snipe
84c73aae5d Merge pull request #10165 from snipe/fixes/set_restore_actions_to_POST_requests
Set restore actions to POST requests instead of GET
2021-10-04 20:40:33 -07:00
snipe
dc3af7cc74 Resolved conflicts
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 20:39:24 -07:00
snipe
34eab88b7e Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 20:25:31 -07:00
snipe
903609b5a5 Updated languages
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 19:59:55 -07:00
snipe
e491a93892 Removed restore link
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 19:56:56 -07:00
snipe
b20c841a89 Fixed asset models restore
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 19:29:13 -07:00
snipe
8fe59f8383 Switch users restore over to POST
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 19:22:38 -07:00
snipe
8bf09d9f89 Make form-based restore button on asset view
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 19:01:16 -07:00
snipe
3594ec9905 Handle bulk check and uncheck
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 17:58:16 -07:00
snipe
52caee2a9f Handle checking and unchecking for bulk actions
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 17:18:26 -07:00
snipe
52ea172e5d Fix ID array
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 17:18:07 -07:00
snipe
caad5be957 Updated routes to use POST for restore
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 17:17:36 -07:00
snipe
fa1cf3073b Add @alwism as a contributor 2021-10-04 15:04:58 -07:00
snipe
71badee78a Add @Robert-Azelis as a contributor 2021-10-04 15:04:47 -07:00
snipe
cb0d1add8d Add @01ste02 as a contributor 2021-10-04 15:04:22 -07:00
snipe
1b0d11a572 Add @jethron as a contributor 2021-10-04 15:03:50 -07:00
snipe
9e522b6a4d Add @Computroniks as a contributor 2021-10-04 15:03:35 -07:00
snipe
a773e70936 Add @Toreg87 as a contributor 2021-10-04 15:03:23 -07:00
snipe
92a38f2a23 Add @jerm as a contributor 2021-10-04 15:03:05 -07:00
snipe
542f774c68 Add @FliegenKLATSCH as a contributor 2021-10-04 15:02:56 -07:00
snipe
67e106c7fa Add @AL4AL as a contributor 2021-10-04 15:02:51 -07:00
snipe
536b5717f0 Merge pull request #10164 from snipe/fixes/require_revalidation_on_logout_back_button
Force revalidation headers when user logs out
2021-10-04 12:56:03 -07:00
snipe
9b48732cd2 Force revalidation headers when user logs out
Signed-off-by: snipe <snipe@snipe.net>
2021-10-04 12:52:48 -07:00
snipe
244616b31e Merge pull request #10157 from snipe/jerm/fix-cachedir-ownership
[Docker] Fix ownership of cache directory in startup script
2021-10-01 17:50:36 -07:00
Jeremy Price
22313711d5 Fix ownership of cache directory
Snipe-IT was waiting to load because
/var/www/html/storage/framework/cache/ and its contet were owned by
root:root, but docker needed to be able to write to them

This change recursively chowns that path to docker:root, and now it
loads.
2021-10-01 16:54:17 -07:00
snipe
89e650f842 Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2021-09-30 16:01:56 -07:00
snipe
daa88f06f7 Added pivot to components JSON
Signed-off-by: snipe <snipe@snipe.net>
2021-09-30 15:51:08 -07:00
snipe
d0acb9fdb4 Applies PR #10150 to master
Signed-off-by: snipe <snipe@snipe.net>
2021-09-30 15:33:00 -07:00
snipe
8e437a66af Merge branch 'master' of https://github.com/snipe/snipe-it 2021-09-28 20:03:35 -07:00
snipe
f232579e2b Added Discord badge
Signed-off-by: snipe <snipe@snipe.net>
2021-09-28 20:02:46 -07:00
snipe
7b7583fde3 Merge pull request #10141 from uberbrady/fix_currency_problems
Fixed #9789 and Fixed #10088 and Fixed [fd23442] - Fix currency problems especially with European currency format
2021-09-28 19:37:25 -07:00
Brady Wetherington
ae466be153 Fix license output, tweak CleanFloat function to handle numbers over 1 million 2021-09-28 19:10:25 -07:00
Brady Wetherington
f3338667c7 Create new ParseCurrency helper and use it in the appropriate controllers 2021-09-28 18:20:39 -07:00
Brady Wetherington
f380da3f19 Try to ensure all currency output is formatted correctly. 2021-09-28 16:45:47 -07:00
snipe
919eaf320c Updated javascript assets
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 19:00:53 -07:00
snipe
c9337a1947 Merge branch 'master' of https://github.com/snipe/snipe-it 2021-09-23 18:59:25 -07:00
snipe
d069d032fc Updated JS asset
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 18:59:13 -07:00
snipe
d37dedb654 Merge pull request #10123 from takuy/patch-1
Fixed #9928: update expected field name for response list
2021-09-23 18:57:02 -07:00
snipe
fedf51dda4 Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 18:29:47 -07:00
snipe
53334f7905 Merge pull request #10124 from snipe/features/added_components_to_assets_API
Added assigned components to assets API
2021-09-23 18:26:57 -07:00
snipe
2f9582ee5c Switched to loadMissing for performance
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 17:31:19 -07:00
snipe
3b7ce0091c Load components in the assets API if components=true in API request
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 17:23:53 -07:00
snipe
6e270c0ed2 Include created_at in pivot
Signed-off-by: snipe <snipe@snipe.net>
2021-09-23 17:23:17 -07:00
Sam
d0f284129a Update expected field for response list
The existing code to handle the "enter key" / auto selections broke at some point. It was expecting results to be in an "items" list, not a "results" list. This should close #9928 hopefully. Tested locally.
2021-09-23 20:12:45 -04:00
snipe
6aa7e9cbfa Merge branch 'master' of https://github.com/snipe/snipe-it 2021-09-23 14:32:48 -07:00
snipe
3862b6476b Merge pull request #10122 from inietov/fixes/api_issue_when_component_checkout
Fixes API Issue when checking out a component
2021-09-23 13:21:48 -07:00
Ivan Nieto Vivanco
7dfab3a6e2 Change the condition to 'bigger or equal' instead of just 'bigger than' in ComponentsController checkout api 2021-09-23 15:02:39 -05:00
snipe
0f40ba2b34 Check for admin rights before displaying admin permission options
Signed-off-by: snipe <snipe@snipe.net>
2021-09-22 19:31:49 -07:00
snipe
39a702397a Add user permissions message if the user is not an admin or better
Signed-off-by: snipe <snipe@snipe.net>
2021-09-22 19:05:02 -07:00
snipe
a6b3aa5f04 Don't try to delete the file if there is no log entry
Signed-off-by: snipe <snipe@snipe.net>
2021-09-22 19:04:25 -07:00
snipe
3821c4d372 Merge remote-tracking branch 'origin/develop' 2021-09-21 21:53:40 -07:00
snipe
104d66b4b1 Merge pull request #10115 from snipe/features/added_footer_to_depreciation_report_totals
Added totals to depreciation report footer
2021-09-21 21:53:17 -07:00
snipe
b4a90045e6 Added totals to depreciation report footer
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 21:52:18 -07:00
snipe
3b9b63a7a8 Merge remote-tracking branch 'origin/develop' 2021-09-21 21:29:11 -07:00
snipe
9b78b25372 Grr. 100 should be 1000
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 21:28:59 -07:00
snipe
0411f63591 Merge remote-tracking branch 'origin/develop' 2021-09-21 21:25:39 -07:00
snipe
7df4f98e19 Bump number per page up to 1000
Use this shit at your own peril. Very large pages will load slowly, as these are very complex queries.

Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 21:25:22 -07:00
snipe
86a4f2d3ec Merge remote-tracking branch 'origin/develop' 2021-09-21 20:54:37 -07:00
snipe
0763c76a4e Fixed scoping with leftjoin
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 20:54:24 -07:00
snipe
3af7c66de7 Merge remote-tracking branch 'origin/develop' 2021-09-21 20:11:08 -07:00
snipe
0be4b21721 Merge pull request #10114 from snipe/fixes/sorting_in_non_assets
Fixes sorting on non-asset relations in API
2021-09-21 20:09:43 -07:00
snipe
5d32c17a2e Removed comments
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 20:01:36 -07:00
snipe
10ca7cffc3 Fixes for query scoping, ordering, and nicer readability
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 19:59:23 -07:00
snipe
05faffbd28 Merge remote-tracking branch 'origin/develop' 2021-09-21 17:50:35 -07:00
snipe
dacdf788bc Reverted erroneous german text in UK language files 2021-09-21 17:50:13 -07:00
snipe
d54057e495 Merge remote-tracking branch 'origin/develop' 2021-09-21 15:55:04 -07:00
snipe
a22c35140b Merge pull request #10112 from snipe/fixes/strtolower_for_category_type
Improved category_type with strtolower() to make it case insensitive
2021-09-21 15:54:35 -07:00
snipe
61176335d7 Improved category_type with strtolower() to make it case insensitive
Signed-off-by: snipe <snipe@snipe.net>
2021-09-21 15:51:41 -07:00
snipe
11c8b1259e Merge remote-tracking branch 'origin/develop' 2021-09-20 18:49:17 -07:00
snipe
9b52c61d95 Updated banner with better warning
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 18:49:04 -07:00
snipe
2dfb965885 Merge pull request #10104 from snipe/fixes/revamp_pave_command_to_persist_api_keys
Fixes pave command to persist api keys and first few test users
2021-09-20 18:48:11 -07:00
snipe
36464bc17d Fix confirmation, because apparently you can't pass that along via cli vs interactively
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 18:22:06 -07:00
snipe
f35208d58d Clean up, find custom fields and drop those columns
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 18:03:13 -07:00
snipe
4d30edd535 Let's make sure to keep some of the stuff we need on the demo as well
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 17:29:32 -07:00
snipe
957f33c8cf First stab at a better pave command
Signed-off-by: snipe <snipe@snipe.net>
2021-09-20 17:19:41 -07:00
snipe
7c8c567eaf Merge remote-tracking branch 'origin/develop' 2021-09-20 15:12:53 -07:00
snipe
6772ace94e Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-09-20 15:10:54 -07:00
snipe
ee28f3e853 Merge branch 'snyk-fix-bb1a61f0d07295579c411381da690d4c' of https://github.com/snipe/snipe-it into develop 2021-09-20 15:10:31 -07:00
snipe
81f1f4ce6f Add @vapier as a contributor 2021-09-20 15:07:37 -07:00
snipe
3b79038879 Merge pull request #10082 from vapier/develop
add rewrite rule for Let's Encrypt certificates
2021-09-20 14:57:14 -07:00
snipe
7e611fa699 Merge remote-tracking branch 'origin/develop' 2021-09-15 13:55:12 -07:00
snipe
e8ad5dc273 Merge pull request #10086 from snipe/fixes_depreciation_report
Fixed extraneous asset search in depreciation report
2021-09-15 13:54:32 -07:00
snipe
8a93e1e796 Remove asset call on depreciation report controller method
We ajax this in now, so no need for it

Signed-off-by: snipe <snipe@snipe.net>
2021-09-15 13:49:53 -07:00
snipe
3d7000f759 Merge remote-tracking branch 'origin/develop' 2021-09-15 11:33:30 -07:00
snipe
d96f877aa4 Default show_in_nav to 0
Signed-off-by: snipe <snipe@snipe.net>
2021-09-15 11:33:13 -07:00
Mike Frysinger
7b665ade0a add rewrite rule for Let's Encrypt certificates
The LE tools need access to a stable path to automatically obtain
certificates, so add a rewrite rule to allow it.
2021-09-14 16:21:31 -04:00
snipe
02705d0d1a Fixed S3 upload path
Signed-off-by: snipe <snipe@snipe.net>
2021-09-14 12:49:17 -07:00
snipe
772a06c87a Merge remote-tracking branch 'origin/develop' 2021-09-13 17:13:20 -07:00
snipe
0d633ce618 Fixed issue where created_at date was not showing on uploads
Signed-off-by: snipe <snipe@snipe.net>
2021-09-13 17:13:01 -07:00
snipe
cedf77b5ed Merge remote-tracking branch 'origin/develop' 2021-09-13 15:47:25 -07:00
snipe
c6b26965a0 Check for valid category name
Signed-off-by: snipe <snipe@snipe.net>
2021-09-13 15:47:13 -07:00
snipe
4b303adda7 Merge pull request #10080 from uberbrady/upgrade_docker_php74
Upgrade Docker to PHP 7.4
2021-09-13 15:30:32 -07:00
Brady Wetherington
37fe4e91b1 Upgrade Docker to PHP 7.4 2021-09-13 15:24:30 -07:00
snipe
179f26ca2e Merge pull request #10079 from inietov/fixes/archived_assets_showing_in_locations
Awesome, thanks!
2021-09-13 14:46:44 -07:00
Ivan Nieto Vivanco
1ae665b645 Use the property 'archived' so if the 'name' one changes it doesn't fails 2021-09-13 16:45:05 -05:00
Ivan Nieto Vivanco
1b433920f1 Delete an extra semicolon 2021-09-13 16:24:12 -05:00
Ivan Nieto Vivanco
2b64af0d34 Add a condition in the view 'print all assigned' from locations where it skips the assets in relation of if they're archived and that option is marked in the settings 2021-09-13 16:17:34 -05:00
snipe
7f31befe5d Merge remote-tracking branch 'origin/develop' 2021-09-10 20:46:15 -07:00
snipe
a5409215fc Merge pull request #10070 from snipe/fixes/update_status_label_color_via_api
Fixed #9969 - added color, show_in_nav, and default_label to status l…
2021-09-10 20:45:47 -07:00
snipe
80175cffdc Fixed #9969 - added color, show_in_nav, and default_label to status labels API
Signed-off-by: snipe <snipe@snipe.net>
2021-09-10 20:44:49 -07:00
snipe
f8f969919e Merge remote-tracking branch 'origin/develop' 2021-09-10 20:26:37 -07:00
snipe
fb68c49c44 Merge pull request #10069 from snipe/fixes/add_use_default_eula_to_category_endpoint
Fixed #9973 - add use_default_eula to category endpoint
2021-09-10 20:25:56 -07:00
snipe
514f9aa64a Fixed #9973 - add use_default_eula to categories API endpoint
Signed-off-by: snipe <snipe@snipe.net>
2021-09-10 20:23:49 -07:00
snipe
0d633688a4 Merge pull request #10063 from jasonspriggs/develop
This looks good to me, thanks! I'm not as familiar with Heroku these days (it's been years and years since I've used it), but it seems okay?
2021-09-10 18:22:12 -07:00
Jason Spriggs
949454c6d4 Minor modifications to documentation for app.json 2021-09-09 16:55:26 -04:00
Jason Spriggs
d100a5de72 Add Papertrail logging addon 2021-09-08 21:11:46 -04:00
Jason Spriggs
acefb3d1b9 Add descriptions for some env vars 2021-09-08 20:51:43 -04:00
snipe
38a544ea42 Updated version branch to master
Signed-off-by: snipe <snipe@snipe.net>
2021-09-08 13:50:52 -07:00
snipe
a4e307c4db Updated languages
Signed-off-by: snipe <snipe@snipe.net>
2021-09-08 13:49:33 -07:00
snipe
116bc4ece4 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-09-08 13:42:48 -07:00
snipe
14a8baecaa Merge pull request #10059 from inietov/fixes/CSV_imports_checkout_to_location
Convert value of column 'checkout type' in CSV file to lowercase
2021-09-08 13:31:49 -07:00
Ivan Nieto Vivanco
f1b8b7d11d Convert whatever value we get in column 'checkout type' to all lowercase 2021-09-08 12:49:29 -05:00
snipe
c6b3fc219c Merge pull request #10023 from snipe/snyk-fix-deed9a63fc3bf8e6472c4aabe8c95f02
[Snyk] Security upgrade alpine from 3.13 to 3
2021-09-07 19:56:10 -07:00
snipe
cfaa6679af Merge pull request #10031 from inietov/fixes/checkout_date_not_saved_in_asset_history
Fixed #10026: Checkout date not saved in asset history
2021-09-07 17:37:30 -07:00
snipe
bb5a04491d Merge pull request #10053 from inietov/fixes/accepted_assets_still_showing_unaccepted_report
Fix Accepted Assets still showing on Unaccepted Asset Report
2021-09-07 12:15:17 -07:00
snipe
f9c0eee7c9 Merge pull request #10048 from inietov/fixes/blank_results_for_non_superadmins
Fix to PR #10009.  The asset search now works as intended for normal users
2021-09-07 12:14:29 -07:00
Ivan Nieto Vivanco
27ff0be9a8 Delete checkout acceptances when an asset is checked in without response 2021-09-07 12:01:32 -05:00
Ivan Nieto Vivanco
b5525e6a21 Deleted additional bindings present also in the User model 2021-09-07 00:57:12 -05:00
Ivan Nieto Vivanco
c3eb7a3425 Remove aditional bindings that 'overflows' the generated queries 2021-09-07 00:15:21 -05:00
Jason Spriggs
48374f0854 Add PUBLIC_FILESYSTEM_DISK 2021-09-05 12:21:46 -04:00
Jason Spriggs
bae3c9ce93 Add Deploy to Heroku button to README 2021-09-05 10:34:48 -04:00
Jason Spriggs
b51392e4a5 Add base heroku changes 2021-09-05 10:33:13 -04:00
snipe
6bd18ebefa Merge pull request #10043 from benwa/master
Use the new Issues form
2021-09-02 16:15:45 -07:00
Bennett Blodinger
034eb5fb07 no markdown? 2021-09-02 17:48:38 -05:00
Bennett Blodinger
563edddfc5 add a feature request 2021-09-02 17:47:32 -05:00
Bennett Blodinger
391d4f839a formatting 2021-09-02 17:43:24 -05:00
Bennett Blodinger
51a359496a unique IDs 2021-09-02 17:37:47 -05:00
Bennett Blodinger
43b7c844b0 multiline 2021-09-02 17:32:31 -05:00
Bennett Blodinger
a1674f8d58 Create config.yml 2021-09-02 17:29:36 -05:00
Bennett Blodinger
a8a6950b7e Delete Feature_request.md 2021-09-02 17:28:01 -05:00
Bennett Blodinger
4598fcf666 Delete Bug_report.md 2021-09-02 17:27:46 -05:00
Bennett Blodinger
37eac18c69 Create bug_report.yml
Using the (currently in beta) https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
2021-09-02 17:27:27 -05:00
Bennett Blodinger
ca3296b65a Update issue templates 2021-09-02 16:58:18 -05:00
snipe
a79f49ade3 Merge pull request #10034 from snipe/features/ajaxify_depreciation
Fixed [ch15359] ajaxify the depreciation report
2021-09-01 18:26:10 -07:00
snipe
a26c227dcb Merge pull request #10018 from jjasghar/patch-1
Fixed typo: Update README.md
2021-09-01 17:50:15 -07:00
snipe
94310e18b1 Presenters and Transformers for Depreciation report
Signed-off-by: snipe <snipe@snipe.net>
2021-09-01 17:33:59 -07:00
snipe
2f25eb598b Allow the Assets API controller to handle depreciation reports
Signed-off-by: snipe <snipe@snipe.net>
2021-09-01 17:33:39 -07:00
snipe
387018c44e Updated depreciation report blade to use server-side API
Signed-off-by: snipe <snipe@snipe.net>
2021-09-01 17:05:31 -07:00
snipe
67357e07f1 Added API route for depreciations report
RED FLAG: This will need to be updated for v6!!!!

Signed-off-by: snipe <snipe@snipe.net>
2021-09-01 17:05:00 -07:00
Ivan Nieto Vivanco
e621eaf456 Change date showed in the activity report view, the condition is now on action_date 2021-09-01 13:58:17 -05:00
Ivan Nieto Vivanco
ea1d7a42e2 Add condition to check if action_date have value and if it have assign it to created_at parameter 2021-09-01 13:08:08 -05:00
snipe
d5a7955e1d Fixed #10024 - use string for dashboard in side nav instead of hard coded
Signed-off-by: snipe <snipe@snipe.net>
2021-08-31 22:25:00 -07:00
snyk-bot
e33ab269ae fix: Dockerfile.alpine to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE313-APKTOOLS-1533754
- https://snyk.io/vuln/SNYK-ALPINE313-OPENSSL-1569446
- https://snyk.io/vuln/SNYK-ALPINE313-OPENSSL-1569446
- https://snyk.io/vuln/SNYK-ALPINE313-OPENSSL-1569448
- https://snyk.io/vuln/SNYK-ALPINE313-OPENSSL-1569448
2021-09-01 01:06:18 +00:00
snipe
4293674f4a Added a few more fields to the users API
Signed-off-by: snipe <snipe@snipe.net>
2021-08-31 12:36:06 -07:00
snipe
aeae681326 Fixecd copypasta from state to zip
Signed-off-by: snipe <snipe@snipe.net>
2021-08-31 12:28:20 -07:00
snipe
4794f93224 Added additional fields for user search
Signed-off-by: snipe <snipe@snipe.net>
2021-08-31 12:24:53 -07:00
snipe
f58ed6bd1f Merge pull request #9982 from Shankschn/master
Fixes: When using API CheckIn assets, there will be two CheckIn records in the Activity Report log for each asset.
2021-08-31 11:08:52 -07:00
snipe
96c0dba92b Merge pull request #10011 from inietov/fixes/quotations_turn_into_html_entity
Fixes Quotations turn into HTML entity
2021-08-31 11:00:38 -07:00
JJ Asghar
07a2ef2234 Update README.md
Typo.
2021-08-31 11:11:19 -05:00
Ivan Nieto Vivanco
d917ae51b7 Remove e() function from other input fields 2021-08-31 04:01:20 -05:00
Ivan Nieto Vivanco
e7470b5545 Remove e() function from the saved notes when updating an asset maintenance 2021-08-31 03:50:57 -05:00
snipe
7e2def7896 Merge pull request #9880 from inietov/bug/fd18463/cannot_edit_departments
Fixes: Can't update departments if Full Company Support is activated
2021-08-30 19:40:59 -07:00
snipe
a02534b6c8 Merge pull request #10009 from inietov/fixes/blank_results_for_non_superadmins
Fixes #9985. Error 500 when using the asset search - blank results for non super-admins
2021-08-30 13:29:18 -07:00
snipe
5c92ddb2c6 Fixed version back to develop from master downmerge
Signed-off-by: snipe <snipe@snipe.net>
2021-08-30 12:57:06 -07:00
snipe
6d3a82aacf Merge pull request #10008 from uberbrady/fix_unlink_error_ldap
Fixed rb445 and rb446 - the unlink calls for the client-side certs...
2021-08-30 12:47:38 -07:00
Brady Wetherington
da0b375773 Fixed rb445 and rb446 - the unlink calls for the client-side certs
need to be wrapped around a file-existence check
2021-08-30 12:29:16 -07:00
Ivan Nieto Vivanco
d1304cc975 Add sentence to infer the table's name according to the query passed 2021-08-30 13:44:26 -05:00
snipe
085be16966 Merge remote-tracking branch 'origin/develop' 2021-08-25 14:45:41 -07:00
snipe
127a3e41bd Merge pull request #9993 from inietov/fixes/exception_when_checkin_licenses_from_assets
Fixes Exception when Checkin Licenses from Assets
2021-08-25 14:45:14 -07:00
Ivan Nieto Vivanco
4a79c77630 Add a condition to checkin licenses assigned to Assets 2021-08-25 16:38:34 -05:00
snipe
e21b21fbde Merge pull request #9990 from inietov/fixes/cannot_upload_files_to_assets
Fixed #9440 Change condition to return the actual max upload size allowed to files
2021-08-25 13:39:23 -07:00
Ivan Nieto Vivanco
137f55e4ce Change condition to return the actual max upload size allowed to files 2021-08-25 15:27:25 -05:00
snipe
4abb9baa95 Merge remote-tracking branch 'origin/develop' 2021-08-24 15:29:41 -07:00
snipe
36ddc7dea7 Merge pull request #9980 from inietov/fixes/display_custom_field_not_holding_value
Fixes:  Display custom field not holding value
2021-08-24 15:12:15 -07:00
snipe
80b411c94b Merge pull request #9986 from uberbrady/fix_client_side_ldap_cert_settings
Make the LDAP Client-side certificate fields Nullable
2021-08-24 15:10:49 -07:00
Brady Wetherington
ae65e2a0a0 Adding explicit default(null), and removing the nullable() attribute on the down() migration 2021-08-24 14:15:55 -07:00
Brady Wetherington
2d578a9864 Make the LDAP Client-side certificate fields Nullable 2021-08-24 12:52:03 -07:00
Shanks
961e80404a Update AssetsController.php
Fix:When using API CheckIn assets, there will be two CheckIn records in the Activity Report log for each asset.
2021-08-24 16:39:58 +08:00
Ivan Nieto Vivanco
830ba470dd Change the used function to only affect single and double quotes 2021-08-23 22:10:59 -05:00
Ivan Nieto Vivanco
80fb24e861 Fix issue caused for single and double quotes when used as listbox's values 2021-08-23 22:00:01 -05:00
snipe
70f6753f50 Merge pull request #9979 from uberbrady/add_client_side_ldap_certs
Add client side ldap certs
2021-08-23 16:30:46 -07:00
snipe
9285697611 Merge remote-tracking branch 'origin/develop' 2021-08-20 17:30:52 -07:00
snipe
9687bcb41c Fixed issue where consumables model number was not searchable
Signed-off-by: snipe <snipe@snipe.net>
2021-08-20 17:30:35 -07:00
snipe
4ec4e0f44e Merge remote-tracking branch 'origin/develop' 2021-08-19 12:09:48 -07:00
snipe
ff8faab3be Merge pull request #9960 from uberbrady/fix_null_sum_totals
Fix regression for NULL valued numbers in the summary calculation
2021-08-19 12:08:33 -07:00
Brady Wetherington
e28db2d221 Fix regression for NULL valued numbers in the summary calculation 2021-08-19 12:01:47 -07:00
snipe
24af2ab67a Merge remote-tracking branch 'origin/develop' 2021-08-18 14:31:53 -07:00
snipe
7b447a2f16 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-08-18 14:31:38 -07:00
snipe
f5112b47cd Merge pull request #9953 from uberbrady/fix_bootstrap_sum_formatter
Fixed ch17133 - Fixed sum total calculation on Bootstrap Table pages -
2021-08-18 14:31:10 -07:00
Brady Wetherington
4519f6e180 Fixed sum total calculation on Bootstrap Table pages 2021-08-18 14:13:31 -07:00
snipe
6f7718dd0e Merge pull request #9950 from inietov/fixes/ch945/status_colors_are_not_displaying_correctly
Looks great, thanks!
2021-08-18 14:09:26 -07:00
Ivan Nieto Vivanco
f04e23cacb Add a small refactor so we not repeat logic 2021-08-18 15:22:53 -05:00
Brady Wetherington
1b66f7f719 Add new client-side LDAP SSL certs to .gitignore 2021-08-18 13:22:36 -07:00
Ivan Nieto Vivanco
4207858a14 Fix the count in StatuslabelsController@getAssetsCountByStatuslabel() function that allows it to pass the correct index
Also edit the default color for assets with the Pending label, so it match the color in the docs
2021-08-18 14:08:35 -05:00
snipe
b88fde5dae Nicer comment formatting
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 12:07:09 -07:00
snipe
04fa5f2022 Merge remote-tracking branch 'origin/develop' 2021-08-18 01:05:25 -07:00
snipe
923d2a79ae Fixed weird layout on bulk audit [ch17146]
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 01:05:09 -07:00
snipe
c970464690 Updated production assets
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 00:48:05 -07:00
snipe
f99602c039 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2021-08-18 00:47:33 -07:00
snipe
0aa328f908 Updated hash
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 00:45:35 -07:00
snipe
f8562e5835 Recompiled assets
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 00:45:02 -07:00
snipe
8a6c7269d3 Fixed border radius for bulk checkout field [ch16936]
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 00:44:55 -07:00
snipe
37f2c7beac Nicer bulk asset select width
Signed-off-by: snipe <snipe@snipe.net>
2021-08-18 00:44:16 -07:00
snipe
b5bb74b8ca Merge remote-tracking branch 'origin/develop' 2021-08-17 22:01:23 -07:00
snipe
b5e69d6678 Merge pull request #9947 from snipe/fixes/apply_v6_currency_formatter
Fixed #9909  and #9714 - applies v6 currency formatter to v5 [ch16628]
2021-08-17 22:00:39 -07:00
snipe
cce808c784 Fixed #9909 and #9714 - applies v6 currency formatter to v5 [ch16628]
Duplicates d4e46ee41f but on v5

Signed-off-by: snipe <snipe@snipe.net>
2021-08-17 21:59:33 -07:00
Brady Wetherington
4d4badf830 Got the client-side LDAP setup working well enough for sync! 2021-08-17 14:43:36 -07:00
snipe
d70e4e04c0 Merge pull request #9933 from JemCdo/patch-1
Fixed #9934: Typo on creating Depreciation
2021-08-16 07:44:56 -07:00
James Emanuel
98285001ac Fixing Typo on creating Depreciation 2021-08-16 15:33:17 +03:00
snipe
29c584289f Merge remote-tracking branch 'origin/develop' 2021-08-14 14:09:31 -07:00
snipe
dc79ca94a2 Merge pull request #9931 from snipe/features/add_asset_restore_to_api
Features/add asset restore to api
2021-08-14 14:08:36 -07:00
snipe
ef687fdc7b Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2021-08-14 14:07:04 -07:00
snipe
45caa8a90d Added restore functionalty to asset API
Signed-off-by: snipe <snipe@snipe.net>
2021-08-14 14:06:15 -07:00
snipe
b1e2f86871 Merge pull request #9919 from ItsGageHolland/patch-1
Update README.md
2021-08-11 12:39:17 -07:00
Godfrey M
01037cf9cb initial commit: adds migration, input area and transformer modifications for depreciation minimum value [ch15358] 2021-08-10 18:26:43 -07:00
Gage K. Holland
63a5c70e8e Update README.md 2021-08-10 09:16:51 +01:00
snyk-bot
3fedcc6766 fix: upgrade bootstrap-table from 1.18.2 to 1.18.3
Snyk has created this PR to upgrade bootstrap-table from 1.18.2 to 1.18.3.

See this package in npm:
https://www.npmjs.com/package/bootstrap-table

See this project in Snyk:
https://app.snyk.io/org/snipe/project/3d53e1dd-b8bf-46b5-ba61-18ce26933166?utm_source=github&utm_medium=upgrade-pr
2021-08-07 21:41:02 +00:00
snyk-bot
892ae9cf91 fix: upgrade tableexport.jquery.plugin from 1.10.21 to 1.10.26
Snyk has created this PR to upgrade tableexport.jquery.plugin from 1.10.21 to 1.10.26.

See this package in npm:
https://www.npmjs.com/package/tableexport.jquery.plugin

See this project in Snyk:
https://app.snyk.io/org/snipe/project/3d53e1dd-b8bf-46b5-ba61-18ce26933166?utm_source=github&utm_medium=upgrade-pr
2021-08-07 21:40:51 +00:00
snyk-bot
9ae6591aa3 fix: Dockerfile.alpine to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE313-APKTOOLS-1533754
2021-08-07 21:38:53 +00:00
snipe
cdc4940338 Merge pull request #9881 from inietov/fixes/integrity_constraint_violation__emailing_password_reset
Fixes Integrity constraint violation when emailing password reset.
2021-07-30 16:01:53 -07:00
Ivan Nieto Vivanco
27cdfbc579 Edit the log message 2021-07-29 16:14:52 -05:00
Ivan Nieto Vivanco
405545cd88 Add exception handling in the ForgotPasswordController 2021-07-29 16:02:45 -05:00
Ivan Nieto Vivanco
1b8156ac7f Add a hidden field to handle departments inside Full Company Support config 2021-07-29 13:28:57 -05:00
Jethro Nederhof
d8fdd1b408 Fix branding logo URL path
The current method adds an additional slash to the URL which results in the logo request producing a 404 error on for Storage drivers like S3 and GCS that don't automatically collapse additional forward slashes into single slashes.

E.g. with the current code my logo URL renders like `https://storage.googleapis.com/mybucketname/public//setting-logo-Al0aKMhmYz.svg` (note the double slash after "public") when instead it should render like `https://storage.googleapis.com/mybucketname/public/setting-logo-Al0aKMhmYz.svg`

For a local driver this should work fine since webservers handle the additional slashes case, but for key-based storage this 404s.

Thanks for your work on Snipe-It, seems like a good system so far!
2021-07-28 14:55:34 +10:00
snipe
593e1234a5 Merge pull request #9797 from markbrule/fixes/search_parameter_checkedout_api
Fixed #9671: wrap OR queries in sub-condition in checkedout search
2021-07-27 14:39:10 -07:00
snipe
9a5d9eafeb Merge pull request #9709 from morning-bird/master
add CompanyableTrait
2021-07-27 14:38:21 -07:00
snipe
eca15bd49b Merge pull request #9837 from Godmartinz/chore/ch16531/update-demo-photos-of-iphones-to-be-more
Update demo photos of iPhones to be more [ch16531]
2021-07-27 14:34:52 -07:00
snipe
d2fc98b685 Merge pull request #9861 from inietov/fixes/consumables_accessories_not_correctly_displayed_via_locations
Fixes #9853 Consumables/Accessories not correctly displayed via Locations
2021-07-26 14:49:05 -07:00
Ivan Nieto Vivanco
38a2a0c1ee Add the pertinent filters in Accessories and Consumables controllers 2021-07-26 12:59:15 -05:00
snipe
75d4a46fff Merge pull request #9856 from inietov/bug/ch15413/model_number_is_not_on_accessory_import_dropdown
Fixes: Model Number is not on the Accessory import dropdown of mappable fields [ch15413]
2021-07-24 01:05:26 -07:00
Ivan Nieto Vivanco
0f1c48cb6f Add the field model_number to Accessory importer 2021-07-24 02:38:44 -05:00
Godfrey M
9fb911146f Update demo photos of iPhones to be more [ch16531] 2021-07-19 12:26:04 -07:00
snipe
615bdd0499 Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2021-07-15 13:29:07 -07:00
snipe
33e92c975a Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2021-07-15 13:29:00 -07:00
snipe
5f842d02ef Fixed namespace
Signed-off-by: snipe <snipe@snipe.net>
2021-07-15 13:24:40 -07:00
snipe
f5ba47fcdd Merge pull request #9829 from Godmartinz/bug/ch16602/make-non-linked-striped-text-the-same-for
Make non linked striped text the same for [ch16602]
2021-07-14 14:54:18 -07:00
Godfrey M
44612e5eb7 Make non linked striped text the same for [ch16602] 2021-07-14 14:50:45 -07:00
snipe
6b7d5ed5a4 Merge remote-tracking branch 'origin/develop' 2021-07-14 11:35:47 -07:00
snipe
5e76d50f2d Merge pull request #9825 from PetriAsi/feature/api-image-uploads
Fixed #9767 : Feature/api image uploads legacy image_source property  support
2021-07-14 10:24:40 -07:00
Petri Asikainen
febf1ec20f Support legacy image_source property 2021-07-14 13:09:50 +03:00
Petri Asikainen
fa8b0964ed Merge branch 'develop' of github.com:snipe/snipe-it into feature/api-image-uploads 2021-07-14 13:06:39 +03:00
snipe
a0798a68d9 Merge pull request #9767 from PetriAsi/feature/api-image-uploads
Added #9594 : Feature api image uploads and remove
2021-07-13 09:36:35 -07:00
Petri Asikainen
7b12668af4 Merge branch 'develop' of github.com:snipe/snipe-it into feature/api-image-uploads 2021-07-13 17:23:44 +03:00
Oskar Stenberg
5b5874499d Added import for min_amt for consumables 2021-07-12 11:46:19 +02:00
snipe
4cfdaf89d8 Merge remote-tracking branch 'origin/develop' 2021-07-08 17:47:08 -07:00
snipe
b307d2858c Merge pull request #9809 from uberbrady/fix_saml_custom_settings
The custom settings section of SAML sometimes has bad linefeeds
2021-07-08 17:16:37 -07:00
Brady Wetherington
0ec2884c29 The custom settings section of SAML sometimes has bad linefeeds 2021-07-08 17:00:01 -07:00
snipe
f264cade7d Merge remote-tracking branch 'origin/develop' 2021-07-08 16:05:32 -07:00
snipe
8ea3acc943 Fixed route ordering (FIFO)
Signed-off-by: snipe <snipe@snipe.net>
2021-07-08 16:05:07 -07:00
snipe
f785c3e759 Default to 1 if no qty is passed
Signed-off-by: snipe <snipe@snipe.net>
2021-07-08 16:04:52 -07:00
snipe
0a2a8932d4 Merge pull request #9808 from inietov/bug/ch15453/selected_maintenance_history_columns_not_remembered
Fixes [ch15453] Maintenance/History columns not remembered.
2021-07-08 12:15:53 -07:00
Ivan Nieto Vivanco
d2e94dfc1c Added cookie option to assets Bootstrap Table to save the state of the table. 2021-07-08 14:05:40 -05:00
Petri Asikainen
4379ea61fa Just mention source of idea as code rewriten 2021-07-08 19:50:33 +03:00
Petri Asikainen
41deabf998 hand legacy image_source field 2021-07-07 09:33:48 +03:00
Petri Asikainen
7a424649c8 convert image_source field
This reverts commit b2d3ba7410.
2021-07-07 09:24:24 +03:00
Petri Asikainen
b2d3ba7410 Revert "Handle image_source with ConvertBase64ToFiles"
This reverts commit 168d7f7004.
2021-07-07 09:20:38 +03:00
Petri Asikainen
168d7f7004 Handle image_source with ConvertBase64ToFiles 2021-07-07 09:08:37 +03:00
snipe
60b8320b4b Updated production assets
Signed-off-by: snipe <snipe@snipe.net>
2021-07-06 15:15:28 -07:00
snipe
721b749ae1 Merge remote-tracking branch 'origin/develop' 2021-07-06 15:13:39 -07:00
snipe
11d9b1ba45 Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2021-07-06 15:09:03 -07:00
snipe
2f10d946ec Merge branch 'bug/ch16594/table-striping-on-dark-mode-skins-is-too' of https://github.com/Godmartinz/snipe-it into develop
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/skin-black-dark.css
#	public/css/dist/skins/skin-black-dark.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/mix-manifest.json
2021-07-06 15:08:20 -07:00
snipe
6e0355fa34 Merge pull request #9778 from inietov/fixes/users_departments_not_being_imported
Fixes #9730. Remove an else statement that doesn't allow to continue the importer flow.
2021-07-06 14:59:42 -07:00
Ivan Nieto Vivanco
131a285e2f Fixes Vue issue with the import process. 2021-07-06 15:59:45 -05:00
Mark Brule
f706c87cbc wrap OR queries in sub-condition 2021-07-06 20:43:17 +00:00
Petri Asikainen
f53cabee24 Better debug comment 2021-07-06 07:26:16 +03:00
Petri Asikainen
e275c9ee90 Fixed case again 2021-07-06 07:10:03 +03:00
Petri Asikainen
3d8acd1bd8 removed unused Bag-functions 2021-07-06 07:00:12 +03:00
Petri Asikainen
2169c62700 Merge branch 'feature/api-image-uploads-json' into feature/api-image-uploads 2021-07-06 06:55:54 +03:00
Petri Asikainen
c21b291484 keep using request 2021-07-06 06:51:07 +03:00
Petri Asikainen
c1bc2486ad keep using request 2021-07-06 06:49:19 +03:00
Petri Asikainen
e3166c2209 fix debug placement 2021-07-06 06:41:37 +03:00
Petri Asikainen
7a5b5c291d merged from develop 2021-07-06 06:38:32 +03:00
Petri Asikainen
d66ef233bf handle files via standard field 2021-07-06 06:25:37 +03:00
Petri Asikainen
013df747d7 debug trait 2021-07-05 09:59:19 +03:00
Petri Asikainen
02fb7ac03e Try without trait 2021-07-04 13:39:46 +03:00
Petri Asikainen
d48a9d549d Try without trait 2021-07-04 13:37:05 +03:00
Petri Asikainen
f59f3dbde4 case case again.. 2021-07-02 10:43:15 +03:00
Petri Asikainen
f4fa6836cb trait base64 encoded files 2021-07-02 10:29:26 +03:00
Petri Asikainen
e846e6ac76 trait base64 encoded files 2021-07-02 10:18:18 +03:00
Petri Asikainen
e15159b9c3 trait base64 encoded files 2021-07-02 10:17:29 +03:00
Ivan Nieto Vivanco
5545457536 Remove an else statement that doesn't allow to continue the importer flow. 2021-07-01 14:26:03 -05:00
snipe
19994e2097 Merge pull request #9774 from uberbrady/snipeit_restore_php73
Better debugging output, and remove non-PHP-7.3-compatible option
2021-06-30 15:22:48 -07:00
Brady Wetherington
102591b009 Better debugging output, and remove non-PHP-7.3-compatible option 2021-06-30 14:53:08 -07:00
Petri Asikainen
347e742e88 merged current upstream/develop 2021-06-30 12:02:05 +03:00
snipe
b46e2b5990 Merge remote-tracking branch 'origin/develop' 2021-06-30 01:03:05 -07:00
snipe
868419b35b Components checkin/checkout via API
Signed-off-by: snipe <snipe@snipe.net>
2021-06-30 01:02:44 -07:00
snipe
df7e0e5630 Fixed company resource route
Signed-off-by: snipe <snipe@snipe.net>
2021-06-29 23:46:25 -07:00
Petri Asikainen
6048acc95d fixed capitalization 2021-06-30 06:36:12 +03:00
snipe
86b3f8349a Merge pull request #9768 from svpernova09/vagrant-ansible-fix
Fix APP_ENV/APP_DEBUG typo overwriting the APP_ENV in Vagrant Playbook
2021-06-29 07:57:14 -07:00
Joe Ferguson
fbf5c705db Fix APP_ENV/APP_DEBUG typo overwriting the APP_ENV in Vagrant Playbook 2021-06-29 08:12:01 -05:00
Petri Asikainen
b0aa26e6cb Support images and multipart requests 2021-06-29 14:25:20 +03:00
Petri Asikainen
b49733832c Support images and multipart requests 2021-06-29 12:29:17 +03:00
Petri Asikainen
8c0be3aa87 Support images and multipart requests 2021-06-29 12:29:07 +03:00
Petri Asikainen
a936744e2e Support images and multipart requests 2021-06-29 12:28:52 +03:00
Petri Asikainen
f9da83bc46 Support images and multipart requests 2021-06-29 12:28:42 +03:00
Petri Asikainen
fc8498972e Support images and multipart requests 2021-06-29 12:28:32 +03:00
Petri Asikainen
4ba75291e4 Support images and multipart requests 2021-06-29 12:27:18 +03:00
Petri Asikainen
a7b1e31776 Support images and multipart requests 2021-06-29 12:27:08 +03:00
Petri Asikainen
604a0b6df1 Support images and multipart requests 2021-06-29 12:26:59 +03:00
Petri Asikainen
4ed9788a0e Support images and multipart requests 2021-06-29 12:26:45 +03:00
Petri Asikainen
e8a4059db9 Support images and multipart requests 2021-06-29 12:26:24 +03:00
Petri Asikainen
aa402bf896 Support images and multipart requests 2021-06-29 12:26:15 +03:00
Petri Asikainen
8d4219759e Support images and multipart requests 2021-06-29 12:25:47 +03:00
Godfrey M
aba912001d Table striping on dark mode skins is too [ch16594] 2021-06-28 20:41:56 -07:00
snipe
15b82997ca Merge pull request #9764 from uberbrady/develop
Regenerate assets after repairing Vue integration
2021-06-28 16:58:05 -07:00
Brady Wetherington
dce1dd41c8 Regenerate assets after repairing Vue integration 2021-06-28 16:38:05 -07:00
snipe
f504d7ef5f Merge remote-tracking branch 'origin/develop' 2021-06-28 13:12:10 -07:00
snipe
9ba7e7a0f3 Merge pull request #9761 from snipe/features/9745_add_notes_to_statuslabels
Added #9745 - adds searchable, sortable notes to statuslabels index
2021-06-28 13:09:24 -07:00
snipe
30297e479e Hide notes field by default
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 13:08:32 -07:00
snipe
19413a63da Make notes field searchable on status labels
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 11:53:17 -07:00
snipe
a4fd0c9c6d Fixed #9745 - added searchable, sortable notes field to status labels
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 11:52:57 -07:00
snipe
5b5b70e639 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2021-06-28 11:01:45 -07:00
snipe
6521f16b80 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 11:00:34 -07:00
snipe
9b2cb19f22 Fixed #9743 - Vue screens not loading
Signed-off-by: snipe <snipe@snipe.net>
2021-06-28 10:59:34 -07:00
Petri Asikainen
e0c5205e9b save images 2021-06-28 08:11:33 +03:00
Petri Asikainen
695bf1e15f save images 2021-06-28 07:58:08 +03:00
Petri Asikainen
0e2efb6573 Merge branch 'develop' of github.com:snipe/snipe-it into feature/api-image-uploads 2021-06-27 14:38:55 +03:00
snipe
3ca3de9e4f Merge remote-tracking branch 'origin/develop' 2021-06-23 20:05:38 -07:00
snipe
174d53aff9 Fixed #9729 - order number maxlength updated to 200
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 20:05:22 -07:00
snipe
22152f0a8c Updated assets
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 17:55:38 -07:00
snipe
b5a75206fe Merge remote-tracking branch 'origin/develop' 2021-06-23 17:19:48 -07:00
snipe
3f39cff225 Merge pull request #9738 from Godmartinz/bug/ch16594/table-striping-on-dark-mode-skins-is-too
corrected a link color in the dark mode yellow skin
2021-06-23 16:39:02 -07:00
Godfrey M
a37edd5c5b darkened back-sub-alt more 2021-06-23 16:34:41 -07:00
snipe
6f3e156be6 Merge remote-tracking branch 'origin/develop' 2021-06-23 16:34:34 -07:00
snipe
7d1c2199ed Attempted to re-bound to lowest php version possible
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 16:29:43 -07:00
Godfrey M
f199098a59 undid the color change for links, darkened the back-sub-alt 2021-06-23 16:29:21 -07:00
snipe
335f4e50a5 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2021-06-23 16:07:01 -07:00
snipe
1808986bf5 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 16:06:30 -07:00
snipe
bc0c887812 Merge remote-tracking branch 'origin/develop' 2021-06-23 16:05:19 -07:00
snipe
d8191f738c Updated flysystem to 1.1.4 for critical security update
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 16:04:42 -07:00
snipe
7b51bf4f51 Merge remote-tracking branch 'origin/develop' 2021-06-23 14:41:27 -07:00
snipe
450183c55c Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-06-23 14:41:10 -07:00
snipe
e44a25126d Merge pull request #9676 from inietov/fixes/asset_checkin_api_doesnt_send_notification
Fixes #9666 Asset checkin via api doesn't send notification.
2021-06-23 14:35:07 -07:00
snipe
c801305c9b Merge pull request #9681 from tulsaschoolsdata/9680-fix-statuslabels-asset-count
Fixed #9680: Use Eloquent’s `withCount` method to count Statuslabel assets
2021-06-23 14:34:34 -07:00
snipe
4db5a8f62b Merge pull request #9695 from Joly0/master
Update print.blade.php
2021-06-23 14:33:25 -07:00
snipe
7b4cc5044b Add @derdeagle as a contributor 2021-06-23 14:31:48 -07:00
snipe
1c1ebdf44d Merge pull request #9706 from derdeagle/develop
Fixes #9705: Prevent syntax error in startup.sh
2021-06-23 14:31:32 -07:00
snipe
c684e5f481 Add @PetriAsi as a contributor 2021-06-23 14:31:16 -07:00
snipe
7b5a6a0085 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	resources/views/partials/forms/edit/company-select.blade.php
2021-06-23 14:30:31 -07:00
snipe
1bc4d1b997 Merge pull request #9717 from PetriAsi/fix/accessories-bulk-set-min-amt
Added #9716: Allow to bulk update accessories min_amt
2021-06-23 14:28:59 -07:00
snipe
ac52ea3463 Porting PR #9720 to develop
Signed-off-by: snipe <snipe@snipe.net>
2021-06-23 14:27:15 -07:00
snipe
a521ef706f Merge pull request #9720 from bmkalle/patch-1
Update company-select.blade.php
2021-06-23 14:26:29 -07:00
Godfrey M
154adeb9b2 corrected a link color in the dark mode yellow skin 2021-06-23 14:06:36 -07:00
Petri Asikainen
491a788cd0 testing image upload via api 2021-06-23 11:22:41 +03:00
snipe
a67ce965ec Update version.php 2021-06-22 20:13:03 -07:00
snipe
3e102bf57b Be more specific in accessory query
Signed-off-by: snipe <snipe@snipe.net>
2021-06-19 16:49:13 -07:00
snipe
cdcb153b1e Merge remote-tracking branch 'origin/develop' 2021-06-19 16:20:35 -07:00
snipe
0153c6ae96 Do not try to add the notes column if it already exists on accessories_users
Signed-off-by: snipe <snipe@snipe.net>
2021-06-19 16:20:22 -07:00
bmkalle
a330dca7d4 Update company-select.blade.php
select should be disabled if full multiple companies is activated and the user isn't a superuser. otherwise the user get the ability to choose all companies.
2021-06-17 10:51:00 +02:00
Petri Asikainen
ae2c77f97f Allow to bulk update min_amt 2021-06-17 00:36:04 +03:00
GMS ICT 2
ea7f18d0e6 add CompanyableTrait 2021-06-15 15:32:44 +07:00
Joly0
9a429952ff update print.blade.php 2021-06-15 08:52:01 +02:00
Johannes Münch
8f4b88a877 Fixes #9705 Prevent syntax error in startup.sh
If SESSION_DRIVER is not defined it leads to a syntax error.
2021-06-12 20:21:43 +02:00
Joly0
72f27ccc5b Update print.blade.php 2021-06-11 11:05:39 +02:00
snipe
8cd78b2790 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2021-06-10 17:44:17 -07:00
snipe
aae6a8fc6c Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2021-06-10 17:42:29 -07:00
snipe
ace7abc1ad Merge remote-tracking branch 'origin/develop' 2021-06-10 15:18:24 -07:00
snipe
c567ad0617 Add @travismiller as a contributor 2021-06-10 15:18:02 -07:00
snipe
4c007ae085 Merge remote-tracking branch 'origin/develop' 2021-06-10 15:17:19 -07:00
snipe
54cb6c050a Merge pull request #9679 from tulsaschoolsdata/serial-number-indexes
Fixed #8486: Add index for asset serial number
2021-06-09 17:36:06 -07:00
snipe
851e5ca96e Merge pull request #9683 from tulsaschoolsdata/9682-company-id-indexes
Thanks!
2021-06-09 17:35:37 -07:00
Travis Miller
103c4325ce Fixed #9682: Add indexes for company_id 2021-06-09 14:29:00 -05:00
Travis Miller
ebe7c2da87 Fixed #8486: Add index for asset serial number 2021-06-09 14:12:35 -05:00
Travis Miller
4f6b1bb12d Fixed #9680: Use Eloquent’s withCount method to count Statuslabel assets 2021-06-09 11:52:04 -05:00
Ivan Nieto Vivanco
bb227cafb2 Added event to trigger the notification. 2021-06-08 13:16:13 -05:00
snipe
6c1dd81e0a Merge pull request #9640 from inietov/fixes/errorexception_invalid_argument_supplied
Fixes an issue when tried to upload a file to an user without actually selecting a file. [ch16471]
2021-05-27 14:03:25 -07:00
Ivan Nieto Vivanco
9f944ad497 Added the 'required' attribute to the input file n the upload file form modal. Added a validation for the UserFilesController if the user doesn't select any file to upload [ch16471]. 2021-05-27 15:48:13 -05:00
snipe
01e3296ff3 Updated hash
Signed-off-by: snipe <snipe@snipe.net>
2021-05-26 15:58:24 -07:00
snipe
7d5a9180e6 Updated hash
Signed-off-by: snipe <snipe@snipe.net>
2021-05-26 15:57:56 -07:00
snipe
9f2b4c721d Allow password reset from user profile
Signed-off-by: snipe <snipe@snipe.net>
2021-05-26 15:32:23 -07:00
snipe
3d008079c9 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-26 14:32:33 -07:00
snipe
b8d413a6b8 Merge pull request #9632 from inietov/fixes/api_allow_duplicate_asset_tags
Fixes an issue that allows duplicate asset tags when the Asset is created via API.
2021-05-26 13:34:59 -07:00
snipe
30a193502f Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-26 13:27:20 -07:00
snipe
11f1b29db9 Add @kcoyo as a contributor 2021-05-26 13:04:51 -07:00
snipe
200d0804ec Merge pull request #9630 from kcoyo/develop
Fixed #9607: Sessions expire for SAML/RemoteUser/LDAP
2021-05-26 13:04:13 -07:00
Ivan Nieto Vivanco
d9f5f1182a Delete a couple lines that rewrites validation rules for asset tags in the model Asset.php:save() method. 2021-05-25 23:09:27 -05:00
snipe
3f09d17389 Fixed typo “synchronization”
Signed-off-by: snipe <snipe@snipe.net>
2021-05-25 18:45:06 -07:00
kcoyo
55555ee233 Merge pull request #1 from kcoyo/Fixed-#9607---Sessions-expire-for-SAML/RemoteUser/LDAP
Fixed #9607 - Sessions expire for SAML/RemoteUser/LDAP
2021-05-25 16:44:08 -07:00
kcoyo
cee6f0d579 Update LoginController.php
Fixed #9607 - Sessions expire for SAML/RemoteUser/LDAP
2021-05-25 16:37:34 -07:00
snipe
5b4550a6a8 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-21 16:56:15 -07:00
snipe
1a7edb3411 Accept webp in uploads (not just image files)
Signed-off-by: snipe <snipe@snipe.net>
2021-05-21 16:56:11 -07:00
snipe
796c7c8431 Merge pull request #9619 from uberbrady/migrator_misses_logos
Several improvements to the snipeit:restore Artisan command
2021-05-21 16:02:55 -07:00
Brady Wetherington
94c1d36e08 The legacy 'logo.png' might not be a PNG, so switched to wildcard. 2021-05-21 15:55:37 -07:00
Brady Wetherington
e71bba441e Several improvements to the snipeit:restore Artisan command
The output now focuses on files that were skipped. Wildcard support
was added for individual files. A progress bar fills as the files
are transferred from the ZIPball to the filesystem. A new command-line
switch can be used to disable the progress bar. Barcode restores are
now skipped (we'd probably prefer to regenerate them). A few missed
directories have been added in. Some logic to skip macOS resource-fork
files has been put in. Some bugs with array operations were fixed.
There's now a concept of 'valid' and 'invalid' files for wildcard
operations.
2021-05-21 15:23:23 -07:00
Sabir Manandhar
c3d75d3be3 feat[docker]: create session table migration if session driver is set to database (#9587) 2021-05-20 14:31:22 -07:00
snipe
9eea46adef Fixed parse error in user print view
Signed-off-by: snipe <snipe@snipe.net>
2021-05-20 13:53:43 -07:00
sabir-dzangolab
19766a0a72 Fix/startup-sh (#9586)
* fix: update docker/startup.sh broken after merging hotfixs/2fa_qr

* fix: Typo in Dockerfile.alpine
2021-05-17 15:39:05 -07:00
Marc Leuser
4030789786 fix LicenseSeatsController method documentation (#9584)
in an attempt to get the automatic API reference generation to work
2021-05-14 16:14:32 -07:00
Jonathon Reinhart
fd082addff Fix incorrect case of ldap sync status string (#9563)
Fixes #9562
2021-05-12 19:15:39 -07:00
snipe
d636566012 Merge remote-tracking branch 'origin/master' into develop 2021-05-12 17:45:06 -07:00
Brady Wetherington
6066005aeb [WIP] Initial rough stabs at the Backup Migrator. It kinda-sorta works? (#9457)
* Initial rough stabs at the Backup Migrator. It kinda-sorta works?

* Fix hardcoded mysql path var
2021-05-12 17:44:39 -07:00
snipe
76897f3a3a Make label printing from asset page more consistent with normal UI
Signed-off-by: snipe <snipe@snipe.net>
2021-05-12 17:08:53 -07:00
snipe
c1babdc9b0 Merge remote-tracking branch 'origin/develop' 2021-05-12 16:51:57 -07:00
snipe
1a95337db1 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-12 16:51:39 -07:00
Ivan Nieto Vivanco
6ed5dff1a5 Fix the target path to copy the demo logos in the database\seeds\SettingsSeeder.php. Also added the code that copies the demo logos to app\Console\Commands\ResetDemoSettings.php (#9571) 2021-05-12 16:41:49 -07:00
snipe
3f559c4a50 Add @tbrconnect as a contributor 2021-05-12 13:38:56 -07:00
tbrconnect
a29ef73346 Feature #3088 Print labels from asset detail page (#9559)
This PR adds a "Generate Label" button to the detail asset page as
described in #3088.

Fixes #3088

Co-authored-by: tilmann.bitterberg <tilmann@tbrglobal.com>
2021-05-12 13:38:26 -07:00
snipe
015ca1fcdc Merge remote-tracking branch 'origin/develop' 2021-05-07 18:13:22 -07:00
snipe
ded61614d1 Attempt to fix transient LDAP bug
Signed-off-by: snipe <snipe@snipe.net>
2021-05-07 18:13:04 -07:00
Brady Wetherington
62199f6255 Manually re-add support for Label Logos in Labels (#9552) 2021-05-07 17:01:32 -07:00
snipe
75b89b5a97 Merge remote-tracking branch 'origin/develop' 2021-05-07 16:42:41 -07:00
snipe
a704614397 Bumped max for country on model
Signed-off-by: snipe <snipe@snipe.net>
2021-05-07 16:42:26 -07:00
snipe
2dcb50d28e Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-07 16:36:12 -07:00
snipe
9aac3ae628 Fixed HTML causing two backup headers to appear
Signed-off-by: snipe <snipe@snipe.net>
2021-05-07 16:36:07 -07:00
Tom Misilo
397e2df3ea Upgrade the Alpine docker img to v3.13 for PHP 7.4 (#9550)
v3.13 of the alpine image has php7.4 instead of php7.3
2021-05-07 13:50:36 -07:00
Tom Misilo
4e408cbc42 Fix CSP Always being Enabled unless in debug mode. (#9543) 2021-05-05 10:51:47 -07:00
snipe
570a31a1c4 Merge remote-tracking branch 'origin/develop' 2021-05-05 10:29:10 -07:00
snipe
ece627b3a3 Small fixes for location printing when relationships are missing/invalid, per #9521
Signed-off-by: snipe <snipe@snipe.net>
2021-05-05 10:23:46 -07:00
snipe
d8d3fa2293 Only show department if it’s valid
Signed-off-by: snipe <snipe@snipe.net>
2021-05-05 10:13:19 -07:00
snipe
ab694347b0 Added favicon to demo dir
Signed-off-by: snipe <snipe@snipe.net>
2021-05-05 01:18:49 -07:00
snipe
aa98e4ea7a Bumped hash
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2021-05-05 00:04:17 -07:00
snipe
6935d94184 Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2021-05-05 00:03:33 -07:00
snipe
d9d5b4d730 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	README.md
2021-05-05 00:01:09 -07:00
Ivan Nieto Vivanco
36a43642d8 Changed the orderBy clause inside the custom reports function that forms the CSV to be 'id' so making it a unique value and don't causes repeated items. [ch14587] (#9535) 2021-05-04 23:50:02 -07:00
snipe
ed98683496 Add @mikecmpbll as a contributor 2021-05-04 22:40:04 -07:00
snipe
c2dc7ac182 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-04 22:39:24 -07:00
Dampfklon
37f7768e7a Fix Dockerfile.alpine build error and snipeit runtime permission error (#9520) 2021-05-04 22:29:24 -07:00
snipe
c1a8b609ea Add @markbrule as a contributor 2021-05-04 22:27:35 -07:00
markbrule
6c1553167d issue #9422 - pivot ID was being used as a user_id (#9512) 2021-05-04 22:27:01 -07:00
snipe
c572c98361 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2021-05-04 22:21:35 -07:00
snipe
6c0af3c6e1 Add @JohnnyPicnic as a contributor 2021-05-04 22:21:18 -07:00
snipe
715b1a0fb2 Fixed #9157 Update .env to API_TOKEN_EXPIRATION_YEARS=15 (reapplies #9524)
Signed-off-by: snipe <snipe@snipe.net>
2021-05-04 22:20:54 -07:00
Tom Misilo
a6bbe1fec3 Delete file from assets folder, not just the ref. (#9525) 2021-05-04 22:18:22 -07:00
snipe
67ac3631df Production assets
Signed-off-by: snipe <snipe@snipe.net>
2021-05-04 22:05:26 -07:00
snipe
5760b76c4e Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/skin-black-dark.css
#	public/css/dist/skins/skin-black-dark.min.css
#	public/css/dist/skins/skin-black.css
#	public/css/dist/skins/skin-black.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-blue.css
#	public/css/dist/skins/skin-blue.min.css
#	public/css/dist/skins/skin-contrast.css
#	public/css/dist/skins/skin-contrast.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-green.css
#	public/css/dist/skins/skin-green.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-orange.css
#	public/css/dist/skins/skin-orange.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-purple.css
#	public/css/dist/skins/skin-purple.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/css/dist/skins/skin-red.css
#	public/css/dist/skins/skin-red.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/css/dist/skins/skin-yellow.css
#	public/css/dist/skins/skin-yellow.min.css
#	public/mix-manifest.json
2021-05-04 22:03:56 -07:00
snipe
57b9b571dc Fixed #9531 - highlight search box when filled, add clear button (#9534) 2021-05-04 22:00:34 -07:00
snipe
62f091e769 Merge remote-tracking branch 'origin/develop' 2021-04-30 15:38:02 -07:00
snipe
cee5eea121 Use 24-hour date format for audit
Signed-off-by: snipe <snipe@snipe.net>
2021-04-30 15:37:39 -07:00
snipe
c6726015f7 Added missing use statement
Signed-off-by: snipe <snipe@snipe.net>
2021-04-30 14:52:08 -07:00
1287 changed files with 25125 additions and 4078 deletions

View File

@@ -2308,10 +2308,208 @@
]
},
{
"login": "Nevets82",
"name": "Steven",
"avatar_url": "https://avatars.githubusercontent.com/u/4462739?v=4",
"profile": "http://nevets82.github.io",
"login": "JohnnyPicnic",
"name": "JohnnyPicnic",
"avatar_url": "https://avatars.githubusercontent.com/u/5553884?v=4",
"profile": "https://github.com/JohnnyPicnic",
"contributions": [
"code"
]
},
{
"login": "markbrule",
"name": "markbrule",
"avatar_url": "https://avatars.githubusercontent.com/u/8799594?v=4",
"profile": "https://github.com/markbrule",
"contributions": [
"code"
]
},
{
"login": "mikecmpbll",
"name": "Mike Campbell",
"avatar_url": "https://avatars.githubusercontent.com/u/1962801?v=4",
"profile": "https://github.com/mikecmpbll",
"contributions": [
"code"
]
},
{
"login": "tbrconnect",
"name": "tbrconnect",
"avatar_url": "https://avatars.githubusercontent.com/u/11973217?v=4",
"profile": "https://github.com/tbrconnect",
"contributions": [
"code"
]
},
{
"login": "kcoyo",
"name": "kcoyo",
"avatar_url": "https://avatars.githubusercontent.com/u/12447225?v=4",
"profile": "https://github.com/kcoyo",
"contributions": [
"code"
]
},
{
"login": "travismiller",
"name": "Travis Miller",
"avatar_url": "https://avatars.githubusercontent.com/u/494017?v=4",
"profile": "https://travismiller.com/",
"contributions": [
"code"
]
},
{
"login": "PetriAsi",
"name": "Petri Asikainen",
"avatar_url": "https://avatars.githubusercontent.com/u/8735148?v=4",
"profile": "https://github.com/PetriAsi",
"contributions": [
"code"
]
},
{
"login": "derdeagle",
"name": "derdeagle",
"avatar_url": "https://avatars.githubusercontent.com/u/11424540?v=4",
"profile": "https://github.com/derdeagle",
"contributions": [
"code"
]
},
{
"login": "vapier",
"name": "Mike Frysinger",
"avatar_url": "https://avatars.githubusercontent.com/u/176950?v=4",
"profile": "https://wh0rd.org/",
"contributions": [
"code"
]
},
{
"login": "AL4AL",
"name": "ALPHA",
"avatar_url": "https://avatars.githubusercontent.com/u/22044358?v=4",
"profile": "https://github.com/AL4AL",
"contributions": [
"code"
]
},
{
"login": "FliegenKLATSCH",
"name": "FliegenKLATSCH",
"avatar_url": "https://avatars.githubusercontent.com/u/1042587?v=4",
"profile": "https://www.ifern.de",
"contributions": [
"code"
]
},
{
"login": "jerm",
"name": "Jeremy Price",
"avatar_url": "https://avatars.githubusercontent.com/u/442138?v=4",
"profile": "https://github.com/jerm",
"contributions": [
"code"
]
},
{
"login": "Toreg87",
"name": "Toreg87",
"avatar_url": "https://avatars.githubusercontent.com/u/84392209?v=4",
"profile": "https://github.com/Toreg87",
"contributions": [
"code"
]
},
{
"login": "Computroniks",
"name": "Matthew Nickson",
"avatar_url": "https://avatars.githubusercontent.com/u/67638596?v=4",
"profile": "https://github.com/Computroniks",
"contributions": [
"code"
]
},
{
"login": "jethron",
"name": "Jethro Nederhof",
"avatar_url": "https://avatars.githubusercontent.com/u/1646397?v=4",
"profile": "https://jethron.id.au",
"contributions": [
"code"
]
},
{
"login": "01ste02",
"name": "Oskar Stenberg",
"avatar_url": "https://avatars.githubusercontent.com/u/23289826?v=4",
"profile": "https://github.com/01ste02",
"contributions": [
"code"
]
},
{
"login": "Robert-Azelis",
"name": "Robert-Azelis",
"avatar_url": "https://avatars.githubusercontent.com/u/82208283?v=4",
"profile": "https://github.com/Robert-Azelis",
"contributions": [
"code"
]
},
{
"login": "alwism",
"name": "Alexander William Smith",
"avatar_url": "https://avatars.githubusercontent.com/u/60648387?v=4",
"profile": "https://github.com/alwism",
"contributions": [
"code"
]
},
{
"login": "leitwerk-ag",
"name": "LEITWERK AG",
"avatar_url": "https://avatars.githubusercontent.com/u/24418301?v=4",
"profile": "https://www.leitwerk.de/",
"contributions": [
"code"
]
},
{
"login": "adamboutcher",
"name": "Adam",
"avatar_url": "https://avatars.githubusercontent.com/u/1911435?v=4",
"profile": "http://www.aboutcher.co.uk",
"contributions": [
"code"
]
},
{
"login": "sneak-it",
"name": "Ian",
"avatar_url": "https://avatars.githubusercontent.com/u/16104273?v=4",
"profile": "https://snksrv.com",
"contributions": [
"code"
]
},
{
"login": "bestlong",
"name": "Shao Yu-Lung (Allen)",
"avatar_url": "https://avatars.githubusercontent.com/u/4023909?v=4",
"profile": "http://blog.bestlong.idv.tw/",
"contributions": [
"code"
]
},
{
"login": "Haxatron",
"name": "Haxatron",
"avatar_url": "https://avatars.githubusercontent.com/u/76475453?v=4",
"profile": "https://github.com/Haxatron",
"contributions": [
"code"
]

View File

@@ -77,7 +77,7 @@ ENCRYPT=false
COOKIE_NAME=snipeit_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
API_TOKEN_EXPIRATION_YEARS=40
API_TOKEN_EXPIRATION_YEARS=15
# --------------------------------------------
# OPTIONAL: SECURITY HEADER SETTINGS

View File

@@ -1,62 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
#### Please confirm you have done the following before posting your bug report:
- [ ] I have enabled debug mode
- [ ] I have read [checked the Common Issues page](https://snipe-it.readme.io/docs/common-issues)
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server (please complete the following information):**
- Snipe-IT Version
- OS: [e.g. Ubuntu, CentOS]
- Web Server: [e.g. Apache, IIS]
- PHP Version
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Error Messages**
- WITH DEBUG TURNED ON, if you're getting an error in your browser, include that error
- If a stacktrace is provided in the error, include that too.
- Any errors that appear in your browser's error console.
- Confirm whether the error is reproducible on the demo: https://snipeitapp.com/demo.
- Include any additional information you can find in `storage/logs` and your webserver's logs.
- Include the output from `php -m` (this should display what modules you have enabled.)
**Additional context**
- Is this a fresh install or an upgrade?
- What OS and web server you're running Snipe-IT on
- What method you used to install Snipe-IT (install.sh, manual installation, docker, etc)
- Include what you've done so far in the installation, and if you got any error messages along the way.
- Indicate whether or not you've manually edited any data directly in the database
Add any other context about the problem here.
Please do not post an issue without answering the related questions above. If you have opened a different issue and already answered these questions, answer them again, once for every ticket. It will be next to impossible for us to help you.

View File

@@ -1,23 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Server (please complete the following information):**
- Snipe-IT Version
- OS: [e.g. Ubuntu, CentOS]
- Web Server: [e.g. Apache, IIS]
- PHP Version
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

129
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,129 @@
name: Bug Report
description: Create a report to help us improve
body:
- type: checkboxes
attributes:
label: Debug mode
description: Please confirm you have done the following before posting your bug report
options:
- label: I have enabled debug mode
required: true
- label: I have read [checked the Common Issues page](https://snipe-it.readme.io/docs/common-issues)
required: true
- type: textarea
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Reproduction steps
description: Steps to reproduce the behavior.
value: |
1.
2.
3.
...
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Screenshots
description: 'If applicable, add screenshots to help explain your problem.'
- type: markdown
attributes:
value: "### Server"
- type: input
attributes:
label: Snipe-IT Version
validations:
required: true
- type: input
id: server_operatingSystem
attributes:
label: Operating System
description: 'e.g. Ubuntu, Windows'
validations:
required: true
- type: input
attributes:
label: Web Server
description: 'e.g. Apache, IIS'
validations:
required: true
- type: input
attributes:
label: PHP Version
validations:
required: true
- type: markdown
attributes:
value: "### Desktop"
- type: input
id: desktop_operatingSystem
attributes:
label: Operating System
description: 'e.g. Ubuntu, Windows'
- type: input
id: desktop_browser
attributes:
label: Browser
description: 'e.g. Google Chrome, Safari'
- type: input
id: desktop_version
attributes:
label: Version
description: 'e.g. 93'
- type: markdown
attributes:
value: "### Mobile"
- type: input
attributes:
label: Device
description: 'e.g. iPhone 6, Pixel 4a'
- type: input
id: mobile_operatingSystem
attributes:
label: Operating System
description: 'e.g. iOS 8.1, Android 9'
- type: input
id: mobile_browser
attributes:
label: Browser
description: 'e.g. Google Chrome, Safari'
- type: input
id: mobile_version
attributes:
label: Version
description: 'e.g. 93'
- type: textarea
attributes:
label: Error messages
description: |
WITH DEBUG TURNED ON, if you're getting an error in your browser, include that error
If a stacktrace is provided in the error, include that too.
Any errors that appear in your browser's error console.
Confirm whether the error is reproducible on the demo: https://snipeitapp.com/demo.
Include any additional information you can find in `storage/logs` and your webserver's logs.
Include the output from `php -m` (this should display what modules you have enabled.)
render: shell
- type: textarea
attributes:
label: Additional context
description: |
Is this a fresh install or an upgrade?
What OS and web server you're running Snipe-IT on
What method you used to install Snipe-IT (install.sh, manual installation, docker, etc)
Include what you've done so far in the installation, and if you got any error messages along the way.
Indicate whether or not you've manually edited any data directly in the database
Add any other context about the problem here.
- type: markdown
attributes:
value: Please do not post an issue without answering the related questions above. If you have opened a different issue and already answered these questions, answer them again, once for every ticket. It will be next to impossible for us to help you.

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -0,0 +1,42 @@
name: Feature Request
description: Suggest an idea for this project
body:
- type: input
attributes:
label: Snipe-IT Version
validations:
required: true
- type: input
id: server_operatingSystem
attributes:
label: Operating System
description: 'e.g. Ubuntu, Windows'
validations:
required: true
- type: input
attributes:
label: Web Server
description: 'e.g. Apache, IIS'
validations:
required: true
- type: input
attributes:
label: PHP Version
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional context Add any other context or screenshots about the feature request here.

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

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

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

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

2
.gitignore vendored
View File

@@ -63,3 +63,5 @@ _ide_helper.php
.phpstorm.meta.php
_ide_helper_models.php
/.phplint-cache
storage/ldap_client_tls.cert
storage/ldap_client_tls.key

View File

@@ -1,5 +1,5 @@
FROM ubuntu:bionic
LABEL maintainer Brady Wetherington <uberbrady@gmail.com>
FROM ubuntu:focal
LABEL maintainer Brady Wetherington <bwetherington@grokability.com>
# No need to add `apt-get clean` here, reference:
# - https://github.com/snipe/snipe-it/pull/9201
@@ -14,15 +14,15 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
apt-utils \
apache2 \
apache2-bin \
libapache2-mod-php7.2 \
php7.2-curl \
php7.2-ldap \
php7.2-mysql \
php7.2-gd \
php7.2-xml \
php7.2-mbstring \
php7.2-zip \
php7.2-bcmath \
libapache2-mod-php7.4 \
php7.4-curl \
php7.4-ldap \
php7.4-mysql \
php7.4-gd \
php7.4-xml \
php7.4-mbstring \
php7.4-zip \
php7.4-bcmath \
patch \
curl \
wget \
@@ -38,7 +38,7 @@ autoconf \
libc-dev \
pkg-config \
libmcrypt-dev \
php7.2-dev \
php7.4-dev \
ca-certificates \
unzip \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -47,16 +47,16 @@ unzip \
RUN curl -L -O https://github.com/pear/pearweb_phars/raw/master/go-pear.phar
RUN php go-pear.phar
RUN pecl install mcrypt-1.0.2
RUN pecl install mcrypt-1.0.3
RUN bash -c "echo extension=/usr/lib/php/20170718/mcrypt.so > /etc/php/7.2/mods-available/mcrypt.ini"
RUN bash -c "echo extension=/usr/lib/php/20190902/mcrypt.so > /etc/php/7.4/mods-available/mcrypt.ini"
RUN phpenmod mcrypt
RUN phpenmod gd
RUN phpenmod bcmath
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.2/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.2/cli/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.4/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.4/cli/php.ini
RUN useradd -m --uid 1000 --gid 50 docker
@@ -96,6 +96,8 @@ RUN \
&& rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \
&& mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \
&& ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
&& chown docker "/var/lib/snipeit/keys/" \
&& chown -h docker "/var/www/html/storage/" \
&& chmod +x /var/www/html/artisan \

View File

@@ -1,4 +1,4 @@
FROM alpine:3.12
FROM alpine:3
# Apache + PHP
RUN apk add --no-cache \
apache2 \
@@ -57,7 +57,7 @@ RUN \
&& mkdir -p "/var/lib/snipeit/dumps" && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \
&& mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \
&& ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \
&& chown -h "/var/www/html/storage/*.key"
&& chown -hR apache "/var/www/html/storage/" \
&& chown -R apache "/var/lib/snipeit"
# Install composer

1
Procfile Normal file
View File

@@ -0,0 +1 @@
web: php heroku/startup.php && heroku-php-apache2 public/

View File

@@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-254-orange.svg?style=flat-square)](#contributors)
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-276-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@@ -19,6 +19,8 @@ For instructions on installing and configuring Snipe-IT on your server, check ou
If you're having trouble with the installation, please check the [Common Issues](https://snipe-it.readme.io/docs/common-issues) and [Getting Help](https://snipe-it.readme.io/docs/getting-help) documentation, and search this repository's open *and* closed issues for help.
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
-----
### User's Manual
For help using Snipe-IT, check out the [user's manual](https://snipe-it.readme.io/docs/overview).
@@ -55,11 +57,11 @@ Since the release of the JSON REST API, several third-party developers have been
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
- [InQRy](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
- [jamf2snipe](https://github.com/ParadoxGuitarist/jamf2snipe) by [@ParadoxGuitarist](https://github.com/ParadoxGuitarist) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
- [Marksman](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
- [Snipe-IT plugin for Jira Service Desk (beta)](https://marketplace.atlassian.com/apps/1220379/snipe-it-for-jira-service-desk-beta?hosting=cloud&tab=overview) - for the upcoming Snipe-IT v5 only
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
@@ -125,7 +127,10 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/915514?v=4" width="110px;"/><br /><sub>Kevin Köllmann</sub>](https://www.kevinkoellmann.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koelle25 "Code") | [<img src="https://avatars.githubusercontent.com/u/49025941?v=4" width="110px;"/><br /><sub>sw-mreyes</sub>](https://github.com/sw-mreyes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sw-mreyes "Code") | [<img src="https://avatars.githubusercontent.com/u/70129?v=4" width="110px;"/><br /><sub>Joel Pittet</sub>](https://pittet.ca)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joelpittet "Code") | [<img src="https://avatars.githubusercontent.com/u/792695?v=4" width="110px;"/><br /><sub>Eli Young</sub>](https://elyscape.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=elyscape "Code") | [<img src="https://avatars.githubusercontent.com/u/317015?v=4" width="110px;"/><br /><sub>Raell Dottin</sub>](https://github.com/raelldottin)<br />[💻](https://github.com/snipe/snipe-it/commits?author=raelldottin "Code") | [<img src="https://avatars.githubusercontent.com/u/1446856?v=4" width="110px;"/><br /><sub>Tom Misilo</sub>](https://github.com/misilot)<br />[💻](https://github.com/snipe/snipe-it/commits?author=misilot "Code") | [<img src="https://avatars.githubusercontent.com/u/4496300?v=4" width="110px;"/><br /><sub>David Davenne</sub>](http://david.davenne.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JuustoMestari "Code") |
| [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") |
| [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") |
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/4462739?v=4" width="110px;"/><br /><sub>Steven</sub>](http://nevets82.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Nevets82 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [<img src="https://avatars.githubusercontent.com/u/11973217?v=4" width="110px;"/><br /><sub>tbrconnect</sub>](https://github.com/tbrconnect)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") | [<img src="https://avatars.githubusercontent.com/u/12447225?v=4" width="110px;"/><br /><sub>kcoyo</sub>](https://github.com/kcoyo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kcoyo "Code") | [<img src="https://avatars.githubusercontent.com/u/494017?v=4" width="110px;"/><br /><sub>Travis Miller</sub>](https://travismiller.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=travismiller "Code") |
| [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") | [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") | [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") |
| [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -199,7 +199,7 @@
- { regexp: '^DB_PASSWORD=', line: 'DB_PASSWORD=vagrant' }
- { regexp: '^APP_URL=', line: "APP_URL=http://{{ fqdn }}" }
- { regexp: '^APP_ENV=', line: "APP_ENV=development" }
- { regexp: '^APP_DEBUG=', line: "APP_ENV=true" }
- { regexp: '^APP_DEBUG=', line: "APP_DEBUG=true" }
- name: Generate application key
shell: "php {{ app_path }}/artisan key:generate --force"
- name: Artisan Migrate

154
app.json Normal file
View File

@@ -0,0 +1,154 @@
{
"name": "Snipe-IT",
"description": "Open source asset management.",
"keywords": [
"asset management",
"it asset"
],
"website": "https://snipeitapp.com/",
"repository": "https://github.com/snipe/snipe-it",
"logo": "https://pbs.twimg.com/profile_images/976748875733020672/K-HnZCCK_400x400.jpg",
"success_url": "/setup",
"env": {
"APP_ENV": {
"description": "Laravel environment mode. Unless developing the application, this should be production.",
"value": "production"
},
"APP_DEBUG": {
"description": "Laravel debug mode. Unless developing the application or actively debugging a problem, this should be set to false.",
"value": "false"
},
"APP_KEY": {
"description": "A secret key for verifying the integrity of signed cookies. (See either https://snipe-it.readme.io/docs/generate-your-app-key or generate at https://coderstoolbox.online/toolbox/generate-symfony-secret)",
"value": ""
},
"APP_URL": {
"description": "URL where your Snipe-IT install will be available at.",
"value": "https://your-app-name.herokuapp.com"
},
"APP_TIMEZONE": {
"description": "Which timezone do you want to use for your install? (http://php.net/manual/en/timezones.php)",
"value": "UTC"
},
"APP_LOCALE": {
"description": "Which language do you want to use for your install? (https://snipe-it.readme.io/docs/configuration#setting-a-language)",
"value": "en"
},
"MAX_RESULTS": {
"description": "The maximum number of search results that can be returned at one time.",
"value": "500"
},
"MAIL_DRIVER": {
"description": "Mail driver - Generally SMTP on Heroku - https://snipe-it.readme.io/docs/configuration#required-outgoing-mail-settings",
"value": "smtp"
},
"MAIL_HOST": {
"description": "SMTP Server Hostname",
"value": "smtp.your.domain.name"
},
"MAIL_PORT": {
"description": "SMTP Server Port",
"value": "25"
},
"MAIL_USERNAME": {
"description": "SMTP Server Username",
"value": "YOURUSERNAME"
},
"MAIL_PASSWORD": {
"description": "SMTP Server Password",
"value": "YOURPASSWORD"
},
"MAIL_ENCRYPTION": {
"description": "Encryption protocol for email sending.",
"value": "null"
},
"MAIL_FROM_ADDR": {
"description": "Email from address",
"value": "no-reply@domain.name"
},
"MAIL_FROM_NAME": {
"description": "Email from Name",
"value": "Snipe-IT"
},
"MAIL_REPLYTO_ADDR": {
"description": "Email Reply-To address",
"value": "your@domain.name"
},
"MAIL_REPLYTO_NAME": {
"description": "Email Reply-To Name",
"value": "Snipe-IT"
},
"MAIL_AUTO_EMBED": {
"description": "Whether or not to embed images in emails (via CID or base64) versus linking to them.",
"value": "true"
},
"MAIL_AUTO_EMBED_METHOD": {
"description": "Method that should be used for attaching inline images.",
"value": "base64"
},
"SESSION_LIFETIME": {
"description": "Specify the time in minutes that the session should remain valid.",
"value": "12000"
},
"EXPIRE_ON_CLOSE": {
"description": "Specify whether or not the logged in session should be expired when the user closes their browser window.",
"value": "false"
},
"ENCRYPT": {
"description": "Specify whether you wish to use encrypted cookies for your Snipe-IT sessions.",
"value": "true"
},
"COOKIE_NAME": {
"description": "The name of the cookie set by Snipe-IT for session management.",
"value": "snipeit_session"
},
"COOKIE_DOMAIN": {
"description": "The domain name that the session cookie should be sent for.",
"value": "your-app-name.herokuapp.com"
},
"SECURE_COOKIES": {
"description": "Should cookies only be sent for HTTPS connections? Generally true on Heroku.",
"value": "true"
},
"LOGIN_MAX_ATTEMPTS": {
"description": "The maximum number of failed attempts allowed before the user is throttled.",
"value": "5"
},
"LOGIN_LOCKOUT_DURATION": {
"description": "The duration (in seconds) that the user should be blocked from attempting to authenticate again.",
"value": "60"
},
"APP_LOG": {
"description": "Driver to send logs to. (errorlog for stderr)",
"value": "errorlog"
},
"ALLOW_IFRAMING": {
"description": "Allow Snipe-IT to be loaded using an iFrame?",
"value": "false"
},
"GOOGLE_MAPS_API": {
"description": "Include your Google Maps API key here if you'd like Snipe-IT to load maps from Google on your locations and suppliers pages.",
"required": false
},
"BACKUP_ENV": {
"description": "Set this to true if you wish to backup your .env file in your Admin > Backups process.",
"value": "true"
},
"ENABLE_HSTS": {
"description": "Whether or not to send the HSTS security policy header.",
"value": "false"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "free"
}
},
"image": "heroku/php",
"addons": [
"cleardb:ignite",
"heroku-redis:hobby-dev",
"papertrail:choklad"
]
}

View File

@@ -2,23 +2,9 @@
namespace App\Console\Commands;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\Department;
use App\Models\Depreciation;
use App\Models\Group;
use App\Models\Import;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\CustomField;
use Schema;
use DB;
use Illuminate\Console\Command;
@@ -29,15 +15,14 @@ class PaveIt extends Command
*
* @var string
*/
protected $signature = 'snipeit:pave
{--soft : Perform a "Soft" Delete, leaving all migrations, table structure, and the first user in place.}';
protected $signature = 'snipeit:pave {--force : Skip the interactive yes/no prompt for confirmation}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Pave the database to start over. This should ALMOST NEVER BE USED. (It is primarily a quick tool for developers.)';
protected $description = 'Clear the database tables, leaving all migrations, table structure, and the first user in place. (It is primarily a quick tool for developers.) If you want to destroy all tables as well, use php artisan db:wipe.';
/**
* Create a new command instance.
@@ -56,106 +41,51 @@ class PaveIt extends Command
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nTHIS WILL DELETE ALL OF THE DATA IN YOUR DATABASE. \nThere is NO undo. This WILL destroy ALL of your data. \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) {
if ($this->option('soft')) {
Accessory::getQuery()->delete();
Asset::getQuery()->delete();
Category::getQuery()->delete();
Company::getQuery()->delete();
Component::getQuery()->delete();
Consumable::getQuery()->delete();
Department::getQuery()->delete();
Depreciation::getQuery()->delete();
License::getQuery()->delete();
LicenseSeat::getQuery()->delete();
Location::getQuery()->delete();
Manufacturer::getQuery()->delete();
AssetModel::getQuery()->delete();
Statuslabel::getQuery()->delete();
Supplier::getQuery()->delete();
Group::getQuery()->delete();
Import::getQuery()->delete();
DB::statement('delete from accessories_users');
DB::statement('delete from asset_logs');
DB::statement('delete from asset_maintenances');
DB::statement('delete from login_attempts');
DB::statement('delete from asset_uploads');
DB::statement('delete from action_logs');
DB::statement('delete from checkout_requests');
DB::statement('delete from checkout_acceptances');
DB::statement('delete from consumables_users');
DB::statement('delete from custom_field_custom_fieldset');
DB::statement('delete from custom_fields');
DB::statement('delete from custom_fieldsets');
DB::statement('delete from components_assets');
DB::statement('delete from kits');
DB::statement('delete from kits_accessories');
DB::statement('delete from kits_consumables');
DB::statement('delete from kits_licenses');
DB::statement('delete from kits_models');
DB::statement('delete from login_attempts');
DB::statement('delete from models_custom_fields');
DB::statement('delete from permission_groups');
DB::statement('delete from password_resets');
DB::statement('delete from requested_assets');
DB::statement('delete from requests');
DB::statement('delete from throttle');
DB::statement('delete from users_groups');
DB::statement('delete from users WHERE id!=1');
} else {
\DB::statement('drop table IF EXISTS accessories_users');
\DB::statement('drop table IF EXISTS accessories');
\DB::statement('drop table IF EXISTS asset_logs');
\DB::statement('drop table IF EXISTS action_logs');
\DB::statement('drop table IF EXISTS asset_maintenances');
\DB::statement('drop table IF EXISTS asset_uploads');
\DB::statement('drop table IF EXISTS assets');
\DB::statement('drop table IF EXISTS categories');
\DB::statement('drop table IF EXISTS checkout_requests');
\DB::statement('drop table IF EXISTS checkout_acceptances');
\DB::statement('drop table IF EXISTS companies');
\DB::statement('drop table IF EXISTS components');
\DB::statement('drop table IF EXISTS components_assets');
\DB::statement('drop table IF EXISTS consumables_users');
\DB::statement('drop table IF EXISTS consumables');
\DB::statement('drop table IF EXISTS custom_field_custom_fieldset');
\DB::statement('drop table IF EXISTS custom_fields');
\DB::statement('drop table IF EXISTS custom_fieldsets');
\DB::statement('drop table IF EXISTS depreciations');
\DB::statement('drop table IF EXISTS departments');
\DB::statement('drop table IF EXISTS groups');
\DB::statement('drop table IF EXISTS history');
\DB::statement('drop table IF EXISTS kits');
\DB::statement('drop table IF EXISTS kits_accessories');
\DB::statement('drop table IF EXISTS kits_consumables');
\DB::statement('drop table IF EXISTS kits_licenses');
\DB::statement('drop table IF EXISTS kits_models');
\DB::statement('drop table IF EXISTS models_custom_fields');
\DB::statement('drop table IF EXISTS permission_groups');
\DB::statement('drop table IF EXISTS license_seats');
\DB::statement('drop table IF EXISTS licenses');
\DB::statement('drop table IF EXISTS locations');
\DB::statement('drop table IF EXISTS login_attempts');
\DB::statement('drop table IF EXISTS manufacturers');
\DB::statement('drop table IF EXISTS models');
\DB::statement('drop table IF EXISTS migrations');
\DB::statement('drop table IF EXISTS oauth_access_tokens');
\DB::statement('drop table IF EXISTS oauth_auth_codes');
\DB::statement('drop table IF EXISTS oauth_clients');
\DB::statement('drop table IF EXISTS oauth_personal_access_clients');
\DB::statement('drop table IF EXISTS oauth_refresh_tokens');
\DB::statement('drop table IF EXISTS password_resets');
\DB::statement('drop table IF EXISTS requested_assets');
\DB::statement('drop table IF EXISTS requests');
\DB::statement('drop table IF EXISTS settings');
\DB::statement('drop table IF EXISTS status_labels');
\DB::statement('drop table IF EXISTS suppliers');
\DB::statement('drop table IF EXISTS throttle');
\DB::statement('drop table IF EXISTS users_groups');
\DB::statement('drop table IF EXISTS users');
\DB::statement('drop table IF EXISTS imports');
if (!$this->option('force')) {
$confirmation = $this->confirm("\n****************************************************\nTHIS WILL DELETE ALL OF THE DATA IN YOUR DATABASE. \nThere is NO undo. This WILL destroy ALL of your data, \nINCLUDING ANY non-Snipe-IT tables you have in this database. \n****************************************************\n\nDo you wish to continue? No backsies! ");
if (!$confirmation) {
$this->error('ABORTING');
exit(-1);
}
}
// List all the tables in the database so we don't have to worry about missing some as the app grows
$tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();
$except_tables = [
'oauth_access_tokens',
'oauth_clients',
'oauth_personal_access_clients',
'migrations',
'settings',
'users',
];
// We only need to find out what these are so we can nuke these columns on the assets table.
$custom_fields = CustomField::get();
foreach ($custom_fields as $custom_field) {
$this->info('DROP the '.$custom_field->db_column.' column from assets as well.');
if (\Schema::hasColumn('assets', $custom_field->db_column)) {
\Schema::table('assets', function ($table) use ($custom_field) {
$table->dropColumn($custom_field->db_column);
});
}
}
foreach ($tables as $table) {
if (in_array($table, $except_tables)) {
$this->info($table. ' is SKIPPED.');
} else {
\DB::statement('truncate '.$table);
$this->info($table. ' is TRUNCATED.');
}
}
// Leave in the demo oauth keys so we don't have to reset them every day in the demos
\DB::statement('delete from oauth_clients WHERE id > 2');
\DB::statement('delete from oauth_access_tokens WHERE id > 2');
}
}
}

View File

@@ -81,6 +81,8 @@ class ResetDemoSettings extends Command
$user->save();
}
\Storage::disk('public')->put('snipe-logo.png', file_get_contents(public_path('img/demo/snipe-logo.png')));
\Storage::disk('public')->put('snipe-logo-lg.png', file_get_contents(public_path('img/demo/snipe-logo-lg.png')));
}

View File

@@ -0,0 +1,297 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use ZipArchive;
class RestoreFromBackup extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:restore
{--force : Skip the danger prompt; assuming you hit "y"}
{filename : The zip file to be migrated}
{--no-progress : Don\'t show a progress bar}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Restore from a previously created backup';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$dir = getcwd();
print "Current working directory is: $dir\n";
//
$filename = $this->argument('filename');
if (!$filename) {
return $this->error("Missing required filename");
}
if (!$this->option('force') && !$this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
return $this->error("Data loss not confirmed");
}
if (config('database.default') != 'mysql') {
return $this->error("DB_CONNECTION must be MySQL in order to perform a restore. Detected: ".config('database.default'));
}
$za = new ZipArchive();
$errcode = $za->open($filename/* , ZipArchive::RDONLY */); // that constant only exists in PHP 7.4 and higher
if ($errcode !== true) {
$errors = [
ZipArchive::ER_EXISTS => "File already exists.",
ZipArchive::ER_INCONS => "Zip archive inconsistent.",
ZipArchive::ER_INVAL => "Invalid argument.",
ZipArchive::ER_MEMORY => "Malloc failure.",
ZipArchive::ER_NOENT => "No such file.",
ZipArchive::ER_NOZIP => "Not a zip archive.",
ZipArchive::ER_OPEN => "Can't open file.",
ZipArchive::ER_READ => "Read error.",
ZipArchive::ER_SEEK => "Seek error."
];
return $this->error("Could not access file: ".$filename." - ".array_key_exists($errcode,$errors) ? $errors[$errcode] : " Unknown reason: $errcode");
}
$private_dirs = [
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
'storage/private_uploads/audits',
'storage/private_uploads/imports',
'storage/private_uploads/assetmodels',
'storage/private_uploads/users',
'storage/private_uploads/licenses',
'storage/private_uploads/signatures'
];
$private_files = [
'storage/oauth-private.key',
'storage/oauth-public.key'
];
$public_dirs = [
'public/uploads/companies',
'public/uploads/components',
'public/uploads/categories',
'public/uploads/manufacturers',
//'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated
'public/uploads/consumables',
'public/uploads/departments',
'public/uploads/avatars',
'public/uploads/suppliers',
'public/uploads/assets', // these are asset _pictures_, not asset files
'public/uploads/locations',
'public/uploads/accessories',
'public/uploads/models',
'public/uploads/categories',
'public/uploads/avatars',
'public/uploads/manufacturers'
];
$public_files = [
'public/uploads/logo.*',
'public/uploads/setting-email_logo*',
'public/uploads/setting-label_logo*',
'public/uploads/setting-logo*',
'public/uploads/favicon.*',
'public/uploads/favicon-uploaded.*'
];
$all_files = $private_dirs + $public_dirs;
$sqlfiles = [];
$sqlfile_indices = [];
$interesting_files = [];
$boring_files = [];
for ($i=0; $i<$za->numFiles;$i++) {
$stat_results = $za->statIndex($i);
// echo "index: $i\n";
// print_r($stat_results);
$raw_path = $stat_results['name'];
if(strpos($raw_path,'\\')!==false) { //found a backslash, swap it to forward-slash
$raw_path = strtr($raw_path,'\\','/');
//print "Translating file: ".$stat_results['name']." to: ".$raw_path."\n";
}
// skip macOS resource fork files (?!?!?!)
if(strpos($raw_path,"__MACOSX")!==false && strpos($raw_path,"._") !== false) {
//print "SKIPPING macOS Resource fork file: $raw_path\n";
$boring_files[] = $raw_path;
continue;
}
if(@pathinfo($raw_path)['extension'] == "sql") {
print "Found a sql file!\n";
$sqlfiles[] = $raw_path;
$sqlfile_indices[] = $i;
continue;
}
foreach(array_merge($private_dirs,$public_dirs) as $dir) {
$last_pos = strrpos($raw_path,$dir.'/');
if($last_pos !== false ) {
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
$interesting_files[$raw_path] = ['dest' =>$dir, 'index' => $i];
continue 2;
if($last_pos + strlen($dir) +1 == strlen($raw_path)) {
// we don't care about that; we just want files with the appropriate prefix
//print("FOUND THE EXACT DIRECTORY: $dir AT: $raw_path!!!\n");
}
}
}
$good_extensions = ["png","gif","jpg","svg","jpeg","doc","docx","pdf","txt",
"zip","rar","xls","xlsx","lic","xml","rtf", "webp","key","ico"];
foreach(array_merge($private_files, $public_files) as $file) {
$has_wildcard = (strpos($file,"*") !== false);
if($has_wildcard) {
$file = substr($file,0,-1); //trim last character (which should be the wildcard)
}
$last_pos = strrpos($raw_path,$file); // no trailing slash!
if($last_pos !== false ) {
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
if(!in_array($extension, $good_extensions)) {
$this->warn("Potentially unsafe file ".$raw_path." is being skipped");
$boring_files[] = $raw_path;
continue 2;
}
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//no wildcards found in $file, process 'normally'
if($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it.
// print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though.
$interesting_files[$raw_path] = ['dest' => dirname($file),'index' => $i];
continue 2;
}
}
}
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
} // end of pre-processing the ZIP file for-loop
// print_r($interesting_files);exit(-1);
if( count($sqlfiles) != 1) {
return $this->error("There should be exactly *one* sql backup file found, found: ".( count($sqlfiles) == 0 ? "None" : implode(", ",$sqlfiles)));
}
if( strpos($sqlfiles[0], "db-dumps") === false ) {
//return $this->error("SQL backup file is missing 'db-dumps' component of full pathname: ".$sqlfiles[0]);
//older Snipe-IT installs don't have the db-dumps subdirectory component
}
//how to invoke the restore?
$pipes = [];
$env_vars = getenv();
$env_vars['MYSQL_PWD'] = config("database.connections.mysql.password");
$proc_results = proc_open("mysql -h ".escapeshellarg(config('database.connections.mysql.host'))." -u ".escapeshellarg(config('database.connections.mysql.username'))." ".escapeshellarg(config('database.connections.mysql.database')), // yanked -p since we pass via ENV
[0 => ['pipe','r'],1 => ['pipe','w'],2 => ['pipe','w']],
$pipes,
null,
$env_vars); // this is not super-duper awesome-secure, but definitely more secure than showing it on the CLI, or dropping temporary files with passwords in them.
if($proc_results === false) {
return $this->error("Unable to invoke mysql via CLI");
}
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
// $this->info("Stderr says? ".fgets($pipes[2])); //FIXME: ditto, same.
// should we read stdout?
// fwrite($pipes[0],config("database.connections.mysql.password")."\n"); //this doesn't work :(
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
$sql_stat = $za->statIndex($sqlfile_indices[0]);
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
$sql_contents = $za->getStream($sql_stat['name']);
if ($sql_contents === false) {
$stdout = fgets($pipes[1]);
$this->info($stdout);
$stderr = fgets($pipes[2]);
$this->info($stderr);
return false;
}
while(($buffer = fgets($sql_contents)) !== false ) {
//$this->info("Buffer is: '$buffer'");
$bytes_written = fwrite($pipes[0],$buffer);
if($bytes_written === false) {
$stdout = fgets($pipes[1]);
$this->info($stdout);
$stderr = fgets($pipes[2]);
$this->info($stderr);
return false;
}
}
fclose($pipes[0]);
fclose($sql_contents);
$this->line(stream_get_contents($pipes[1]));
fclose($pipes[1]);
$this->error(stream_get_contents($pipes[2]));
fclose($pipes[2]);
//wait, have to do fclose() on all pipes first?
$close_results = proc_close($proc_results);
if($close_results != 0) {
return $this->error("There may have been a problem with the database import: Error number ".$close_results);
}
//and now copy the files over too (right?)
//FIXME - we don't prune the filesystem space yet!!!!
if($this->option('no-progress')) {
$bar = null;
} else {
$bar = $this->output->createProgressBar(count($interesting_files));
}
foreach($interesting_files AS $pretty_file_name => $file_details) {
$ugly_file_name = $za->statIndex($file_details['index'])['name'];
$fp = $za->getStream($ugly_file_name);
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
$migrated_file = fopen($file_details['dest']."/".basename($pretty_file_name),"w");
while(($buffer = fgets($fp))!== false) {
fwrite($migrated_file,$buffer);
}
fclose($migrated_file);
fclose($fp);
//$this->info("Wrote $ugly_file_name to $pretty_file_name");
if($bar) {
$bar->advance();
}
}
if($bar) {
$bar->finish();
$this->line("");
} else {
$this->info(count($interesting_files)." files were succesfully transferred");
}
foreach($boring_files as $boring_file) {
$this->warn($boring_file." was skipped.");
}
}
}

View File

@@ -121,6 +121,6 @@ class Handler extends ExceptionHandler
*/
protected function invalidJson($request, ValidationException $exception)
{
return response()->json(Helper::formatStandardApiResponse('error', null, $exception->errors(), 400));
return response()->json(Helper::formatStandardApiResponse('error', null, $exception->errors(), 422));
}
}

View File

@@ -46,7 +46,10 @@ class Helper
public static function formatCurrencyOutput($cost)
{
if (is_numeric($cost)) {
return number_format($cost, 2, '.', '');
if (Setting::getSettings()->digit_separator=='1.234,56') {
return number_format($cost, 2, ',', '.');
}
return number_format($cost, 2, '.', ',');
}
// It's already been parsed.
return $cost;
@@ -64,7 +67,7 @@ class Helper
{
$colors = [
"#008941",
"#FF4A46",
"#FF851B",
"#006FA6",
"#A30059",
"#1CE6FF",
@@ -400,6 +403,19 @@ class Helper
*/
public static function ParseFloat($floatString)
{
/*******
*
* WARNING: This does conversions based on *locale* - a Unix-ey-like thing.
*
* Everything else in the system tends to convert based on the Snipe-IT settings
*
* So it's very likely this is *not* what you want - instead look for the new
*
* ParseCurrency($currencyString)
*
* Which should be directly below here
*
*/
$LocaleInfo = localeconv();
$floatString = str_replace(",", "", $floatString);
$floatString = str_replace($LocaleInfo["decimal_point"], ".", $floatString);
@@ -413,6 +429,26 @@ class Helper
$floatString = str_replace($currencySymbol, '', $floatString);
return floatval($floatString);
}
/**
* Format currency using comma or period for thousands, and period or comma for decimal, based on settings.
*
* @author [B. Wetherington] [<bwetherington@grokability.com>]
* @since [v5.2]
* @return Float
*/
public static function ParseCurrency($currencyString) {
$without_currency = str_replace(Setting::getSettings()->default_currency, '', $currencyString); //generally shouldn't come up, since we don't do this in fields, but just in case it does...
if(Setting::getSettings()->digit_separator=='1.234,56') {
//EU format
$without_thousands = str_replace('.', '', $without_currency);
$corrected_decimal = str_replace(',', '.', $without_thousands);
} else {
$without_thousands = str_replace(',', '', $without_currency);
$corrected_decimal = $without_thousands; // decimal is already OK
}
return floatval($corrected_decimal);
}
/**
* Get the list of status labels in an array to make a dropdown menu
@@ -887,7 +923,8 @@ class Helper
// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
$upload_max = Helper::parse_size(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
if ($upload_max > 0 && $upload_max < $post_max_size) {
$max_size = ini_get('upload_max_filesize');
}
}

View File

@@ -74,7 +74,7 @@ class AccessoriesController extends Controller
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = Helper::ParseFloat(request('purchase_cost'));
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->user_id = Auth::user()->id;
$accessory->supplier_id = request('supplier_id');
@@ -137,7 +137,7 @@ class AccessoriesController extends Controller
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = request('purchase_cost');
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');

View File

@@ -13,6 +13,7 @@ use Carbon\Carbon;
use Auth;
use DB;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
class AccessoriesController extends Controller
{
@@ -26,9 +27,23 @@ class AccessoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Accessory::class);
$allowed_columns = ['id','name','model_number','eol','notes','created_at','min_amt','company_id'];
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
$allowed_columns =
[
'id',
'name',
'model_number',
'eol',
'notes',
'created_at',
'min_amt',
'company_id'
];
$accessories = Accessory::with('category', 'company', 'manufacturer', 'users', 'location');
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier');
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
@@ -50,6 +65,10 @@ class AccessoriesController extends Controller
$accessories->where('supplier_id','=',$request->input('supplier_id'));
}
if ($request->filled('location_id')) {
$accessories->where('location_id','=',$request->input('location_id'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($accessories) && ($request->get('offset') > $accessories->count())) ? $accessories->count() : $request->get('offset', 0);
@@ -57,24 +76,32 @@ class AccessoriesController extends Controller
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort) {
switch ($sort_override) {
case 'category':
$accessories = $accessories->OrderCategory($order);
break;
case 'company':
$accessories = $accessories->OrderCompany($order);
break;
case 'location':
$accessories = $accessories->OrderLocation($order);
break;
case 'manufacturer':
$accessories = $accessories->OrderManufacturer($order);
break;
case 'supplier':
$accessories = $accessories->OrderSupplier($order);
break;
default:
$accessories = $accessories->orderBy($sort, $order);
$accessories = $accessories->orderBy($column_sort, $order);
break;
}
$accessories->orderBy($sort, $order);
$total = $accessories->count();
$accessories = $accessories->skip($offset)->take($limit)->get();
return (new AccessoriesTransformer)->transformAccessories($accessories, $total);
@@ -86,14 +113,15 @@ class AccessoriesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Accessory::class);
$accessory = new Accessory;
$accessory->fill($request->all());
$accessory = $request->handleImages($accessory);
if ($accessory->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $accessory, trans('admin/accessories/message.create.success')));
@@ -165,9 +193,13 @@ class AccessoriesController extends Controller
if ($request->filled('search')) {
$accessory_users = $accessory->users()
->where('first_name', 'like', '%'.$request->input('search').'%')
->orWhere('last_name', 'like', '%'.$request->input('search').'%')
->get();
->where(function ($query) use ($request) {
$search_str = '%' . $request->input('search') . '%';
$query->where('first_name', 'like', $search_str)
->orWhere('last_name', 'like', $search_str)
->orWhere('note', 'like', $search_str);
})
->get();
$total = $accessory_users->count();
}
@@ -180,15 +212,16 @@ class AccessoriesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Accessory::class);
$accessory = Accessory::findOrFail($id);
$accessory->fill($request->all());
$accessory = $request->handleImages($accessory);
if ($accessory->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $accessory, trans('admin/accessories/message.update.success')));
@@ -287,7 +320,7 @@ class AccessoriesController extends Controller
$accessory = Accessory::find($accessory_user->accessory_id);
$this->authorize('checkin', $accessory);
$logaction = $accessory->logCheckin(User::find($accessoryUserId), $request->input('note'));
$logaction = $accessory->logCheckin(User::find($accessory_user->user_id), $request->input('note'));
// Was the accessory updated?
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {

View File

@@ -105,7 +105,7 @@ class AssetMaintenancesController extends Controller
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
$assetMaintenance->is_warranty = $request->input('is_warranty');
$assetMaintenance->cost = e($request->input('cost'));
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
$assetMaintenance->notes = e($request->input('notes'));
$asset = Asset::find(e($request->input('asset_id')));
@@ -162,7 +162,7 @@ class AssetMaintenancesController extends Controller
$assetMaintenance->supplier_id = e($request->input('supplier_id'));
$assetMaintenance->is_warranty = e($request->input('is_warranty'));
$assetMaintenance->cost = Helper::ParseFloat(e($request->input('cost')));
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
$assetMaintenance->notes = e($request->input('notes'));
$asset = Asset::find(request('asset_id'));

View File

@@ -9,6 +9,7 @@ use App\Http\Transformers\SelectlistTransformer;
use App\Models\Asset;
use App\Models\AssetModel;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
/**
@@ -66,7 +67,7 @@ class AssetModelsController extends Controller
if ($request->filled('status')) {
if ($request->input('status')=='deleted') {
$assetmodels->onlyTrashed();
}
@@ -107,14 +108,15 @@ class AssetModelsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', AssetModel::class);
$assetmodel = new AssetModel;
$assetmodel->fill($request->all());
$assetmodel = $request->handleImages($assetmodel);
if ($assetmodel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.create.success')));
@@ -159,16 +161,17 @@ class AssetModelsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', AssetModel::class);
$assetmodel = AssetModel::findOrFail($id);
$assetmodel->fill($request->all());
$assetmodel = $request->handleImages($assetmodel);
/**
* Allow custom_fieldset_id to override and populate fieldset_id.
* This is stupid, but required for legacy API support.

View File

@@ -1,13 +1,16 @@
<?php
namespace App\Http\Controllers\Api;
use App\Events\CheckoutableCheckedIn;
use Illuminate\Support\Facades\Gate;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckoutRequest;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\DepreciationReportTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Company;
@@ -20,12 +23,14 @@ use Auth;
use Carbon\Carbon;
use DB;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Input;
use Paginator;
use Slack;
use Str;
use TCPDF;
use Validator;
use Route;
/**
@@ -46,10 +51,32 @@ class AssetsController extends Controller
* @since [v4.0]
* @return JsonResponse
*/
public function index(Request $request, $audit = null)
public function index(Request $request, $audit = null)
{
$this->authorize('index', Asset::class);
\Log::debug(Route::currentRouteName());
/**
* This looks MAD janky (and it is), but the AssetsController@index does a LOT of heavy lifting throughout the
* app. This bit here just makes sure that someone without permission to view assets doesn't
* end up with priv escalations because they asked for a different endpoint.
*
* Since we never gave the specification for which transformer to use before, it should default
* gracefully to just use the AssetTransformer by default, which shouldn't break anything.
*
* It was either this mess, or repeating ALL of the searching and sorting and filtering code,
* which would have been far worse of a mess. *sad face* - snipe (Sept 1, 2021)
*/
if (Route::currentRouteName()=='api.depreciation-report.index') {
$transformer = 'App\Http\Transformers\DepreciationReportTransformer';
$this->authorize('reports.view');
} else {
$transformer = 'App\Http\Transformers\AssetsTransformer';
$this->authorize('index', Asset::class);
}
$settings = Setting::getSettings();
$allowed_columns = [
@@ -88,10 +115,10 @@ class AssetsController extends Controller
}
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier'); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
// These are used by the API to query against specific ID numbers.
// They are also used by the individual searches on detail pages like
// locations, etc.
@@ -243,7 +270,7 @@ class AssetsController extends Controller
$assets->TextSearch($request->input('search'));
}
// This is kinda gross, but we need to do this because the Bootstrap Tables
// API passes custom field ordering as custom_fields.fieldname, and we have to strip
// that out to let the default sorter below order them correctly on the assets table.
@@ -292,8 +319,25 @@ class AssetsController extends Controller
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
// dd($assets);
return (new AssetsTransformer)->transformAssets($assets, $total);
/**
* Include additional associated relationships
*/
if ($request->input('components')) {
$assets->loadMissing(['components' => function ($query) {
$query->orderBy('created_at', 'desc');
}]);
}
/**
* Here we're just determining which Transformer (via $transformer) to use based on the
* variables we set earlier on in this method - we default to AssetsTransformer.
*/
return (new $transformer)->transformAssets($assets, $total, $request);
}
@@ -305,11 +349,11 @@ class AssetsController extends Controller
* @since [v4.2.1]
* @return JsonResponse
*/
public function showByTag($tag)
public function showByTag(Request $request, $tag)
{
if ($asset = Asset::with('assetstatus')->with('assignedTo')->where('asset_tag',$tag)->first()) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset);
return (new AssetsTransformer)->transformAsset($asset, $request);
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
@@ -323,18 +367,24 @@ class AssetsController extends Controller
* @since [v4.2.1]
* @return JsonResponse
*/
public function showBySerial($serial)
public function showBySerial(Request $request, $serial)
{
$this->authorize('index', Asset::class);
if ($assets = Asset::with('assetstatus')->with('assignedTo')
->withTrashed()->where('serial',$serial)->get()) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
$assets = Asset::with('assetstatus')->with('assignedTo');
if ($request->input('deleted', 'false') === 'true') {
$assets = $assets->withTrashed();
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
$assets = $assets->where('serial', $serial)->get();
if ($assets) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
}
}
/**
* Returns JSON with information about an asset for detail view.
*
@@ -343,17 +393,17 @@ class AssetsController extends Controller
* @since [v4.0]
* @return JsonResponse
*/
public function show($id)
public function show(Request $request, $id)
{
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()
->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')->findOrFail($id)) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset);
return (new AssetsTransformer)->transformAsset($asset, $request->input('components') );
}
}
public function licenses($id)
public function licenses(Request $request, $id)
{
$this->authorize('view', Asset::class);
$this->authorize('view', License::class);
@@ -424,11 +474,11 @@ class AssetsController extends Controller
* Accepts a POST request to create a new asset
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @since [v4.0]
* @return JsonResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Asset::class);
@@ -449,7 +499,7 @@ class AssetsController extends Controller
$asset->depreciate = '0';
$asset->status_id = $request->get('status_id', 0);
$asset->warranty_months = $request->get('warranty_months', null);
$asset->purchase_cost = Helper::ParseFloat($request->get('purchase_cost'));
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost')); // this is the API's store method, so I don't know that I want to do this? Confusing. FIXME (or not?!)
$asset->purchase_date = $request->get('purchase_date', null);
$asset->assigned_to = $request->get('assigned_to', null);
$asset->supplier_id = $request->get('supplier_id', 0);
@@ -457,21 +507,15 @@ class AssetsController extends Controller
$asset->rtd_location_id = $request->get('rtd_location_id', null);
$asset->location_id = $request->get('rtd_location_id', null);
if ($request->has('image_source') && $request->input('image_source') != "") {
$saved_image_path = Helper::processUploadedImage(
$request->input('image_source'), 'uploads/assets/'
);
/**
* this is here just legacy reasons. Api\AssetController
* used image_source once to allow encoded image uploads.
*/
if ($request->has('image_source')) {
$request->offsetSet('image', $request->offsetGet('image_source'));
}
if (!$saved_image_path) {
return response()->json(Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.create.error')
), 200);
}
$asset->image = $saved_image_path;
}
$asset = $request->handleImages($asset);
// Update custom fields in the database.
// Validation for these fields is handled through the AssetRequest form request
@@ -539,11 +583,11 @@ class AssetsController extends Controller
* Accepts a POST request to update an asset
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @since [v4.0]
* @return JsonResponse
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Asset::class);
@@ -557,32 +601,19 @@ class AssetsController extends Controller
($request->filled('company_id')) ?
$asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : '';
($request->filled('rtd_location_id')) ?
$asset->location_id = $request->get('rtd_location_id') : null;
if ($request->filled('image_source')) {
if ($request->input('image_source') == "") {
($request->filled('rtd_location_id')) ?
$asset->location_id = $request->get('rtd_location_id') : null;
$asset->image = null;
} else {
$saved_image_path = Helper::processUploadedImage(
$request->input('image_source'), 'uploads/assets/'
);
if (!$saved_image_path) {
return response()->json(Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.update.error')
), 200);
}
$asset->image = $saved_image_path;
}
}
/**
* this is here just legacy reasons. Api\AssetController
* used image_source once to allow encoded image uploads.
*/
if ($request->has('image_source')) {
$request->offsetSet('image', $request->offsetGet('image_source'));
}
$asset = $request->handleImages($asset);
// Update custom fields
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
foreach ($model->fieldset->fields as $field) {
@@ -657,6 +688,39 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
* Restore a soft-deleted asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $assetId
* @since [v5.1.18]
* @return JsonResponse
*/
public function restore($assetId = null)
{
// Get asset information
$asset = Asset::withTrashed()->find($assetId);
$this->authorize('delete', $asset);
if (isset($asset->id)) {
// Restore the asset
Asset::withTrashed()->where('id', $assetId)->restore();
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->user_id = Auth::user()->id;
$logaction->logaction('restored');
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.restore.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
@@ -781,7 +845,8 @@ class AssetsController extends Controller
}
if ($asset->save()) {
$asset->logCheckin($target, e($request->input('note')));
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note')));
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success')));
}
@@ -845,7 +910,7 @@ class AssetsController extends Controller
}
}
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.$request->input('asset_tag').' not found'));
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.e($request->input('asset_tag')).' not found'));

View File

@@ -8,6 +8,7 @@ use App\Http\Transformers\CategoriesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Category;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class CategoriesController extends Controller
@@ -54,14 +55,16 @@ class CategoriesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Category::class);
$category = new Category;
$category->fill($request->all());
$category->category_type = strtolower($request->input('category_type'));
$category = $request->handleImages($category);
if ($category->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $category, trans('admin/categories/message.create.success')));
@@ -92,15 +95,17 @@ class CategoriesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Category::class);
$category = Category::findOrFail($id);
$category->fill($request->all());
$category->category_type = strtolower($request->input('category_type'));
$category = $request->handleImages($category);
if ($category->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $category, trans('admin/categories/message.update.success')));

View File

@@ -8,6 +8,7 @@ use App\Http\Transformers\CompaniesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Company;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class CompaniesController extends Controller
@@ -65,15 +66,16 @@ class CompaniesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Company::class);
$company = new Company;
$company->fill($request->all());
$company = $request->handleImages($company);
if ($company->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new CompaniesTransformer)->transformCompany($company), trans('admin/companies/message.create.success')));
}
@@ -104,15 +106,16 @@ class CompaniesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Company::class);
$company = Company::findOrFail($id);
$company->fill($request->all());
$company = $request->handleImages($company);
if ($company->save()) {
return response()

View File

@@ -8,6 +8,10 @@ use App\Http\Transformers\ComponentsTransformer;
use App\Models\Company;
use App\Models\Component;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use App\Events\CheckoutableCheckedIn;
use App\Events\ComponentCheckedIn;
use App\Models\Asset;
class ComponentsController extends Controller
{
@@ -22,8 +26,25 @@ class ComponentsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Component::class);
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
$allowed_columns =
[
'id',
'name',
'min_amt',
'order_number',
'serial',
'purchase_date',
'purchase_cost',
'qty',
'image',
];
$components = Company::scopeCompanyables(Component::select('components.*')
->with('company', 'location', 'category'));
->with('company', 'location', 'category', 'assets'));
if ($request->filled('search')) {
$components = $components->TextSearch($request->input('search'));
@@ -48,11 +69,12 @@ class ComponentsController extends Controller
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$allowed_columns = ['id','name','min_amt','order_number','serial','purchase_date','purchase_cost','company','category','qty','location','image'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort) {
switch ($sort_override) {
case 'category':
$components = $components->OrderCategory($order);
break;
@@ -63,7 +85,7 @@ class ComponentsController extends Controller
$components = $components->OrderCompany($order);
break;
default:
$components = $components->orderBy($sort, $order);
$components = $components->orderBy($column_sort, $order);
break;
}
@@ -78,14 +100,15 @@ class ComponentsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Component::class);
$component = new Component;
$component->fill($request->all());
$component = $request->handleImages($component);
if ($component->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $component, trans('admin/components/message.create.success')));
@@ -116,15 +139,17 @@ class ComponentsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Component::class);
$component = Component::findOrFail($id);
$component->fill($request->all());
$component = $request->handleImages($component);
if ($component->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $component, trans('admin/components/message.update.success')));
@@ -172,4 +197,119 @@ class ComponentsController extends Controller
$assets = $assets->skip($offset)->take($limit)->get();
return (new ComponentsTransformer)->transformCheckedoutComponents($assets, $total);
}
/**
* Validate and checkout the component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* t
* @since [v5.1.8]
* @param Request $request
* @param int $componentId
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function checkout(Request $request, $componentId)
{
// Check if the component exists
if (is_null($component = Component::find($componentId))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.does_not_exist')));
}
$this->authorize('checkout', $component);
if ($component->numRemaining() >= $request->get('assigned_qty')) {
if (!$asset = Asset::find($request->input('assigned_to'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')));
}
// Update the accessory data
$component->assigned_to = $request->input('assigned_to');
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'created_at' => \Carbon::now(),
'assigned_qty' => $request->get('assigned_qty', 1),
'user_id' => \Auth::id(),
'asset_id' => $request->get('assigned_to')
]);
$component->logCheckout($request->input('note'), $asset);
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Not enough components remaining: '.$component->numRemaining().' remaining, '.$request->get('assigned_qty').' requested.'));
}
/**
* Validate and store checkin data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.1.8]
* @param Request $request
* @param $component_asset_id
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function checkin(Request $request, $component_asset_id)
{
if ($component_assets = \DB::table('components_assets')->find($component_asset_id)) {
if (is_null($component = Component::find($component_assets->component_id))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.not_found')));
}
$this->authorize('checkin', $component);
$max_to_checkin = $component_assets->assigned_qty;
if ($max_to_checkin > 1) {
$validator = \Validator::make($request->all(), [
"checkin_qty" => "required|numeric|between:1,$max_to_checkin"
]);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Checkin quantity must be between 1 and '.$max_to_checkin));
}
}
// Validation passed, so let's figure out what we have to do here.
$qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty', 1));
// We have to modify the record to reflect the new qty that's
// actually checked out.
$component_assets->assigned_qty = $qty_remaining_in_checkout;
\Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
\DB::table('components_assets')->where('id',
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
// If the checked-in qty is exactly the same as the assigned_qty,
// we can simply delete the associated components_assets record
if ($qty_remaining_in_checkout == 0) {
\DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
}
$asset = Asset::find($component_assets->asset_id);
event(new CheckoutableCheckedIn($component, $asset, \Auth::user(), $request->input('note'), \Carbon::now()));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkin.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'No matching checkouts for that component join record'));
}
}

View File

@@ -10,6 +10,7 @@ use App\Models\Company;
use App\Models\Consumable;
use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
class ConsumablesController extends Controller
{
@@ -24,6 +25,26 @@ class ConsumablesController extends Controller
public function index(Request $request)
{
$this->authorize('index', Consumable::class);
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
$allowed_columns =
[
'id',
'name',
'order_number',
'min_amt',
'purchase_date',
'purchase_cost',
'company',
'category',
'model_number',
'item_no',
'qty',
'image',
];
$consumables = Company::scopeCompanyables(
Consumable::select('consumables.*')
->with('company', 'location', 'category', 'users', 'manufacturer')
@@ -41,10 +62,18 @@ class ConsumablesController extends Controller
$consumables->where('category_id','=',$request->input('category_id'));
}
if ($request->filled('model_number')) {
$consumables->where('model_number','=',$request->input('model_number'));
}
if ($request->filled('manufacturer_id')) {
$consumables->where('manufacturer_id','=',$request->input('manufacturer_id'));
}
if ($request->filled('location_id')) {
$consumables->where('location_id','=',$request->input('location_id'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
@@ -53,12 +82,14 @@ class ConsumablesController extends Controller
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$allowed_columns = ['id','name','order_number','min_amt','purchase_date','purchase_cost','company','category','model_number', 'item_no', 'manufacturer','location','qty','image'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$sort_override = $request->input('sort');
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
switch ($sort) {
switch ($sort_override) {
case 'category':
$consumables = $consumables->OrderCategory($order);
break;
@@ -72,7 +103,7 @@ class ConsumablesController extends Controller
$consumables = $consumables->OrderCompany($order);
break;
default:
$consumables = $consumables->orderBy($sort, $order);
$consumables = $consumables->orderBy($column_sort, $order);
break;
}
@@ -90,14 +121,15 @@ class ConsumablesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Consumable::class);
$consumable = new Consumable;
$consumable->fill($request->all());
$consumable = $request->handleImages($consumable);
if ($consumable->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $consumable, trans('admin/consumables/message.create.success')));
@@ -125,16 +157,17 @@ class ConsumablesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Consumable::class);
$consumable = Consumable::findOrFail($id);
$consumable->fill($request->all());
$consumable = $request->handleImages($consumable);
if ($consumable->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $consumable, trans('admin/consumables/message.update.success')));
}

View File

@@ -9,6 +9,7 @@ use App\Http\Transformers\SelectlistTransformer;
use App\Models\Department;
use Auth;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class DepartmentsController extends Controller
@@ -73,14 +74,16 @@ class DepartmentsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Department::class);
$department = new Department;
$department->fill($request->all());
$department = $request->handleImages($department);
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
@@ -111,15 +114,16 @@ class DepartmentsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Department::class);
$department = Department::findOrFail($id);
$department->fill($request->all());
$department = $request->handleImages($department);
if ($department->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.update.success')));

View File

@@ -20,9 +20,9 @@ class DepreciationsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Depreciation::class);
$allowed_columns = ['id','name','months','created_at'];
$allowed_columns = ['id','name','months','depreciation_min','created_at'];
$depreciations = Depreciation::select('id','name','months','user_id','created_at','updated_at');
$depreciations = Depreciation::select('id','name','months','depreciation_min','user_id','created_at','updated_at');
if ($request->filled('search')) {
$depreciations = $depreciations->TextSearch($request->input('search'));

View File

@@ -17,6 +17,8 @@ class LicenseSeatsController extends Controller
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @param int $licenseId
* @return \Illuminate\Http\Response
*/
public function index(Request $request, $licenseId)
@@ -53,7 +55,8 @@ class LicenseSeatsController extends Controller
/**
* Display the specified resource.
*
* @param int $id
* @param int $licenseId
* @param int $seatId
* @return \Illuminate\Http\Response
*/
public function show($licenseId, $seatId)

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Location;
@@ -86,14 +87,15 @@ class LocationsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Location::class);
$location = new Location;
$location->fill($request->all());
$location = $request->handleImages($location);
if ($location->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new LocationsTransformer)->transformLocation($location), trans('admin/locations/message.create.success')));
@@ -141,17 +143,17 @@ class LocationsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Location::class);
$location = Location::findOrFail($id);
$location->fill($request->all());
$location = $request->handleImages($location);
if ($location->isValid()) {

View File

@@ -8,6 +8,7 @@ use App\Http\Transformers\ManufacturersTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Manufacturer;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class ManufacturersController extends Controller
@@ -59,14 +60,15 @@ class ManufacturersController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Manufacturer::class);
$manufacturer = new Manufacturer;
$manufacturer->fill($request->all());
$manufacturer = $request->handleImages($manufacturer);
if ($manufacturer->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $manufacturer, trans('admin/manufacturers/message.create.success')));
@@ -96,15 +98,16 @@ class ManufacturersController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Manufacturer::class);
$manufacturer = Manufacturer::findOrFail($id);
$manufacturer->fill($request->all());
$manufacturer = $request->handleImages($manufacturer);
if ($manufacturer->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $manufacturer, trans('admin/manufacturers/message.update.success')));

View File

@@ -17,6 +17,7 @@ use GuzzleHttp\Client;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use App\Models\Ldap; // forward-port of v4 LDAP model for Sync
use App\Http\Requests\SlackSettingsRequest;
class SettingsController extends Controller
@@ -165,31 +166,41 @@ class SettingsController extends Controller
public function slacktest(Request $request)
{
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false
]
$validator = Validator::make($request->all(), [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:'
]);
try {
$slack->post($request->input('slack_endpoint'),['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'Oops! Please check the channel name and webhook endpoint URL. Slack responded with: '.$e->getMessage()], 400);
if ($validator->fails()) {
return response()->json(['message' => 'Validation failed', 'errors' => $validator->errors()], 422);
}
return response()->json(['message' => 'Something went wrong :( '], 400);
// If validation passes, continue to the curl request
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($request->input('slack_endpoint'), ['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'FARTS! Please check the channel name and webhook endpoint URL ('.$request->input('slack_endpoint').'). Slack responded with: '.$e->getMessage()], 400);
}
//}
return response()->json(['message' => 'Something went wrong :( '], 400);
}

View File

@@ -22,7 +22,7 @@ class StatuslabelsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Statuslabel::class);
$allowed_columns = ['id','name','created_at', 'assets_count','color','default_label'];
$allowed_columns = ['id','name','created_at', 'assets_count','color', 'notes','default_label'];
$statuslabels = Statuslabel::withCount('assets as assets_count');
@@ -71,6 +71,10 @@ class StatuslabelsController extends Controller
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav', 0);
$statuslabel->default_label = $request->input('default_label', 0);
if ($statuslabel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.create.success')));
@@ -111,9 +115,7 @@ class StatuslabelsController extends Controller
$request->except('deployable', 'pending','archived');
if (!$request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
}
$statuslabel->fill($request->all());
@@ -121,6 +123,9 @@ class StatuslabelsController extends Controller
$statuslabel->deployable = $statusType['deployable'];
$statuslabel->pending = $statusType['pending'];
$statuslabel->archived = $statusType['archived'];
$statuslabel->color = $request->input('color');
$statuslabel->show_in_nav = $request->input('show_in_nav');
$statuslabel->default_label = $request->input('default_label');
if ($statuslabel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.update.success')));
@@ -167,10 +172,7 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::with('assets')
->groupBy('id')
->withCount('assets as assets_count')
->get();
$statuslabels = Statuslabel::withCount('assets')->get();
$labels=[];
$points=[];
@@ -179,7 +181,6 @@ class StatuslabelsController extends Controller
foreach ($statuslabels as $statuslabel) {
if ($statuslabel->assets_count > 0) {
$labels[]=$statuslabel->name. ' ('.number_format($statuslabel->assets_count).')';
$points[]=$statuslabel->assets_count;
@@ -187,8 +188,8 @@ class StatuslabelsController extends Controller
$colors_array[] = $statuslabel->color;
} else {
$colors_array[] = Helper::defaultChartColors($default_color_count);
$default_color_count++;
}
$default_color_count++;
}
}

View File

@@ -8,6 +8,7 @@ use App\Http\Transformers\SelectlistTransformer;
use App\Http\Transformers\SuppliersTransformer;
use App\Models\Supplier;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class SuppliersController extends Controller
@@ -55,14 +56,15 @@ class SuppliersController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Supplier::class);
$supplier = new Supplier;
$supplier->fill($request->all());
$supplier = $request->handleImages($supplier);
if ($supplier->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $supplier, trans('admin/suppliers/message.create.success')));
@@ -92,15 +94,16 @@ class SuppliersController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param \App\Http\Requests\ImageUploadRequest $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(ImageUploadRequest $request, $id)
{
$this->authorize('update', Supplier::class);
$supplier = Supplier::findOrFail($id);
$supplier->fill($request->all());
$supplier = $request->handleImages($supplier);
if ($supplier->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $supplier, trans('admin/suppliers/message.update.success')));

View File

@@ -16,6 +16,7 @@ use App\Models\License;
use App\Models\User;
use Auth;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
class UsersController extends Controller
@@ -74,6 +75,10 @@ class UsersController extends Controller
$users = $users->withTrashed();
}
if ($request->filled('activated')) {
$users = $users->where('users.activated', '=', $request->input('activated'));
}
if ($request->filled('company_id')) {
$users = $users->where('users.company_id', '=', $request->input('company_id'));
}
@@ -90,6 +95,30 @@ class UsersController extends Controller
$users = $users->where('users.username', '=', $request->input('username'));
}
if ($request->filled('first_name')) {
$users = $users->where('users.first_name', '=', $request->input('first_name'));
}
if ($request->filled('last_name')) {
$users = $users->where('users.last_name', '=', $request->input('last_name'));
}
if ($request->filled('employee_num')) {
$users = $users->where('users.employee_num', '=', $request->input('employee_num'));
}
if ($request->filled('state')) {
$users = $users->where('users.state', '=', $request->input('state'));
}
if ($request->filled('country')) {
$users = $users->where('users.country', '=', $request->input('country'));
}
if ($request->filled('zip')) {
$users = $users->where('users.zip', '=', $request->input('zip'));
}
if ($request->filled('group_id')) {
$users = $users->ByGroup($request->get('group_id'));
}
@@ -98,6 +127,10 @@ class UsersController extends Controller
$users = $users->where('users.department_id','=',$request->input('department_id'));
}
if ($request->filled('manager_id')) {
$users = $users->where('users.manager_id','=',$request->input('manager_id'));
}
if ($request->filled('search')) {
$users = $users->TextSearch($request->input('search'));
}
@@ -237,7 +270,8 @@ class UsersController extends Controller
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$user->password = bcrypt($request->get('password', $tmp_pass));
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
@@ -280,9 +314,15 @@ class UsersController extends Controller
$user = User::findOrFail($id);
// This is a janky hack to prevent people from changing admin demo user data on the public demo.
// The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
// Thanks, jerks. You are why we can't have nice things. - snipe
/**
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
*
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
*
* Thanks, jerks. You are why we can't have nice things. - snipe
*
*/
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
@@ -290,7 +330,7 @@ class UsersController extends Controller
$user->fill($request->all());
if ($user->id == $request->input('manager_id')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
}
@@ -320,6 +360,9 @@ class UsersController extends Controller
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
// Sync group memberships:
@@ -397,12 +440,12 @@ class UsersController extends Controller
* @param $userId
* @return string JSON
*/
public function assets($id)
public function assets(Request $request, $id)
{
$this->authorize('view', User::class);
$this->authorize('view', Asset::class);
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model')->get();
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
}
/**

View File

@@ -100,7 +100,7 @@ class AssetMaintenancesController extends Controller
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
$assetMaintenance->is_warranty = $request->input('is_warranty');
$assetMaintenance->cost = $request->input('cost');
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
$assetMaintenance->notes = $request->input('notes');
$asset = Asset::find($request->input('asset_id'));
@@ -209,10 +209,10 @@ class AssetMaintenancesController extends Controller
return static::getInsufficientPermissionsRedirect();
}
$assetMaintenance->supplier_id = e($request->input('supplier_id'));
$assetMaintenance->is_warranty = e($request->input('is_warranty'));
$assetMaintenance->cost = Helper::ParseFloat(e($request->input('cost')));
$assetMaintenance->notes = e($request->input('notes'));
$assetMaintenance->supplier_id = $request->input('supplier_id');
$assetMaintenance->is_warranty = $request->input('is_warranty');
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
$assetMaintenance->notes = $request->input('notes');
$asset = Asset::find(request('asset_id'));

View File

@@ -269,6 +269,7 @@ class AssetModelsController extends Controller
*/
public function getClone($modelId = null)
{
$this->authorize('create', AssetModel::class);
// Check if the model exists
if (is_null($model_to_clone = AssetModel::find($modelId))) {
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));

View File

@@ -2,7 +2,6 @@
namespace App\Http\Controllers\Assets;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetFileRequest;
use App\Models\Actionlog;
@@ -10,6 +9,7 @@ use App\Models\Asset;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use App\Helpers\StorageHelper;
use enshrined\svgSanitize\Sanitizer;
class AssetFilesController extends Controller
{
@@ -36,9 +36,29 @@ class AssetFilesController extends Controller
if (!Storage::exists('private_uploads/assets')) Storage::makeDirectory('private_uploads/assets', 775);
foreach ($request->file('file') as $file) {
$extension = $file->getClientOriginalExtension();
$file_name = 'hardware-'.$asset->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
// Check for SVG and sanitize it
if ($extension=='svg') {
\Log::debug('This is an SVG');
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
try {
Storage::put('private_uploads/assets/'.$file_name, $cleanSVG);
} catch (\Exception $e) {
\Log::debug('Upload no workie :( ');
\Log::debug($e);
}
} else {
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
}
$asset->logUpload($file_name, e($request->get('notes')));
}
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
@@ -110,20 +130,20 @@ class AssetFilesController extends Controller
{
$asset = Asset::find($assetId);
$this->authorize('update', $asset);
$rel_path = 'storage/private_uploads/assets';
$rel_path = 'private_uploads/assets';
// the asset is valid
if (isset($asset->id)) {
$this->authorize('update', $asset);
$log = Actionlog::find($fileId);
if ($log) {
if (file_exists(base_path().'/'.$rel_path.'/'.$log->filename)) {
Storage::disk('public')->delete($rel_path.'/'.$log->filename);
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
}
$log->delete();
return redirect()->back()
->with('success', trans('admin/hardware/message.deletefile.success'));
}

View File

@@ -138,7 +138,7 @@ class AssetsController extends Controller
$asset->depreciate = '0';
$asset->status_id = request('status_id', 0);
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = Helper::ParseFloat($request->get('purchase_cost'));
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
$asset->purchase_date = request('purchase_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', 0);
@@ -196,7 +196,7 @@ class AssetsController extends Controller
}
if (isset($target)) {
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', e($request->get('name')), $location);
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
}
$success = true;
@@ -302,7 +302,7 @@ class AssetsController extends Controller
$asset->status_id = $request->input('status_id', null);
$asset->warranty_months = $request->input('warranty_months', null);
$asset->purchase_cost = Helper::ParseFloat($request->input('purchase_cost', null));
$asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$asset->purchase_date = $request->input('purchase_date', null);
$asset->supplier_id = $request->input('supplier_id', null);
$asset->expected_checkin = $request->input('expected_checkin', null);
@@ -813,7 +813,7 @@ class AssetsController extends Controller
$asset->unsetEventDispatcher();
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d h:i:s');
$asset->last_audit_date = date('Y-m-d H:i:s');
// Check to see if they checked the box to update the physical location,
// not just note it in the audit notes

View File

@@ -32,7 +32,8 @@ class BulkAssetsController extends Controller
return redirect()->back()->with('error', 'No assets selected');
}
$asset_ids = array_keys($request->input('ids'));
$asset_ids = array_values(array_unique($request->input('ids')));
if ($request->filled('bulk_actions')) {
switch($request->input('bulk_actions')) {
@@ -50,7 +51,7 @@ class BulkAssetsController extends Controller
return view('hardware/bulk-delete')->with('assets', $assets);
case 'edit':
return view('hardware/bulk')
->with('assets', request('ids'))
->with('assets', $asset_ids)
->with('statuslabel_list', Helper::statusLabelList());
}
}
@@ -90,6 +91,7 @@ class BulkAssetsController extends Controller
|| ($request->filled('model_id'))
) {
foreach ($assets as $assetId) {
$this->update_array = [];
$this->conditionallyAddItem('purchase_date')
@@ -102,7 +104,7 @@ class BulkAssetsController extends Controller
->conditionallyAddItem('warranty_months');
if ($request->filled('purchase_cost')) {
$this->update_array['purchase_cost'] = Helper::ParseFloat($request->input('purchase_cost'));
$this->update_array['purchase_cost'] = Helper::ParseCurrency($request->input('purchase_cost'));
}
if ($request->filled('company_id')) {

View File

@@ -29,6 +29,7 @@ class ForgotPasswordController extends Controller
public function __construct()
{
$this->middleware('guest');
$this->middleware('throttle:5,1', ['except' => 'showLinkRequestForm']);
}
/**
@@ -61,7 +62,7 @@ class ForgotPasswordController extends Controller
$request->validate([
'username' => ['required', 'max:255'],
]);
/**
@@ -71,13 +72,21 @@ class ForgotPasswordController extends Controller
* Once we have attempted to send the link, we will examine the response
* then see the message we need to show to the user. Finally, we'll send out a proper response.
*/
$response = $this->broker()->sendResetLink(
array_merge(
$request->only('username'),
['activated' => '1'],
['ldap_import' => '0']
)
);
$response = null;
try {
$response = $this->broker()->sendResetLink(
array_merge(
$request->only('username'),
['activated' => '1'],
['ldap_import' => '0']
)
);
} catch(\Exception $e) {
\Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
}
if ($response === \Password::RESET_LINK_SENT) {
\Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');

View File

@@ -108,7 +108,7 @@ class LoginController extends Controller
Log::debug("Attempting to log user in by SAML authentication.");
$user = $saml->samlLogin($samlData);
if(!is_null($user)) {
Auth::login($user, true);
Auth::login($user);
} else {
$username = $saml->getUsername();
\Log::warning("SAML user '$username' could not be found in database.");
@@ -183,7 +183,7 @@ class LoginController extends Controller
try {
$user = User::where('username', '=', $remote_user)->whereNull('deleted_at')->where('activated', '=', '1')->first();
Log::debug("Remote user auth lookup complete");
if(!is_null($user)) Auth::login($user, true);
if(!is_null($user)) Auth::login($user, $request->input('remember'));
} catch(Exception $e) {
Log::debug("There was an error authenticating the Remote user: " . $e->getMessage());
}
@@ -223,7 +223,7 @@ class LoginController extends Controller
try {
LOG::debug("Attempting to log user in by LDAP authentication.");
$user = $this->loginViaLdap($request);
Auth::login($user, true);
Auth::login($user, $request->input('remember'));
// If the user was unable to login via LDAP, log the error and let them fall through to
// local authentication.

View File

@@ -5,6 +5,7 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Company;
use App\Models\Component;
use App\Helpers\Helper;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Storage;
@@ -74,7 +75,7 @@ class ComponentsController extends Controller
$component->min_amt = $request->input('min_amt', null);
$component->serial = $request->input('serial', null);
$component->purchase_date = $request->input('purchase_date', null);
$component->purchase_cost = $request->input('purchase_cost', null);
$component->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
@@ -144,7 +145,7 @@ class ComponentsController extends Controller
$component->min_amt = $request->input('min_amt');
$component->serial = $request->input('serial');
$component->purchase_date = $request->input('purchase_date');
$component->purchase_cost = request('purchase_cost');
$component->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$component->qty = $request->input('qty');
$component = $request->handleImages($component);

View File

@@ -75,7 +75,7 @@ class ConsumablesController extends Controller
$consumable->model_number = $request->input('model_number');
$consumable->item_no = $request->input('item_no');
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost'));
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$consumable->qty = $request->input('qty');
$consumable->user_id = Auth::id();
@@ -141,7 +141,7 @@ class ConsumablesController extends Controller
$consumable->model_number = $request->input('model_number');
$consumable->item_no = $request->input('item_no');
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost'));
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$consumable->qty = Helper::ParseFloat($request->input('qty'));
$consumable = $request->handleImages($consumable);

View File

@@ -92,7 +92,7 @@ class CustomFieldsController extends Controller
$this->authorize('create', CustomField::class);
$field = new CustomField([
"name" => $request->get("name"),
"name" => trim($request->get("name")),
"element" => $request->get("element"),
"help_text" => $request->get("help_text"),
"field_values" => $request->get("field_values"),
@@ -212,7 +212,7 @@ class CustomFieldsController extends Controller
$this->authorize('update', $field);
$field->name = e($request->get("name"));
$field->name = trim(e($request->get("name")));
$field->element = e($request->get("element"));
$field->field_values = e($request->get("field_values"));
$field->user_id = Auth::id();

View File

@@ -69,6 +69,7 @@ class DepreciationsController extends Controller
// Depreciation data
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$depreciation->depreciation_min= $request->input('depreciation_min');
$depreciation->user_id = Auth::id();
// Was the asset created?
@@ -125,8 +126,9 @@ class DepreciationsController extends Controller
$this->authorize('update', $depreciation);
// Depreciation data
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$depreciation->depreciation_min = $request->input('depreciation_min');
// Was the asset created?
if ($depreciation->save()) {

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use App\Models\Asset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
@@ -80,7 +81,12 @@ class LicenseCheckinController extends Controller
// Ooops.. something went wrong
return redirect()->back()->withInput()->withErrors($validator);
}
$return_to = User::find($licenseSeat->assigned_to);
if($licenseSeat->assigned_to != null){
$return_to = User::find($licenseSeat->assigned_to);
} else {
$return_to = Asset::find($licenseSeat->asset_id);
}
// Update the asset data
$licenseSeat->assigned_to = null;
@@ -88,7 +94,6 @@ class LicenseCheckinController extends Controller
// Was the asset updated?
if ($licenseSeat->save()) {
event(new CheckoutableCheckedIn($licenseSeat, $return_to, Auth::user(), $request->input('note')));
if ($backTo=='user') {

View File

@@ -6,11 +6,11 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\AssetFileRequest;
use App\Models\Actionlog;
use App\Models\License;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Helpers\StorageHelper;
use enshrined\svgSanitize\Sanitizer;
class LicenseFilesController extends Controller
{
@@ -37,28 +37,39 @@ class LicenseFilesController extends Controller
if (!Storage::exists('private_uploads/licenses')) Storage::makeDirectory('private_uploads/licenses', 775);
$upload_success = false;
foreach ($request->file('file') as $file) {
$file_name = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$file->getClientOriginalExtension())).'.'.$file->getClientOriginalExtension();
$extension = $file->getClientOriginalExtension();
$file_name = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
$upload_success = $file->storeAs('private_uploads/licenses', $file_name);
// $upload_success = $file->storeAs('private_uploads/licenses/'.$file_name, $file);
// Check for SVG and sanitize it
if ($extension == 'svg') {
\Log::debug('This is an SVG');
\Log::debug($file_name);
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
try {
Storage::put('private_uploads/licenses/'.$file_name, $cleanSVG);
} catch (\Exception $e) {
\Log::debug('Upload no workie :( ');
\Log::debug($e);
}
} else {
Storage::put('private_uploads/licenses/'.$file_name, file_get_contents($file));
}
//Log the upload to the log
$license->logUpload($file_name, e($request->input('notes')));
}
// This being called from a modal seems to confuse redirect()->back()
// It thinks we should go to the dashboard. As this is only used
// from the modal at present, hardcode the redirect. Longterm
// maybe we evaluate something else.
if ($upload_success) {
return redirect()->route('licenses.show', $license->id)->with('success', trans('admin/licenses/message.upload.success'));
}
return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.error'));
}
return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.nofiles'));
}

View File

@@ -88,7 +88,7 @@ class LicensesController extends Controller
$license->name = $request->input('name');
$license->notes = $request->input('notes');
$license->order_number = $request->input('order_number');
$license->purchase_cost = $request->input('purchase_cost');
$license->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$license->purchase_date = $request->input('purchase_date');
$license->purchase_order = $request->input('purchase_order');
$license->purchase_order = $request->input('purchase_order');
@@ -165,7 +165,7 @@ class LicensesController extends Controller
$license->name = $request->input('name');
$license->notes = $request->input('notes');
$license->order_number = $request->input('order_number');
$license->purchase_cost = $request->input('purchase_cost');
$license->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$license->purchase_date = $request->input('purchase_date');
$license->purchase_order = $request->input('purchase_order');
$license->reassignable = $request->input('reassignable', 0);

View File

@@ -6,6 +6,7 @@ use App\Http\Requests\ImageUploadRequest;
use App\Models\Location;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\Models\Asset;
use Illuminate\Support\Facades\Storage;
/**

View File

@@ -102,11 +102,7 @@ class ReportsController extends Controller
{
$this->authorize('reports.view');
$depreciations = Depreciation::get();
// Grab all the assets
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'company', 'model.category', 'model.depreciation')
->orderBy('created_at', 'DESC')->get();
return view('reports/depreciation', compact('assets'))->with('depreciations',$depreciations);
return view('reports/depreciation')->with('depreciations',$depreciations);
}
/**
@@ -563,7 +559,7 @@ class ReportsController extends Controller
foreach ($customfields as $customfield) {
if (e($request->input($customfield->db_column_name())) == '1') {
if ($request->input($customfield->db_column_name()) == '1') {
$header[] = $customfield->name;
}
}
@@ -641,7 +637,7 @@ class ReportsController extends Controller
$assets->whereBetween('assets.next_audit_date', [$request->input('next_audit_start'), $request->input('next_audit_end')]);
}
$assets->orderBy('assets.created_at', 'ASC')->chunk(20, function($assets) use($handle, $customfields, $request) {
$assets->orderBy('assets.id', 'ASC')->chunk(20, function($assets) use($handle, $customfields, $request) {
$executionTime = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
\Log::debug('Walking results: '.$executionTime);

View File

@@ -22,6 +22,7 @@ use Input;
use Redirect;
use Response;
use App\Helpers\StorageHelper;
use App\Http\Requests\SlackSettingsRequest;
/**
* This controller handles all actions related to Settings for
@@ -667,25 +668,12 @@ class SettingsController extends Controller
*
* @return View
*/
public function postSlack(Request $request)
public function postSlack(SlackSettingsRequest $request)
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$validatedData = $request->validate([
'slack_channel' => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
]);
if ($validatedData) {
$setting->slack_endpoint = $request->input('slack_endpoint');
$setting->slack_channel = $request->input('slack_channel');
$setting->slack_botname = $request->input('slack_botname');
}
if ($setting->save()) {
return redirect()->route('settings.index')
->with('success', trans('admin/settings/message.update.success'));
@@ -947,10 +935,14 @@ class SettingsController extends Controller
$setting->ldap_jobtitle = $request->input('ldap_jobtitle');
$setting->ldap_country = $request->input('ldap_country');
$setting->ldap_dept = $request->input('ldap_dept');
$setting->ldap_client_tls_cert = $request->input('ldap_client_tls_cert');
$setting->ldap_client_tls_key = $request->input('ldap_client_tls_key');
}
if ($setting->save()) {
$setting->update_client_side_cert_files();
return redirect()->route('settings.ldap.index')
->with('success', trans('admin/settings/message.update.success'));
}

View File

@@ -10,6 +10,8 @@ use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use enshrined\svgSanitize\Sanitizer;
use Illuminate\Support\Facades\Storage;
class UserFilesController extends Controller
{
@@ -33,13 +35,36 @@ class UserFilesController extends Controller
$logActions = [];
$files = $request->file('file');
if (is_null($files)){
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
}
foreach($files as $file) {
$extension = $file->getClientOriginalExtension();
$filename = 'user-' . $user->id . '-' . str_random(8);
$filename .= '-' . str_slug($file->getClientOriginalName()) . '.' . $extension;
if (!$file->move($destinationPath, $filename)) {
return redirect()->back()->with('error', trans('admin/users/message.upload.invalidfiles'));
}
$file_name = 'user-'.$user->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
// Check for SVG and sanitize it
if ($extension == 'svg') {
\Log::debug('This is an SVG');
\Log::debug($file_name);
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
try {
Storage::put('private_uploads/users/'.$file_name, $cleanSVG);
} catch (\Exception $e) {
\Log::debug('Upload no workie :( ');
\Log::debug($e);
}
} else {
Storage::put('private_uploads/users/'.$file_name, file_get_contents($file));
}
//Log the uploaded file to the log
$logAction = new Actionlog();
$logAction->item_id = $user->id;
@@ -48,7 +73,7 @@ class UserFilesController extends Controller
$logAction->note = $request->input('notes');
$logAction->target_id = null;
$logAction->created_at = date("Y-m-d H:i:s");
$logAction->filename = $filename;
$logAction->filename = $file_name;
$logAction->action_type = 'uploaded';
if (!$logAction->save()) {

View File

@@ -15,6 +15,7 @@ use App\Models\User;
use App\Notifications\WelcomeNotification;
use Auth;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Password;
use Input;
use Redirect;
use Str;
@@ -617,4 +618,31 @@ class UsersController extends Controller
->with('show_user', $show_user)
->with('settings', Setting::getSettings());
}
/**
* Send individual password reset email
*
* @author A. Gianotto
* @since [v5.0.15]
* @return \Illuminate\Http\RedirectResponse
*/
public function sendPasswordReset($id) {
if (($user = User::find($id)) && ($user->activated == '1') && ($user->email!='') && ($user->ldap_import == '0')) {
$credentials = ['email' => $user->email];
try {
\Password::sendResetLink($credentials, function (Message $message) use ($user) {
$message->subject($this->getEmailSubject());
});
return redirect()->back()->with('success', trans('admin/users/message.password_reset_sent', ['email' => $user->email]));
} catch (\Exception $e) {
return redirect()->back()->with('error', ' Error sending email. :( ');
}
}
return redirect()->back()->with('error', 'User is not activated, is LDAP synced, or does not have an email address ');
}
}

View File

@@ -23,6 +23,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\CheckForDebug::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\SecurityHeaders::class,
\App\Http\Middleware\PreventBackHistory::class,
];

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use Closure;
class PreventBackHistory
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$headers = [
'Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate',
'Pragma' => 'no-cache',
'Expires' => 'Sun, 02 Jan 1990 00:00:00 GMT'
];
$response = $next($request);
foreach($headers as $key => $value) {
$response->headers->set($key, $value);
}
return $response;
}
}

View File

@@ -99,7 +99,7 @@ class SecurityHeaders
// We have to exclude debug mode here because debugbar pulls from a CDN or two
// and it will break things.
if ((config('app.debug')!='true') || (config('app.enable_csp')=='true')) {
if ((config('app.debug')!='true') && (config('app.enable_csp')=='true')) {
$csp_policy[] = "default-src 'self'";
$csp_policy[] = "style-src 'self' 'unsafe-inline'";
$csp_policy[] = "script-src 'self' 'unsafe-inline' 'unsafe-eval'";

View File

@@ -24,7 +24,7 @@ class AssetFileRequest extends Request
{
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
return [
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf|max:'.$max_file_size,
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,webp|max:'.$max_file_size,
];
}
}

View File

@@ -5,10 +5,14 @@ namespace App\Http\Requests;
use App\Models\SnipeModel;
use Intervention\Image\Facades\Image;
use enshrined\svgSanitize\Sanitizer;
use App\Http\Traits\ConvertsBase64ToFiles;
use Illuminate\Http\UploadedFile;
use Storage;
class ImageUploadRequest extends Request
{
use ConvertsBase64ToFiles;
/**
* Determine if the user is authorized to make this request.
*
@@ -26,16 +30,32 @@ class ImageUploadRequest extends Request
*/
public function rules()
{
return [
'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp',
'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml',
];
return [
'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp',
'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp',
];
}
public function response(array $errors)
{
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
}
/**
* Fields that should be traited from base64 to files
*/
protected function base64FileKeys(): array
{
/**
* image_source is here just legacy reasons. Api\AssetController
* had it once to allow encoded image uploads.
*/
return [
'image' => 'auto',
'image_source' => 'auto'
];
}
/**
* Handle and store any images attached to request
@@ -77,14 +97,22 @@ class ImageUploadRequest extends Request
\Log::debug('Form fieldname is: '.$form_fieldname);
\Log::debug('DB fieldname is: '.$use_db_field);
\Log::debug('Trying to upload to '. $path);
// ConvertBase64ToFiles just changes object type,
// as it cannot currently insert files to $this->files
if ($this->offsetGet($form_fieldname) instanceof UploadedFile) {
$image=$this->offsetGet($form_fieldname);
} else {
if ($this->hasFile($form_fieldname)) {
$image = $this->file($form_fieldname);
}
}
\Log::debug($this->file());
if ($this->hasFile($form_fieldname)) {
if (isset($image)) {
\Log::debug($image);
if (!config('app.lock_passwords')) {
$image = $this->file($form_fieldname);
$ext = $image->getClientOriginalExtension();
$file_name = $type.'-'.$form_fieldname.'-'.str_random(10).'.'.$ext;
@@ -165,4 +193,5 @@ class ImageUploadRequest extends Request
return $item;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
class SlackSettingsRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:"https://hooks.slack.com"|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
'slack_botname' => 'string|nullable',
];
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace App\Http\Traits;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
trait ConvertsBase64ToFiles
{
protected function base64FileKeys(): array
{
return [];
}
/**
* Pulls the Base64 contents for each file key and creates
* an UploadedFile instance from it and sets it on the
* request.
*
* @return void
*/
protected function prepareForValidation()
{
$flattened = Arr::dot($this->base64FileKeys());
Collection::make($flattened)->each(function ($filename, $key) {
rescue(function () use ($key, $filename) {
// dont process plain files
if ( $this->file($key)){
return;
}
$base64Contents = $this->input($key);
if (!$base64Contents) {
return;
}
// autogenerate filenames
if ($filename == 'auto'){
$header = explode(';', $base64Contents, 2)[0];
// Grab the image type from the header while we're at it.
$filename = $key . '.' . substr($header, strpos($header, '/')+1);
}
// Generate a temporary path to store the Base64 contents
$tempFilePath = tempnam(sys_get_temp_dir(), $filename);
// Store the contents using a stream, or by decoding manually
if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) {
$source = fopen($base64Contents, 'r');
$destination = fopen($tempFilePath, 'w');
stream_copy_to_stream($source, $destination);
fclose($source);
fclose($destination);
} else {
file_put_contents($tempFilePath, base64_decode($base64Contents, true));
}
$uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true);
\Log::debug("Trait: uploadedfile ". $tempFilePath);
$this->offsetUnset($key);
\Log::debug("Trait: encoded field \"$key\" removed" );
//Inserting new file to $this-files does not work so have to deal this after
$this->offsetSet($key,$uploadedFile);
\Log::debug("Trait: field \"$key\" inserted as UplodedFile" );
}, null, false);
});
}
}
/**
* Loosely based on idea https://github.com/protonemedia/laravel-mixins/tree/master/src/Request
* */

View File

@@ -82,7 +82,7 @@ class AccessoriesTransformer
'first_name'=> e($user->first_name),
'last_name'=> e($user->last_name),
'employee_number' => e($user->employee_num),
'checkout_notes' => $user->pivot->note,
'checkout_notes' => e($user->pivot->note),
'last_checkout' => Helper::getFormattedDateObject($user->pivot->created_at, 'datetime'),
'type' => 'user',
'available_actions' => ['checkin' => true]

View File

@@ -115,7 +115,7 @@ class ActionlogsTransformer
'note' => ($actionlog->note) ? e($actionlog->note): null,
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): null,
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
];

View File

@@ -93,15 +93,15 @@ class AssetsTransformer
$value = (Gate::allows('superadmin')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
$fields_array[$field->name] = [
'field' => $field->convertUnicodeDbSlug(),
'value' => $value,
'field' => e($field->convertUnicodeDbSlug()),
'value' => e($value),
'field_format' => $field->format,
];
} else {
$fields_array[$field->name] = [
'field' => $field->convertUnicodeDbSlug(),
'value' => $asset->{$field->convertUnicodeDbSlug()},
'field' => e($field->convertUnicodeDbSlug()),
'value' => e($asset->{$field->convertUnicodeDbSlug()}),
'field_format' => $field->format,
];
@@ -114,26 +114,38 @@ class AssetsTransformer
}
$permissions_array['available_actions'] = [
'checkout' => Gate::allows('checkout', Asset::class),
'checkin' => Gate::allows('checkin', Asset::class),
'clone' => Gate::allows('create', Asset::class),
'restore' => false,
'update' => (bool) Gate::allows('update', Asset::class),
'delete' => ($asset->assigned_to=='' && Gate::allows('delete', Asset::class)),
'checkout' => ($asset->deleted_at=='' && Gate::allows('checkout', Asset::class)) ? true : false,
'checkin' => ($asset->deleted_at=='' && Gate::allows('checkin', Asset::class)) ? true : false,
'clone' => Gate::allows('create', Asset::class) ? true : false,
'restore' => ($asset->deleted_at!='' && Gate::allows('create', Asset::class)) ? true : false,
'update' => ($asset->deleted_at=='' && Gate::allows('update', Asset::class)) ? true : false,
'delete' => ($asset->deleted_at=='' && $asset->assigned_to =='' && Gate::allows('delete', Asset::class)) ? true : false,
];
if ($asset->deleted_at!='') {
$permissions_array['available_actions'] = [
'checkout' => true,
'checkin' => false,
'clone' => Gate::allows('create', Asset::class),
'restore' => Gate::allows('create', Asset::class),
'update' => false,
'delete' => false,
];
if (request('components')=='true') {
if ($asset->components) {
$array['components'] = [];
foreach ($asset->components as $component) {
$array['components'][] = [
'id' => $component->id,
'pivot_id' => $component->pivot->id,
'name' => e($component->name),
'qty' => $component->pivot->assigned_qty,
'price_cost' => $component->purchase_cost,
'purchase_total' => $component->purchase_cost * $component->pivot->assigned_qty,
'checkout_date' => Helper::getFormattedDateObject($component->pivot->created_at, 'datetime') ,
];
}
}
}
$array += $permissions_array;
return $array;
}
@@ -197,4 +209,4 @@ class AssetsTransformer
return $array;
}
}
}

View File

@@ -29,6 +29,7 @@ class CategoriesTransformer
'image' => ($category->image) ? Storage::disk('public')->url('categories/'.e($category->image)) : null,
'category_type' => ucwords(e($category->category_type)),
'has_eula' => ($category->getEula() ? true : false),
'use_default_eula' => ($category->use_default_eula=='1' ? true : false),
'eula' => ($category->getEula()),
'checkin_email' => ($category->checkin_email =='1'),
'require_acceptance' => ($category->require_acceptance == '1'),

View File

@@ -0,0 +1,120 @@
<?php
namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Asset;
use Illuminate\Database\Eloquent\Collection;
/**
* This tranformer looks like it's extraneous, since we return as much or more
* info in the AssetsTransformer, but we want to flatten these results out so that they
* don't dislose more information than we want. Folks with depreciation powers don't necessaily
* have the right to see additional info, and inspecting the API call here could disclose
* info they're not supposed to see.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.2.0]
*/
class DepreciationReportTransformer
{
public function transformAssets(Collection $assets, $total)
{
$array = array();
foreach ($assets as $asset) {
$array[] = self::transformAsset($asset);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformAsset(Asset $asset)
{
/**
* Set some default values here
*/
$purchase_cost = null;
$depreciated_value = null;
$monthly_depreciation = null;
$diff = null;
$checkout_target = null;
/**
* If there is a location set and a currency set, use that for display
*/
if ($asset->location && $asset->location->currency) {
$purchase_cost_currency = $asset->location->currency;
} else {
$purchase_cost_currency = \App\Models\Setting::getSettings()->default_currency;
}
/**
* If there is a NOT an empty purchase cost (meaning not null or '' but it *could* be zero),
* format the purchase cost. We coould do this inline in the transformer, but we need that value
* for the other calculations that come after, like diff, etc.
*/
if ($asset->purchase_cost!='') {
$purchase_cost = $asset->purchase_cost;
}
/**
* Override the previously set null values if there is a valid model and associated depreciation
*/
if (($asset->model) && ($asset->model->depreciation)) {
$depreciated_value = \App\Helpers\Helper::formatCurrencyOutput($asset->getDepreciatedValue());
$monthly_depreciation = \App\Helpers\Helper::formatCurrencyOutput(($asset->model->eol > 0 ? ($asset->purchase_cost / $asset->model->eol) : 0));
$diff = \App\Helpers\Helper::formatCurrencyOutput(($asset->purchase_cost - $asset->getDepreciatedValue()));
}
if ($asset->assigned) {
$checkout_target = $asset->assigned->name;
if ($asset->checkedOutToUser()) {
$checkout_target = $asset->assigned->getFullNameAttribute();
}
}
$array = [
'company' => ($asset->company) ? e($asset->company->name) : null,
'name' => e($asset->name),
'asset_tag' => e($asset->asset_tag),
'serial' => e($asset->serial),
'model' => ($asset->model) ? e($asset->model->name) : null,
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => ($asset->purchase_date!='') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null ,
'status_label' => ($asset->assetstatus) ? e($asset->assetstatus->name) : null,
'status' => ($asset->assetstatus) ? e($asset->present()->statusMeta) : null,
'category' => (($asset->model) && ($asset->model->category)) ? e($asset->model->category->name) : null,
'manufacturer' => (($asset->model) && ($asset->model->manufacturer)) ? e($asset->model->manufacturer->name) : null,
'supplier' => ($asset->supplier) ? e($asset->supplier->name) : null,
'notes' => ($asset->notes) ? e($asset->notes) : null,
'order_number' => ($asset->order_number) ? e($asset->order_number) : null,
'location' => ($asset->location) ? e($asset->location->name) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'currency' => $purchase_cost_currency,
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
'book_value' => Helper::formatCurrencyOutput($depreciated_value),
'monthly_depreciation' => $monthly_depreciation,
'checked_out_to' => $checkout_target,
'diff' => Helper::formatCurrencyOutput($diff),
'number_of_months' => ($asset->model && $asset->model->depreciation) ? e($asset->model->depreciation->months) : null,
'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? e($asset->model->depreciation->name) : null,
];
return $array;
}
public function transformAssetsDatatable($assets)
{
return (new DatatablesTransformer)->transformDatatables($assets);
}
}

View File

@@ -24,6 +24,7 @@ class DepreciationsTransformer
'id' => (int) $depreciation->id,
'name' => e($depreciation->name),
'months' => $depreciation->months . ' '. trans('general.months'),
'depreciation_min' => $depreciation->depreciation_min,
'created_at' => Helper::getFormattedDateObject($depreciation->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime'),
];

View File

@@ -31,7 +31,8 @@ class LicensesTransformer
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
'purchase_cost' => e($license->purchase_cost),
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
'purchase_cost_numeric' => $license->purchase_cost,
'notes' => e($license->notes),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'seats' => (int) $license->seats,

View File

@@ -14,7 +14,7 @@ class AccessoryImporter extends ItemImporter
protected function handle($row)
{
parent::handle($row); // TODO: Change the autogenerated stub
$this->createAccessoryIfNotExists();
$this->createAccessoryIfNotExists($row);
}
/**
@@ -23,7 +23,7 @@ class AccessoryImporter extends ItemImporter
* @author Daniel Melzter
* @since 3.0
*/
public function createAccessoryIfNotExists()
public function createAccessoryIfNotExists($row)
{
$accessory = Accessory::where('name', $this->item['name'])->first();
if ($accessory) {
@@ -33,12 +33,14 @@ class AccessoryImporter extends ItemImporter
}
$this->log('Updating Accessory');
$this->item['model_number'] = $this->findCsvMatch($row, "model_number");
$accessory->update($this->sanitizeItemForUpdating($accessory));
$accessory->save();
return;
}
$this->log("No Matching Accessory, Creating a new one");
$accessory = new Accessory();
$this->item['model_number'] = $this->findCsvMatch($row, "model_number");
$accessory->fill($this->sanitizeItemForStoring($accessory));
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.

View File

@@ -41,9 +41,12 @@ class ConsumableImporter extends ItemImporter
$consumable = new Consumable();
$this->item['model_number'] = $this->findCsvMatch($row, "model_number");;
$this->item['item_no'] = $this->findCsvMatch($row, "item_number");
$this->item['min_amt'] = $this->findCsvMatch($row, "minimum quantity");
$this->log("min_amt " . $this->item["min_amt"]);
$consumable->fill($this->sanitizeItemForStoring($consumable));
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
$consumable->unsetEventDispatcher();
$this->log(implode(",", $this->item));
if ($consumable->save()) {
$consumable->logCreate('Imported using CSV Importer');
$this->log("Consumable " . $this->item["name"] . ' was created');

View File

@@ -75,6 +75,7 @@ abstract class Importer
'department' => 'department',
'manager_first_name' => 'manager first name',
'manager_last_name' => 'manager last name',
'min_amt' => 'minimum quantity',
];
/**
* Map of item fields->csv names
@@ -195,11 +196,11 @@ abstract class Importer
$val = $default;
$key = $this->lookupCustomKey($key);
// $this->log("Custom Key: ${key}");
$this->log("Custom Key: ${key}");
if (array_key_exists($key, $array)) {
$val = Encoding::toUTF8(trim($array[ $key ]));
}
// $this->log("${key}: ${val}");
$this->log("${key}: ${val}");
return $val;
}

View File

@@ -100,7 +100,7 @@ class ItemImporter extends Importer
return $this->createOrFetchUser($row);
}
if ($this->item['checkout_class'] === 'location') {
if (strtolower($this->item['checkout_class']) === 'location') {
return Location::findOrFail($this->createOrFetchLocation($this->findCsvMatch($row, 'checkout_location')));
}

View File

@@ -121,12 +121,15 @@ class UserImporter extends ItemImporter
*/
public function createOrFetchDepartment($department_name)
{
if (is_null($department_name) || $department_name == ''){
return null;
}
$department = Department::where(['name' => $department_name])->first();
if ($department) {
$this->log('A matching department ' . $department_name . ' already exists');
return $department->id;
} else {
return null;
}
$department = new department();

View File

@@ -29,6 +29,7 @@
| serial number | serial | Asset, license |
| status | status | Asset ? All |
| supplier | supplier | Asset ? All |
| minimum quantity | min_amt | Consumable |
| termination date | termination_date | License |
| warranty months | warranty_months | Asset |
| User Related Fields | assigned_to | Asset |

View File

@@ -71,20 +71,27 @@ class CheckoutableListener
/**
* Send the appropriate notification
*/
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
->where('assigned_to_id', $event->checkedOutTo->id)
->get();
foreach($acceptances as $acceptance){
if($acceptance->isPending()){
$acceptance->delete();
}
}
\Log::debug('checked out to a user');
if(!$event->checkedOutTo->locale){
\Log::debug('Use default settings locale');
Notification::locale(Setting::getSettings()->locale)->send(
$this->getNotifiables($event),
$this->getNotifiables($event),
$this->getCheckinNotification($event)
);
} else {
\Log::debug('Use user locale? I do not think this works as expected yet');
// \Log::debug(print_r($this->getNotifiables($event), true));
Notification::send(
$this->getNotifiables($event),
$this->getNotifiables($event),
$this->getCheckinNotification($event)
);
}

View File

@@ -91,6 +91,7 @@ class Accessory extends SnipeModel
'supplier_id',
'image',
'qty',
'min_amt',
'requestable'
];
@@ -377,4 +378,17 @@ class Accessory extends SnipeModel
{
return $query->leftJoin('manufacturers', 'accessories.manufacturer_id', '=', 'manufacturers.id')->orderBy('manufacturers.name', $order);
}
/**
* Query builder scope to order on supplier
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderSupplier($query, $order)
{
return $query->leftJoin('suppliers', 'accessories.supplier_id', '=', 'suppliers.id')->orderBy('suppliers.name', $order);
}
}

View File

@@ -26,6 +26,7 @@ use Watson\Validating\ValidatingTrait;
class Asset extends Depreciable
{
protected $presenter = 'App\Presenters\AssetPresenter';
use CompanyableTrait;
use Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait, UniqueSerialTrait;
const LOCATION = 'location';
@@ -180,11 +181,6 @@ class Asset extends Depreciable
*/
public function save(array $params = [])
{
$settings = \App\Models\Setting::getSettings();
// I don't remember why we have this here? Asset tag would always be required, even if auto increment is on...
$this->rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required';
if($this->model_id != '') {
$model = AssetModel::find($this->model_id);
@@ -380,7 +376,7 @@ class Asset extends Depreciable
*/
public function components()
{
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty')->withTrashed();
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty', 'created_at')->withTrashed();
}
@@ -890,7 +886,7 @@ class Asset extends Depreciable
->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%')
->orWhere('assets_users.username', 'LIKE', '%'.$term.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%", "%$term%"]);
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%"]);
}
@@ -1260,7 +1256,7 @@ class Asset extends Depreciable
})->orWhere(function ($query) use ($search) {
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%"])
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');

View File

@@ -78,12 +78,12 @@ final class Company extends SnipeModel
$company_id = null;
}
$table = ($table_name) ? $table_name."." : '';
$table = ($table_name) ? $table_name."." : $query->getModel()->getTable().".";
if(\Schema::hasColumn($query->getModel()->getTable(), $column)){
return $query->where($table.$column, '=', $company_id);
return $query->where($table.$column, '=', $company_id);
} else {
return $query->join('users as users_comp', 'users_comp.id', 'user_id')->where('users_comp.company_id', '=', $company_id);
return $query->join('users as users_comp', 'users_comp.id', 'user_id')->where('users_comp.company_id', '=', $company_id);
}
}

View File

@@ -68,6 +68,7 @@ class Consumable extends SnipeModel
'purchase_cost',
'purchase_date',
'qty',
'min_amt',
'requestable'
];
@@ -78,7 +79,7 @@ class Consumable extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date', 'item_no'];
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date', 'item_no', 'model_number'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -27,7 +27,6 @@ class Ldap extends Model
$ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore;
$ldap_use_tls = Setting::getSettings()->ldap_tls;
// If we are ignoring the SSL cert we need to setup the environment variable
// before we create the connection
if ($ldap_server_cert_ignore=='1') {
@@ -50,10 +49,16 @@ class Ldap extends Model
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
ldap_set_option($connection, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
ldap_set_option($connection, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
}
if ($ldap_use_tls=='1') {
ldap_start_tls($connection);
}
return $connection;
}

View File

@@ -23,7 +23,7 @@ class Location extends SnipeModel
protected $rules = array(
'name' => 'required|min:2|max:255|unique_undeleted',
'city' => 'min:2|max:255|nullable',
'country' => 'min:2|max:2|nullable',
'country' => 'min:2|max:255|nullable',
'address' => 'max:80|nullable',
'address2' => 'max:80|nullable',
'zip' => 'min:3|max:10|nullable',

View File

@@ -52,10 +52,7 @@ class Setting extends Model
'admin_cc_email' => 'email|nullable',
'default_currency' => 'required',
'locale' => 'required',
'slack_endpoint' => 'url|required_with:slack_channel|nullable',
'labels_per_page' => 'numeric',
'slack_channel' => 'regex:/^[\#\@]?\w+/|required_with:slack_endpoint|nullable',
'slack_botname' => 'string|nullable',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
@@ -342,8 +339,60 @@ class Setting extends Model
'is_ad',
'ad_domain',
'ad_append_domain',
'ldap_client_tls_key',
'ldap_client_tls_cert'
])->first()->getAttributes();
return collect($ldapSettings);
}
/**
* Return the filename for the client-side SSL cert
*
* @var string
*/
public static function get_client_side_cert_path()
{
return storage_path().'/ldap_client_tls.cert';
}
/**
* Return the filename for the client-side SSL key
*
* @var string
*/
public static function get_client_side_key_path()
{
return storage_path().'/ldap_client_tls.key';
}
public function update_client_side_cert_files()
{
/**
* I'm not sure if it makes sense to have a cert but no key
* nor vice versa, but for now I'm just leaving it like this.
*
* Also, we could easily set this up with an event handler and
* self::saved() or something like that but there's literally only
* one place where we will do that, so I'll just explicitly call
* this method at that spot instead. It'll be easier to debug and understand.
*/
if ($this->ldap_client_tls_cert) {
file_put_contents(self::get_client_side_cert_path(), $this->ldap_client_tls_cert);
} else {
if (file_exists(self::get_client_side_cert_path())) {
unlink(self::get_client_side_cert_path());
}
}
if ($this->ldap_client_tls_key) {
file_put_contents(self::get_client_side_key_path(), $this->ldap_client_tls_key);
} else {
if (file_exists(self::get_client_side_key_path())) {
unlink(self::get_client_side_key_path());
}
}
}
}

View File

@@ -41,7 +41,7 @@ class Statuslabel extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name'];
protected $searchableAttributes = ['name', 'notes'];
/**
* The relations and their attributes that should be included when searching the model.

View File

@@ -619,7 +619,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
$query = $query->where('first_name', 'LIKE', '%'.$search.'%')
->orWhere('last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$search%", "%$search%"]);
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$search%"]);
return $query;
}
@@ -635,7 +635,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
public function advancedTextSearch(Builder $query, array $terms) {
foreach($terms as $term) {
$query = $query->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$term%", "%$term%"]);
$query = $query->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$term%"]);
}
return $query;

View File

@@ -146,7 +146,6 @@ class AssetPresenter extends Presenter
"searchable" => true,
"sortable" => true,
"title" => trans('general.purchase_cost'),
"formatter" => 'numberWithCommas',
"footerFormatter" => 'sumFormatter',
], [
"field" => "order_number",

View File

@@ -56,6 +56,13 @@ class CategoryPresenter extends Presenter
"title" => trans('admin/categories/table.eula_text'),
"visible" => false,
"formatter" => 'trueFalseFormatter',
],[
"field" => "use_default_eula",
"searchable" => false,
"sortable" => true,
"title" => trans('admin/categories/general.use_default_eula_column'),
"visible" => false,
"formatter" => 'trueFalseFormatter',
],[
"field" => "checkin_email",
"searchable" => false,

View File

@@ -0,0 +1,401 @@
<?php
namespace App\Presenters;
use DateTime;
/**
* Class DepreciationReportPresenter
* @package App\Presenters
*/
class DepreciationReportPresenter extends Presenter
{
/**
* Json Column Layout for bootstrap table
* @return string
*/
public static function dataTableLayout()
{
$layout = [
[
"field" => "company",
"searchable" => true,
"sortable" => true,
"switchable" => true,
"title" => trans('general.company'),
"visible" => false,
], [
"field" => "category",
"searchable" => true,
"sortable" => true,
"title" => trans('general.category'),
"visible" => true,
], [
"field" => "name",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.name'),
"visible" => false,
], [
"field" => "asset_tag",
"searchable" => true,
"sortable" => true,
"title" => trans('general.asset_tag'),
"visible" => true,
],[
"field" => "model",
"searchable" => true,
"sortable" => true,
"title" => trans('general.asset_model'),
"visible" => true,
], [
"field" => "model",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.model'),
"visible" => true,
], [
"field" => "model_number",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/models/table.modelnumber'),
"visible" => false
], [
"field" => "serial",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.serial'),
"visible" => true,
], [
"field" => "depreciation",
"searchable" => true,
"sortable" => true,
"title" => trans('general.depreciation'),
"visible" => true,
], [
"field" => "number_of_months",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/depreciations/general.number_of_months'),
"visible" => true,
], [
"field" => "status",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.status'),
"visible" => true,
], [
"field" => "checked_out_to",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.checkoutto'),
"visible" => false,
], [
"field" => "location",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.location'),
"visible" => true,
], [
"field" => "manufacturer",
"searchable" => true,
"sortable" => true,
"title" => trans('general.manufacturer'),
"visible" => false,
],[
"field" => "supplier",
"searchable" => true,
"sortable" => true,
"title" => trans('general.supplier'),
"visible" => false,
], [
"field" => "purchase_date",
"searchable" => true,
"sortable" => true,
"visible" => true,
"title" => trans('general.purchase_date'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "currency",
"searchable" => false,
"sortable" => false,
"visible" => false,
"title" => 'Currency',
], [
"field" => "purchase_cost",
"searchable" => true,
"sortable" => true,
"visible" => true,
"title" => trans('general.purchase_cost'),
"footerFormatter" => 'sumFormatter',
], [
"field" => "order_number",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('general.order_number'),
], [
"field" => "eol",
"searchable" => false,
"sortable" => false,
"visible" => false,
"title" => trans('general.eol'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "book_value",
"searchable" => true,
"sortable" => true,
"visible" => true,
"title" => trans('admin/hardware/table.book_value'),
"footerFormatter" => 'sumFormatter',
], [
"field" => "monthly_depreciation",
"searchable" => true,
"sortable" => true,
"visible" => true,
"title" => trans('admin/hardware/table.monthly_depreciation')
],[
"field" => "diff",
"searchable" => false,
"sortable" => false,
"visible" => true,
"title" => trans('admin/hardware/table.diff'),
"footerFormatter" => 'sumFormatter',
],[
"field" => "warranty_expires",
"searchable" => false,
"sortable" => false,
"visible" => false,
"title" => trans('admin/hardware/form.warranty_expires'),
"formatter" => "dateDisplayFormatter"
],
];
return json_encode($layout);
}
/**
* Generate html link to this items name.
* @return string
*/
public function nameUrl()
{
return (string) link_to_route('hardware.show', e($this->name), $this->id);
}
public function modelUrl()
{
if ($this->model->model) {
return $this->model->model->present()->nameUrl();
}
return '';
}
/**
* Generate img tag to this items image.
* @return mixed|string
*/
public function imageUrl()
{
$imagePath = '';
if ($this->image && !empty($this->image)) {
$imagePath = $this->image;
$imageAlt = $this->name;
} elseif ($this->model && !empty($this->model->image)) {
$imagePath = $this->model->image;
$imageAlt = $this->model->name;
}
$url = config('app.url');
if (!empty($imagePath)) {
$imagePath = '<img src="'.$url.'/uploads/assets/'.$imagePath.' height="50" width="50" alt="'.$imageAlt.'">';
}
return $imagePath;
}
/**
* Generate img tag to this items image.
* @return mixed|string
*/
public function imageSrc()
{
$imagePath = '';
if ($this->image && !empty($this->image)) {
$imagePath = $this->image;
} elseif ($this->model && !empty($this->model->image)) {
$imagePath = $this->model->image;
}
if (!empty($imagePath)) {
return config('app.url').'/uploads/assets/'.$imagePath;
}
return $imagePath;
}
/**
* Get Displayable Name
* @return string
*
* @todo this should be factored out - it should be subsumed by fullName (below)
*
**/
public function name()
{
return $this->fullName;
}
/**
* Helper for notification polymorphism.
* @return mixed
*/
public function fullName()
{
$str = '';
// Asset name
if ($this->model->name) {
$str .= $this->model->name;
}
// Asset tag
if ($this->asset_tag) {
$str .= ' ('.$this->model->asset_tag.')';
}
// Asset Model name
if ($this->model->model) {
$str .= ' - '.$this->model->model->name;
}
return $str;
}
/**
* Returns the date this item hits EOL.
* @return false|string
*/
public function eol_date()
{
if (( $this->purchase_date ) && ( $this->model->model ) && ($this->model->model->eol) ) {
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->model->model->eol . ' months'));
return date_format($date, 'Y-m-d');
}
}
/**
* How many months until this asset hits EOL.
* @return null
*/
public function months_until_eol()
{
$today = date("Y-m-d");
$d1 = new DateTime($today);
$d2 = new DateTime($this->eol_date());
if ($this->eol_date() > $today) {
$interval = $d2->diff($d1);
} else {
$interval = null;
}
return $interval;
}
/**
* @return string
* This handles the status label "meta" status of "deployed" if
* it's assigned. Should maybe deprecate.
*/
public function statusMeta()
{
if ($this->model->assigned) {
return 'deployed';
}
return $this->model->assetstatus->getStatuslabelType();
}
/**
* @return string
* This handles the status label "meta" status of "deployed" if
* it's assigned. Should maybe deprecate.
*/
public function statusText()
{
if ($this->model->assigned) {
return trans('general.deployed');
}
return $this->model->assetstatus->name;
}
/**
* @return string
* This handles the status label "meta" status of "deployed" if
* it's assigned. Results look like:
*
* (if assigned and the status label is "Ready to Deploy"):
* (Deployed)
*
* (f assigned and status label is not "Ready to Deploy":)
* Deployed (Another Status Label)
*
* (if not deployed:)
* Another Status Label
*/
public function fullStatusText() {
// Make sure the status is valid
if ($this->assetstatus) {
// If the status is assigned to someone or something...
if ($this->model->assigned) {
// If it's assigned and not set to the default "ready to deploy" status
if ($this->assetstatus->name != trans('general.ready_to_deploy')) {
return trans('general.deployed'). ' (' . $this->model->assetstatus->name.')';
}
// If it's assigned to the default "ready to deploy" status, just
// say it's deployed - otherwise it's confusing to have a status that is
// both "ready to deploy" and deployed at the same time.
return trans('general.deployed');
}
// Return just the status name
return $this->model->assetstatus->name;
}
// This status doesn't seem valid - either data has been manually edited or
// the status label was deleted.
return 'Invalid status';
}
/**
* Date the warantee expires.
* @return false|string
*/
public function warrantee_expires()
{
if (($this->purchase_date) && ($this->warranty_months)) {
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->warranty_months . ' months'));
return date_format($date, 'Y-m-d');
}
return false;
}
/**
* Url to view this item.
* @return string
*/
public function viewUrl()
{
return route('hardware.show', $this->id);
}
public function glyph()
{
return '<i class="fa fa-barcode" aria-hidden="true"></i>';
}
}

View File

@@ -135,7 +135,7 @@ class LdapAd extends LdapAdConfiguration
$bind_as_user = true;
}
if ($this->ldap->auth()->attempt($login_username, $password, $bind_as_user) === false) {
if (($this->ldap) && ($this->ldap->auth()->attempt($login_username, $password, $bind_as_user) === false)) {
throw new Exception('Unable to validate user credentials!');
}

View File

@@ -156,7 +156,7 @@ class LdapAdConfiguration
private function setLdapConnectionConfiguration(): array
{
// Create the configuration array.
return [
$ldap_settings = [
// Mandatory Configuration Options
'hosts' => $this->getServerUrlBase(),
'base_dn' => $this->ldapSettings['ldap_basedn'],
@@ -180,6 +180,14 @@ class LdapAdConfiguration
// LDAP_OPT_X_TLS_REQUIRE_CERT => LDAP_OPT_X_TLS_HARD,
],
];
if($this->ldapSettings['ldap_client_tls_cert'] || $this->ldapSettings['ldap_client_tls_key']) {
$ldap_settings['custom_options'] = [
LDAP_OPT_X_TLS_CERTFILE => Setting::get_client_side_cert_path(),
LDAP_OPT_X_TLS_KEYFILE => Setting::get_client_side_key_path()
];
}
return $ldap_settings;
}
/**

View File

@@ -41,6 +41,7 @@
"laravel/tinker": "^2.4",
"laravelcollective/html": "^6.0",
"league/csv": "^9.5",
"league/flysystem": "1.1.4",
"league/flysystem-aws-s3-v3": "^1.0",
"league/flysystem-cached-adapter": "^1.0",
"neitanod/forceutf8": "^2.0",
@@ -110,6 +111,9 @@
"sort-packages": true,
"optimize-autoloader": true,
"discard-changes": true,
"process-timeout": 3000
"process-timeout": 3000,
"platform": {
"php": "7.2.5"
}
}
}

1008
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -407,6 +407,7 @@ return [
'Google2FA' => PragmaRX\Google2FALaravel\Facade::class,
'Image' => Intervention\Image\ImageServiceProvider::class,
'Carbon' => Carbon\Carbon::class,
'Helper' => App\Helpers\Helper::class, // makes it much easier to use 'Helper::blah' in blades (which is where we usually use this)
],

View File

@@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v5.1.5',
'full_app_version' => 'v5.1.5 - build 6029-gb8c356443',
'build_version' => '6029',
'app_version' => 'v5.3.4',
'full_app_version' => 'v5.3.4 - build 6550-g39b0dc136',
'build_version' => '6550',
'prerelease_version' => '',
'hash_version' => 'gb8c356443',
'full_hash' => 'v5.1.5-125-gb8c356443',
'hash_version' => 'g39b0dc136',
'full_hash' => 'v5.3.4-17-g39b0dc136',
'branch' => 'master',
);

View File

@@ -226,26 +226,26 @@ $factory->state(App\Models\AssetModel::class, 'tab3-model', function ($faker) {
|--------------------------------------------------------------------------
*/
$factory->state(App\Models\AssetModel::class, 'iphone6s-model', function ($faker) {
$factory->state(App\Models\AssetModel::class, 'iphone11-model', function ($faker) {
return [
'name' => 'iPhone 6s',
'name' => 'iPhone 11',
'category_id' => 4,
'manufacturer_id' => 1,
'eol' => '12',
'depreciation_id' => 3,
'image' => 'iphone6.jpg',
'image' => 'iphone11.jpeg',
'fieldset_id' => 1,
];
});
$factory->state(App\Models\AssetModel::class, 'iphone7-model', function ($faker) {
$factory->state(App\Models\AssetModel::class, 'iphone12-model', function ($faker) {
return [
'name' => 'iPhone 7',
'name' => 'iPhone 12',
'category_id' => 4,
'manufacturer_id' => 1,
'eol' => '12',
'depreciation_id' => 1,
'image' => 'iphone7.jpg',
'image' => 'iphone12.jpeg',
'fieldset_id' => 1,
];
});

View File

@@ -15,9 +15,16 @@ class MoveAccessoryCheckoutNoteToJoinTable extends Migration
*/
public function up()
{
Schema::table('accessories_users', function (Blueprint $table) {
$table->string('note')->nullable(true)->default(null);
});
if (!Schema::hasColumn('accessories_users', 'note'))
{
Schema::table('accessories_users', function (Blueprint $table) {
$table->string('note')->nullable(true)->default(null);
});
}
// Loop through the checked out accessories, find their related action_log entry, and copy over the note
// to the newly created note field
@@ -44,8 +51,10 @@ class MoveAccessoryCheckoutNoteToJoinTable extends Migration
$action_log_entries = Actionlog::where('created_at', '=',$join_log->created_at)
->where('target_id', '=',$join_log->assigned_to)
->where('item_id', '=',$accessory->id)
->where('item_type', '=','App\\Models\\Accessory')
->where('target_type', '=','App\\Models\\User')
->where('action_type', '=', 'checkout')
->where('note', '!=', '')
->orderBy('created_at', 'DESC')->get();
\Log::debug($action_log_entries->count().' matching entries in the action_logs table');
@@ -82,8 +91,15 @@ class MoveAccessoryCheckoutNoteToJoinTable extends Migration
*/
public function down()
{
Schema::table('accessories_users', function (Blueprint $table) {
$table->dropColumn('note');
});
if (Schema::hasColumn('accessories_users', 'note'))
{
Schema::table('accessories_users', function (Blueprint $table)
{
$table->dropColumn('note');
});
}
}
}

View File

@@ -14,7 +14,7 @@ class AddDigitSeparatorToSettings extends Migration
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->char('digit_separator')->nullable()->default('1234.56');
$table->char('digit_separator')->nullable()->default('1,234.56');
});
}

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