Compare commits

..

352 Commits

Author SHA1 Message Date
snipe b1359c3277 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-08-28 18:34:14 +01:00
snipe 0ba8f5cc5a Merge remote-tracking branch 'origin/develop' 2025-08-28 18:06:29 +01:00
snipe 6fb9e2c38e Merge remote-tracking branch 'origin/develop' 2025-08-28 16:12:18 +01:00
snipe eebc2ab8be Merge remote-tracking branch 'origin/develop' 2025-08-28 07:30:15 +01:00
snipe b65b3151ee Merge remote-tracking branch 'origin/develop' 2025-08-28 05:29:48 +01:00
snipe 13a0f49f5f Merge remote-tracking branch 'origin/develop' 2025-08-27 16:36:05 +01:00
snipe 199eefafa1 Merge remote-tracking branch 'origin/develop' 2025-08-27 14:38:47 +01:00
snipe c5b58f9ecc Merge remote-tracking branch 'origin/develop' 2025-08-27 13:32:25 +01:00
snipe 6b68fe4de6 Merge remote-tracking branch 'origin/develop' 2025-08-27 13:30:19 +01:00
snipe 3461bbfdb3 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/app.css.map
#	public/css/build/overrides.css
#	public/css/build/overrides.css.map
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-08-27 12:28:22 +01:00
snipe 00a17cd55e Merge remote-tracking branch 'origin/develop' 2025-08-21 11:51:50 +01:00
snipe f39afe5a65 Merge remote-tracking branch 'origin/develop' 2025-08-20 15:56:19 +01:00
snipe 7612ee6b08 Merge remote-tracking branch 'origin/develop' 2025-08-20 14:17:38 +01:00
snipe 2ed2b0101a Merge remote-tracking branch 'origin/develop' 2025-08-20 12:43:57 +01:00
snipe 5ca9d31964 Merge remote-tracking branch 'origin/develop' 2025-08-20 11:32:27 +01:00
snipe 2fcd8cd261 Merge remote-tracking branch 'origin/develop' 2025-08-20 11:00:26 +01:00
snipe 0ffa47a2c6 Merge remote-tracking branch 'origin/develop' 2025-08-20 09:58:54 +01:00
snipe e203d4dee3 Merge remote-tracking branch 'origin/develop' 2025-08-19 14:49:00 +01:00
snipe b47d773e13 Merge remote-tracking branch 'origin/develop' 2025-08-19 14:34:32 +01:00
snipe a8d0a4a95d Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/js/dist/all.js
#	public/js/dist/all.js.map
#	public/mix-manifest.json
2025-08-19 14:12:58 +01:00
snipe 3fb0804cef Merge remote-tracking branch 'origin/develop' 2025-08-19 13:57:36 +01:00
snipe 6811ebcd52 Merge remote-tracking branch 'origin/develop' 2025-08-19 10:12:56 +01:00
snipe 4fe7bfb851 Merge remote-tracking branch 'origin/develop' 2025-08-18 15:24:25 +01:00
snipe fb60985d03 Merge remote-tracking branch 'origin/develop' 2025-08-18 12:47:19 +01:00
snipe 8f575923cf Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/app.css.map
#	public/css/build/overrides.css
#	public/css/build/overrides.css.map
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-08-18 11:26:43 +01:00
snipe 0ecfd02649 Merge remote-tracking branch 'origin/develop' 2025-08-18 11:00:30 +01:00
snipe 420aaf4f61 Merge remote-tracking branch 'origin/develop' 2025-08-18 09:45:19 +01:00
snipe 0c35f213e1 Merge remote-tracking branch 'origin/develop' 2025-08-17 14:54:43 +01:00
snipe f68813af13 Merge remote-tracking branch 'origin/develop' 2025-08-17 14:11:41 +01:00
snipe 37a90d0ce9 Merge remote-tracking branch 'origin/develop' 2025-08-15 15:07:29 +02:00
snipe 02f1291e8f Merge remote-tracking branch 'origin/develop' 2025-08-15 14:41:24 +02:00
snipe 92e4f6b5d9 Merge remote-tracking branch 'origin/develop' 2025-08-15 14:31:53 +02:00
snipe 7b7738fbcc Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/app.css.map
#	public/css/build/overrides.css
#	public/css/build/overrides.css.map
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-08-15 14:24:30 +02:00
snipe 31197604a3 Merge pull request #17602 from grokability/develop
Merge develop into master
2025-08-13 21:19:39 +02:00
snipe f42a2d7457 Merge remote-tracking branch 'origin/develop' 2025-08-11 20:45:38 +01:00
snipe d29619b67c Merge remote-tracking branch 'origin/develop' 2025-08-11 18:50:17 +01:00
snipe f5235cb835 Merge remote-tracking branch 'origin/develop' 2025-08-11 18:12:51 +01:00
snipe ee830e0cb4 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/app.css.map
#	public/css/build/overrides.css
#	public/css/build/overrides.css.map
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-08-11 14:58:57 +01:00
snipe 0cd3be003d Merge remote-tracking branch 'origin/develop' 2025-08-11 13:07:00 +01:00
snipe c93e35ec77 Merge remote-tracking branch 'origin/develop' 2025-08-11 11:18:31 +01:00
snipe 9538a76232 Merge remote-tracking branch 'origin/develop' 2025-08-11 06:26:29 +01:00
snipe 05876bb124 Merge remote-tracking branch 'origin/develop' 2025-08-11 05:05:13 +01:00
snipe 8bcd5a6d2a Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-08-10 21:04:55 +01:00
snipe a36afbcb25 Merge remote-tracking branch 'origin/develop' 2025-08-10 21:02:48 +01:00
snipe ebd8d085cf Merge remote-tracking branch 'origin/develop' 2025-08-10 21:01:34 +01:00
snipe 505148b024 Merge remote-tracking branch 'origin/develop' 2025-08-10 20:51:27 +01:00
snipe e87e924ac2 Merge remote-tracking branch 'origin/develop' 2025-08-08 11:37:46 +01:00
snipe 90f261bab6 Merge remote-tracking branch 'origin/develop' 2025-08-08 11:32:14 +01:00
snipe f7dfb09a4d Merge remote-tracking branch 'origin/develop' 2025-08-08 09:56:23 +01:00
snipe 3135917127 Merge remote-tracking branch 'origin/develop' 2025-08-07 17:03:01 +01:00
snipe 52afa3d36d Merge remote-tracking branch 'origin/develop' 2025-08-06 16:35:59 +01:00
snipe 242aa60e04 Merge remote-tracking branch 'origin/develop' 2025-08-06 16:26:14 +01:00
snipe 7a3c2c27ff Merge remote-tracking branch 'origin/develop' 2025-08-05 23:19:38 +01:00
snipe 5d124360c2 Merge remote-tracking branch 'origin/develop' 2025-08-05 19:35:12 +01:00
snipe 365d7448d5 Merge remote-tracking branch 'origin/develop' 2025-08-05 19:06:34 +01:00
snipe 9a0102c723 Merge remote-tracking branch 'origin/develop' 2025-08-05 19:03:00 +01:00
snipe 2f77f2cb2b Merge remote-tracking branch 'origin/develop' 2025-08-05 18:13:27 +01:00
snipe 528e3a2106 Merge remote-tracking branch 'origin/develop' 2025-08-05 17:48:12 +01:00
snipe 032a664d4c Merge remote-tracking branch 'origin/develop' 2025-08-04 22:27:59 +01:00
snipe aac1864c9b Merge remote-tracking branch 'origin/develop' 2025-08-04 21:23:41 +01:00
snipe e3477f3306 Merge remote-tracking branch 'origin/develop' 2025-08-02 18:41:39 +01:00
snipe 6620a4f87b Merge remote-tracking branch 'origin/develop' 2025-08-02 14:47:09 +01:00
snipe c0e9dff5bf Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/js/dist/all.js
#	public/js/dist/all.js.map
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-08-01 23:13:22 +01:00
snipe 2d961c435a Merge remote-tracking branch 'origin/develop' 2025-07-31 04:11:31 +01:00
snipe 7c95f03166 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/AdminLTE.css
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	public/css/dist/skins/skin-black-dark.css
#	public/css/dist/skins/skin-black-dark.min.css
#	public/css/dist/skins/skin-black.css
#	public/css/dist/skins/skin-black.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-blue.css
#	public/css/dist/skins/skin-blue.min.css
#	public/css/dist/skins/skin-contrast.css
#	public/css/dist/skins/skin-contrast.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-green.css
#	public/css/dist/skins/skin-green.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-orange.css
#	public/css/dist/skins/skin-orange.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-purple.css
#	public/css/dist/skins/skin-purple.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/css/dist/skins/skin-red.css
#	public/css/dist/skins/skin-red.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/css/dist/skins/skin-yellow.css
#	public/css/dist/skins/skin-yellow.min.css
#	public/js/build/app.js
#	public/js/build/vendor.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-07-28 17:41:13 +01:00
snipe 31e5c13b50 Merge remote-tracking branch 'origin/develop' 2025-07-28 03:30:22 +01:00
snipe 4a9fe4f981 Merge remote-tracking branch 'origin/develop' 2025-07-24 15:54:54 +01:00
snipe 4fcc5587ee Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-07-24 15:36:06 +01:00
snipe 6ca49a20ce Merge remote-tracking branch 'origin/develop' 2025-07-24 15:29:54 +01:00
snipe 28f293fdc1 Merge remote-tracking branch 'origin/develop' 2025-07-24 13:07:09 +01:00
snipe b3e7619adc Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-07-23 16:11:20 +01:00
snipe 6e56d56137 Merge remote-tracking branch 'origin/develop' 2025-07-23 15:06:25 +01:00
snipe 2528f6a07b Merge remote-tracking branch 'origin/develop' 2025-07-23 14:56:49 +01:00
snipe 423d07c919 Merge remote-tracking branch 'origin/develop' 2025-07-23 12:41:20 +01:00
snipe cc608de4bf Merge remote-tracking branch 'origin/develop' 2025-07-23 12:28:35 +01:00
snipe f999a68608 Merge remote-tracking branch 'origin/develop' 2025-07-22 20:28:53 +01:00
snipe db78a9f18f Merge remote-tracking branch 'origin/develop' 2025-07-22 15:25:51 +01:00
snipe 816039f48e Merge remote-tracking branch 'origin/develop' 2025-07-22 15:18:50 +01:00
snipe ae240bae6d Updated prod CSS
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 15:14:42 +01:00
snipe 9e30c69e6d Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-07-22 15:14:32 +01:00
snipe 43c7de9049 Updated prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 14:38:04 +01:00
snipe 7e51c5db81 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-07-22 14:34:10 +01:00
snipe 0ee3c45e7b Merge remote-tracking branch 'origin/develop' 2025-07-22 13:39:54 +01:00
snipe 981e69929c Merge remote-tracking branch 'origin/develop' 2025-07-21 12:36:44 +01:00
snipe 1eae5d12fc Merge remote-tracking branch 'origin/develop' 2025-07-18 17:56:20 +01:00
snipe 8863208333 Merge remote-tracking branch 'origin/develop' 2025-07-16 17:35:55 +01:00
snipe 5f38a74a72 Merge remote-tracking branch 'origin/develop' 2025-07-16 17:02:29 +01:00
snipe fe15dacb1f Merge remote-tracking branch 'origin/develop' 2025-07-16 16:54:30 +01:00
snipe c2d44cf2f2 Merge remote-tracking branch 'origin/develop' 2025-07-16 12:25:14 +01:00
snipe 7f1bdb6f34 Merge remote-tracking branch 'origin/develop' 2025-07-15 10:58:58 +01:00
snipe b0305e12d2 Merge remote-tracking branch 'origin/develop' 2025-07-10 13:11:10 +01:00
snipe 58f76b5c99 Merge remote-tracking branch 'origin/develop' 2025-07-09 21:01:24 +01:00
snipe 7c4ee632cf Merge remote-tracking branch 'origin/develop' 2025-07-09 20:58:17 +01:00
snipe b6b0f716eb Merge remote-tracking branch 'origin/develop' 2025-07-09 20:22:25 +01:00
snipe bd0e04ed15 Merge remote-tracking branch 'origin/develop' 2025-07-09 15:48:17 +01:00
snipe 8599981d44 Merge remote-tracking branch 'origin/develop' 2025-07-09 15:46:53 +01:00
snipe 6fc6e95c67 Merge remote-tracking branch 'origin/develop' 2025-07-08 22:02:34 +01:00
snipe 43b585bde8 Merge remote-tracking branch 'origin/develop' 2025-07-08 21:59:58 +01:00
snipe 710f89291f Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-07-08 21:27:06 +01:00
snipe 4c6249eb9e Merge remote-tracking branch 'origin/develop' 2025-07-07 22:09:45 +01:00
snipe 016900bad8 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-07-07 21:54:04 +01:00
snipe 2e8ae33761 Merge remote-tracking branch 'origin/develop' 2025-07-07 20:58:36 +01:00
snipe 0d325060da Merge remote-tracking branch 'origin/develop' 2025-07-07 17:06:24 +01:00
snipe 1a6e98e18f Merge remote-tracking branch 'origin/develop' 2025-07-07 16:24:04 +01:00
snipe 97e34595f6 Merge remote-tracking branch 'origin/develop' 2025-07-07 16:00:10 +01:00
snipe a179d5234b Merge remote-tracking branch 'origin/develop' 2025-07-07 14:43:28 +01:00
snipe 64c6121fdb Merge remote-tracking branch 'origin/develop' 2025-07-07 14:00:55 +01:00
snipe 08d8954a85 Merge remote-tracking branch 'origin/develop' 2025-07-07 14:00:03 +01:00
snipe 4f20955d0d Merge remote-tracking branch 'origin/develop' 2025-07-07 13:46:03 +01:00
snipe 3a703c8bcf Merge remote-tracking branch 'origin/develop' 2025-07-07 13:35:07 +01:00
snipe ccbffa086b Merge remote-tracking branch 'origin/develop' 2025-07-07 11:36:33 +01:00
snipe 07ee4be840 Merge remote-tracking branch 'origin/develop' 2025-07-02 18:38:12 +01:00
snipe 4cc9b2d312 Merge remote-tracking branch 'origin/develop' 2025-07-02 17:21:39 +01:00
snipe 24dddae1d1 Merge remote-tracking branch 'origin/develop' 2025-07-02 11:57:57 +01:00
snipe ad0165d085 Merge remote-tracking branch 'origin/develop' 2025-07-02 11:44:30 +01:00
snipe 39dc38c5d1 Merge remote-tracking branch 'origin/develop' 2025-07-01 23:32:43 +01:00
snipe 046ce19dbb Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-06-30 11:46:24 +01:00
snipe 33263f5a93 Merge remote-tracking branch 'origin/develop' 2025-06-27 13:52:09 +01:00
snipe 8ef8e76300 Merge remote-tracking branch 'origin/develop' 2025-06-27 12:48:54 +01:00
snipe 73cfdae9e7 Merge remote-tracking branch 'origin/develop' 2025-06-25 15:00:46 +01:00
snipe 54a3e41281 Merge remote-tracking branch 'origin/develop' 2025-06-25 14:58:46 +01:00
snipe d59ba6da84 Merge remote-tracking branch 'origin/develop' 2025-06-25 13:11:39 +01:00
snipe 1b28b06934 Merge remote-tracking branch 'origin/develop' 2025-06-25 11:04:15 +01:00
snipe ff3e69a56c Merge remote-tracking branch 'origin/develop' 2025-06-23 20:51:24 +01:00
snipe 6b975a5fb4 Merge remote-tracking branch 'origin/develop' 2025-06-23 16:41:42 +01:00
snipe 3a02b15124 Merge remote-tracking branch 'origin/develop' 2025-06-23 12:38:40 +01:00
snipe 5f73d81935 Merge remote-tracking branch 'origin/develop' 2025-06-22 20:14:59 +01:00
snipe 002b5c0f6f Merge remote-tracking branch 'origin/develop' 2025-06-22 20:07:52 +01:00
snipe 8086842570 Merge remote-tracking branch 'origin/develop' 2025-06-22 19:42:03 +01:00
snipe 51f2d5a664 Merge remote-tracking branch 'origin/develop' 2025-06-22 19:30:42 +01:00
snipe b74b76de75 Merge remote-tracking branch 'origin/develop' 2025-06-17 18:17:10 +01:00
snipe a1b1498106 Merge remote-tracking branch 'origin/develop' 2025-06-17 17:51:37 +01:00
snipe 1158851ea7 Merge remote-tracking branch 'origin/develop' 2025-06-17 15:57:12 +01:00
snipe e1ab9e959e Merge remote-tracking branch 'origin/develop' 2025-06-17 13:03:27 +01:00
snipe 2bbac3ae9d Merge remote-tracking branch 'origin/develop' 2025-06-17 12:38:52 +01:00
snipe e889b1d5e5 Merge remote-tracking branch 'origin/develop' 2025-06-17 11:42:00 +01:00
snipe 233bf856f4 Merge remote-tracking branch 'origin/develop' 2025-06-17 11:39:12 +01:00
snipe bca843e06c Merge remote-tracking branch 'origin/develop' 2025-06-16 20:32:40 +01:00
snipe 30a79a1278 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-06-16 14:45:53 +01:00
snipe 0f92dee2c4 Merge remote-tracking branch 'origin/develop' 2025-06-15 03:41:23 +01:00
snipe f04efede15 Merge remote-tracking branch 'origin/develop' 2025-06-15 02:59:47 +01:00
snipe f0dfdf6720 Merge remote-tracking branch 'origin/develop' 2025-06-14 23:56:06 +01:00
snipe e26d731382 Merge remote-tracking branch 'origin/develop' 2025-06-14 23:08:48 +01:00
snipe d684d3e559 Merge remote-tracking branch 'origin/develop' 2025-06-14 22:22:54 +01:00
snipe 47c54cb998 Merge remote-tracking branch 'origin/develop' 2025-06-14 17:45:44 +01:00
snipe 592cb2b3ec Merge remote-tracking branch 'origin/develop' 2025-06-14 17:08:11 +01:00
snipe f5a7871a2e Merge remote-tracking branch 'origin/develop' 2025-06-14 16:44:48 +01:00
snipe ec411fa0db Merge remote-tracking branch 'origin/develop' 2025-06-14 12:17:43 +01:00
snipe a850a9bb83 Merge remote-tracking branch 'origin/develop' 2025-06-12 21:34:59 +01:00
snipe 479b7a3f94 Merge remote-tracking branch 'origin/develop' 2025-06-11 10:32:49 +01:00
snipe f7cfee77c9 Merge remote-tracking branch 'origin/develop' 2025-06-11 10:20:22 +01:00
snipe 65a8126a13 Merge remote-tracking branch 'origin/develop' 2025-06-09 13:40:44 +01:00
snipe a39bc102d5 Merge remote-tracking branch 'origin/develop' 2025-06-08 15:30:32 +01:00
snipe 81d930c4d2 Merge remote-tracking branch 'origin/develop' 2025-06-08 15:19:19 +01:00
snipe 6839623061 Merge remote-tracking branch 'origin/develop' 2025-06-06 17:03:37 +01:00
snipe 7de2809d42 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-06-06 14:05:47 +01:00
snipe 98ec6b6886 Merge remote-tracking branch 'origin/develop' 2025-06-06 12:48:54 +01:00
snipe 04827f00cc Merge remote-tracking branch 'origin/develop' 2025-06-06 11:54:10 +01:00
snipe 660bfc6578 Merge remote-tracking branch 'origin/develop' 2025-06-06 08:31:09 +01:00
snipe 1152cd5537 Merge remote-tracking branch 'origin/develop' 2025-06-06 08:26:52 +01:00
snipe f30e8497b2 Merge remote-tracking branch 'origin/develop' 2025-06-04 16:17:26 +01:00
snipe 06495bc45d Merge remote-tracking branch 'origin/develop' 2025-06-04 12:13:30 +01:00
snipe 26067916b3 Merge remote-tracking branch 'origin/develop' 2025-06-04 11:49:03 +01:00
snipe c36ee4852b Merge remote-tracking branch 'origin/develop' 2025-06-04 10:40:56 +01:00
snipe 2cb992ad44 Merge remote-tracking branch 'origin/develop' 2025-06-04 08:43:52 +01:00
snipe 083b7be6c0 Make version number match tagged version :(
Signed-off-by: snipe <snipe@snipe.net>
2025-06-03 11:03:33 +01:00
snipe e24854558f Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-06-03 11:03:05 +01:00
snipe e4314cf426 Merge remote-tracking branch 'origin/develop' 2025-06-03 06:07:20 +01:00
snipe 4106e4e45c Merge remote-tracking branch 'origin/develop' 2025-06-02 22:29:09 +01:00
snipe 05f143db2b Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-06-02 18:15:54 +01:00
snipe 64aeaeeeea Merge remote-tracking branch 'origin/develop' 2025-06-02 17:29:52 +01:00
snipe 61db37ab0d Merge remote-tracking branch 'origin/develop' 2025-06-02 15:28:08 +01:00
snipe f9c4d921e7 Merge remote-tracking branch 'origin/develop' 2025-06-02 15:07:15 +01:00
snipe ca099df573 Merge remote-tracking branch 'origin/develop' 2025-06-02 15:04:00 +01:00
snipe 28b584b8bc Merge remote-tracking branch 'origin/develop' 2025-06-02 02:08:19 +01:00
snipe 70449e694d Merge remote-tracking branch 'origin/develop' 2025-05-29 22:18:50 +01:00
snipe 8395ea552d Merge remote-tracking branch 'origin/develop' 2025-05-29 16:17:58 +01:00
snipe dc66452633 Merge remote-tracking branch 'origin/develop' 2025-05-29 13:32:41 +01:00
snipe 53ce44ac91 Merge remote-tracking branch 'origin/develop' 2025-05-29 12:38:40 +01:00
snipe c7c3243bbc Merge remote-tracking branch 'origin/develop' 2025-05-29 12:35:21 +01:00
snipe 8bdd77d33d Merge remote-tracking branch 'origin/develop' 2025-05-29 12:24:51 +01:00
snipe acd7d0db3a Merge remote-tracking branch 'origin/develop' 2025-05-29 12:09:08 +01:00
snipe 2bfadb8a3c Merge remote-tracking branch 'origin/develop' 2025-05-28 15:21:34 +01:00
snipe 0912e4af7b Merge remote-tracking branch 'origin/develop' 2025-05-26 13:17:38 +01:00
snipe 5aa5c48018 Merge remote-tracking branch 'origin/develop' 2025-05-23 19:37:42 +01:00
snipe 8cdd998f79 Merge remote-tracking branch 'origin/develop' 2025-05-23 17:35:08 +01:00
snipe 050d4d6b25 Merge remote-tracking branch 'origin/develop' 2025-05-23 14:51:48 +01:00
snipe 366cd11238 Merge remote-tracking branch 'origin/develop' 2025-05-23 14:31:10 +01:00
snipe 58d6443331 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-05-23 13:27:44 +01:00
snipe 101b8afb56 Merge remote-tracking branch 'origin/develop' 2025-05-23 13:07:47 +01:00
snipe 5df5c47945 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-05-23 10:43:58 +01:00
snipe a04740ba86 Merge remote-tracking branch 'origin/develop' 2025-05-23 10:42:44 +01:00
snipe 425ad93ac5 Merge remote-tracking branch 'origin/develop' 2025-05-23 10:17:10 +01:00
snipe 8a44144c20 Merge pull request #16954 from grokability/develop
Merge dev into master
2025-05-16 11:16:14 +02:00
snipe ee82c70582 Merge remote-tracking branch 'origin/develop' 2025-05-15 18:32:05 +02:00
snipe c87e8e606b Merge remote-tracking branch 'origin/develop' 2025-05-15 18:02:47 +02:00
snipe 37a50dd953 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-05-15 17:51:54 +02:00
snipe a2669a3084 Removed temp code
Signed-off-by: snipe <snipe@snipe.net>
2025-05-15 17:31:16 +02:00
snipe 77da22f4dd Print errors if they exist (temp)
Signed-off-by: snipe <snipe@snipe.net>
2025-05-15 17:26:04 +02:00
snipe 7830ffe202 Temp echo errors
Signed-off-by: snipe <snipe@snipe.net>
2025-05-15 17:24:08 +02:00
snipe 1c9e20d59f Merge remote-tracking branch 'origin/develop' 2025-05-15 17:10:57 +02:00
snipe 320edac286 Merge remote-tracking branch 'origin/develop' 2025-05-14 17:39:30 +02:00
snipe d49878371d Merge remote-tracking branch 'origin/develop' 2025-05-14 16:23:38 +02:00
snipe d2575a5d9b Add @JassonCordones as a contributor 2025-05-14 15:03:04 +02:00
Marcus Moore ea6cf72580 Formatting 2025-05-14 15:03:04 +02:00
Marcus Moore 2118155b37 Fix bug in getImageUrl method 2025-05-14 15:03:04 +02:00
Marcus Moore ba4f5bb71f Add test for existing functionality 2025-05-14 15:03:04 +02:00
Marcus Moore d5a74a5a8b Remove unneeded div 2025-05-14 15:03:04 +02:00
Marcus Moore 23be1df360 Remove the replaced locales form macro 2025-05-14 15:03:04 +02:00
Marcus Moore b5c1a1da4c Replace Form::locales on user setup 2025-05-14 15:03:04 +02:00
Marcus Moore c11e784f51 Replace Form::locales on bulk edit users page 2025-05-14 15:03:04 +02:00
Marcus Moore 06f51c8f9c Replace Form::locales on user edit page 2025-05-14 15:03:04 +02:00
Marcus Moore 181bcbbda6 Replace Form::locales on localization page 2025-05-14 15:03:04 +02:00
Marcus Moore d008ead6a4 Fix input name 2025-05-14 15:03:04 +02:00
Marcus Moore 75924be958 Introduce locale select component and make replacement on profile page 2025-05-14 15:03:04 +02:00
snipe b1a6e3f8a2 Merge pull request #16930 from JassonCordones/master
fix typo in snipeit.sh
2025-05-14 15:01:41 +02:00
snipe 06712a6041 Merge remote-tracking branch 'origin/develop' 2025-05-14 13:42:51 +02:00
snipe 62b16339a9 Merge remote-tracking branch 'origin/develop' 2025-05-13 20:44:34 +02:00
Jasson 9a2f1a36ba fix typo in snipeit.sh
fix redirect output to stderr
2025-05-13 14:31:37 -04:00
snipe 95cc4d3a73 Merge remote-tracking branch 'origin/develop' 2025-05-09 21:16:58 +01:00
snipe 497eeeb2e0 Merge remote-tracking branch 'origin/develop' 2025-05-09 19:29:01 +01:00
snipe 4be21ca249 Merge remote-tracking branch 'origin/develop' 2025-05-09 18:03:38 +01:00
snipe e8598e214e Merge remote-tracking branch 'origin/develop' 2025-05-09 17:23:22 +01:00
snipe 54b1d65e3c Merge remote-tracking branch 'origin/develop' 2025-05-09 14:46:37 +01:00
snipe f7648496d3 Merge remote-tracking branch 'origin/develop' 2025-05-08 16:26:02 +01:00
snipe 59a57c7197 Merge remote-tracking branch 'origin/develop' 2025-05-08 15:43:53 +01:00
snipe 5659b26827 Merge remote-tracking branch 'origin/develop' 2025-05-08 15:22:43 +01:00
snipe ee4443aaf0 Merge remote-tracking branch 'origin/develop' 2025-05-08 15:09:26 +01:00
snipe 839dcad358 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	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/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/mix-manifest.json
2025-05-07 11:41:31 +01:00
snipe d67933ab49 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	CONTRIBUTORS.md
2025-05-06 16:46:41 +01:00
Godfrey M 0eb3f6b952 set max to 5 2025-05-05 14:42:06 +01:00
Godfrey M 68b0f80fce fix input max, and help block position 2025-05-05 14:42:06 +01:00
Godfrey M 93489529a3 adds Field offset option to labels 2025-05-05 14:42:06 +01:00
snipe 511be74e74 Add @chfsx as a contributor 2025-05-05 14:42:06 +01:00
Fabian Schmid bdee067803 [FIX] set upload-limit 2025-05-05 14:42:06 +01:00
snipe 32156cace3 Merge pull request #16847 from realchrisolin/issue16214
add barcode support for Avery 3490
2025-05-05 14:40:54 +01:00
snipe 30688114be Merge remote-tracking branch 'origin/develop' 2025-05-05 14:04:52 +01:00
snipe 34088bcc17 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-05-05 11:17:01 +01:00
Calvin Schwartz 07835766cc adds support for Avery 3490 2025-05-01 21:11:42 -04:00
Brady Wetherington 251851ec6a Try to get Docker images to build for both architectures 2025-04-30 18:00:39 +01:00
snipe 049a669186 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:46:16 +01:00
snipe d29f13bae9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:26:38 +01:00
snipe c758355df9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:14:34 +01:00
snipe 79d97a83af Merge remote-tracking branch 'origin/develop' 2025-04-30 15:48:38 +01:00
snipe 85bd47c240 Merge remote-tracking branch 'origin/develop' 2025-04-30 15:35:10 +01:00
snipe 473ead9616 Merge remote-tracking branch 'origin/develop' 2025-04-30 13:57:27 +01:00
snipe cf2850933c Merge remote-tracking branch 'origin/develop' 2025-04-30 10:19:43 +01:00
snipe ff2564c57a Merge remote-tracking branch 'origin/develop' 2025-04-30 10:12:05 +01:00
snipe 91d3848246 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-04-29 23:17:51 +01:00
snipe c031f0b45e Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.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/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/mix-manifest.json
2025-04-29 20:38:41 +01:00
snipe fdbb9568ae Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-29 12:39:31 +01:00
snipe d817883459 Merge remote-tracking branch 'origin/develop' 2025-04-29 10:25:42 +01:00
snipe 12255979ac Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-29 10:22:21 +01:00
snipe 366b61850b Merge remote-tracking branch 'origin/develop' 2025-04-26 17:54:02 +01:00
snipe 89be6bd183 Merge remote-tracking branch 'origin/develop' 2025-04-24 14:06:00 +01:00
snipe e120331a2c Merge remote-tracking branch 'origin/develop' 2025-04-24 12:16:53 +01:00
snipe cb8a212d96 Merge remote-tracking branch 'origin/develop' 2025-04-23 21:57:20 +01:00
snipe 7aec431ac5 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:30:16 +01:00
snipe d19681dea1 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:05:38 +01:00
snipe bf2299daf8 Merge remote-tracking branch 'origin/develop' 2025-04-22 17:51:48 +01:00
snipe 164930d0dd Merge remote-tracking branch 'origin/develop' 2025-04-22 16:35:23 +01:00
snipe 387dbac809 Merge remote-tracking branch 'origin/develop' 2025-04-22 14:36:14 +01:00
snipe 3b661e5a99 Merge remote-tracking branch 'origin/develop' 2025-04-22 12:39:35 +01:00
snipe 90c1c0e655 Merge remote-tracking branch 'origin/develop' 2025-04-22 11:42:49 +01:00
snipe 21d8e7695b Merge remote-tracking branch 'origin/develop' 2025-04-21 20:19:54 +01:00
snipe 1acc452cfe Merge remote-tracking branch 'origin/develop' 2025-04-21 14:59:26 +01:00
snipe 1375e1feee Merge remote-tracking branch 'origin/develop' 2025-04-21 12:21:08 +01:00
snipe 2187adf59a Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 15:34:58 +01:00
snipe 0dcb315d9d Merge remote-tracking branch 'origin/develop' 2025-04-18 00:56:26 +01:00
snipe 327ccbd0c9 Merge remote-tracking branch 'origin/develop' 2025-04-18 00:37:11 +01:00
snipe f571d400e6 Merge remote-tracking branch 'origin/develop' 2025-04-17 23:29:12 +01:00
snipe 293aa52335 Merge remote-tracking branch 'origin/develop' 2025-04-17 23:13:04 +01:00
snipe ca178ae9a7 Merge remote-tracking branch 'origin/develop' 2025-04-17 22:48:35 +01:00
snipe d0c810e418 Merge remote-tracking branch 'origin/develop' 2025-04-17 16:42:37 +01:00
snipe d496d2caeb Merge remote-tracking branch 'origin/develop' 2025-04-17 11:59:24 +01:00
snipe e70b75c350 Merge remote-tracking branch 'origin/develop' 2025-04-17 01:00:34 +01:00
snipe a50befeda5 Merge remote-tracking branch 'origin/develop' 2025-04-16 20:16:18 +01:00
snipe e2616e8039 Merge remote-tracking branch 'origin/develop' 2025-04-16 15:52:18 +01:00
snipe 904266debe Merge remote-tracking branch 'origin/develop' 2025-04-16 09:47:18 +01:00
snipe 72d5783795 Merge remote-tracking branch 'origin/develop' 2025-04-16 09:19:05 +01:00
snipe d699fb1473 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:46:43 +01:00
snipe fab1a6c33a Merge remote-tracking branch 'origin/develop' 2025-04-15 20:30:02 +01:00
snipe be73c30194 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-04-15 20:01:20 +01:00
snipe 451646fe4f Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 19:42:26 +01:00
snipe decc919991 Merge remote-tracking branch 'origin/develop' 2025-04-15 19:33:23 +01:00
snipe e0b4005921 Merge remote-tracking branch 'origin/develop' 2025-04-15 16:48:17 +01:00
snipe 3ef36e7534 Merge remote-tracking branch 'origin/develop' 2025-04-14 11:02:06 +01:00
snipe 1949e1e1e9 Merge remote-tracking branch 'origin/develop' 2025-04-14 09:26:25 +01:00
snipe 3358382358 Comment out location scoping option for now
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 21:44:38 +01:00
snipe 3eca3ecd75 Merge remote-tracking branch 'origin/develop' 2025-04-09 21:31:41 +01:00
snipe 140c6b91b0 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-09 02:40:28 +01:00
snipe a5315ec240 Merge remote-tracking branch 'origin/develop' 2025-04-08 08:32:25 +01:00
snipe 93f1656e0b Merge remote-tracking branch 'origin/develop' 2025-04-08 06:51:21 +01:00
snipe f1d006c236 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-08 05:58:51 +01:00
snipe b0b5a96694 Merge remote-tracking branch 'origin/develop' 2025-04-07 13:54:23 +01:00
snipe 7dbe9a85f4 Merge remote-tracking branch 'origin/develop' 2025-04-05 21:02:33 +01:00
snipe d2c39528d5 Merge remote-tracking branch 'origin/develop' 2025-04-05 15:44:22 +01:00
snipe 0420543c94 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-05 14:11:07 +01:00
snipe aae0db902b Merge remote-tracking branch 'origin/develop' 2025-04-03 15:41:08 +01:00
snipe 88dae7cef7 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-03 15:28:10 +01:00
snipe e5cb17e934 Merge remote-tracking branch 'origin/develop' 2025-04-03 10:16:18 +01:00
snipe 9d609805f2 Merge remote-tracking branch 'origin/develop' 2025-04-02 18:33:48 +01:00
snipe e2b9ca8254 Merge remote-tracking branch 'origin/develop' 2025-04-02 14:03:22 +01:00
snipe e16a2fe8af Merge remote-tracking branch 'origin/develop' 2025-04-02 13:51:09 +01:00
snipe 22d61a533d Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-04-02 12:50:35 +01:00
snipe af408bb45f Merge remote-tracking branch 'origin/develop' 2025-04-01 21:33:07 +01:00
snipe 24bfbc06f0 Merge remote-tracking branch 'origin/develop' 2025-04-01 19:40:03 +01:00
snipe 5eb9f353b5 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-04-01 11:25:33 +01:00
snipe 473ce15f47 Merge pull request #16526 from snipe/develop
Merge #16486  and #16519 into master
2025-03-19 15:31:50 -01:00
snipe eb9cfbaed6 Merge pull request #16498 from snipe/develop
Merge develop into master
2025-03-12 23:23:44 +00:00
snipe faeb037ff9 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2025-03-12 21:26:34 +00:00
snipe 07602f697d Merge remote-tracking branch 'origin/develop' 2025-03-12 18:13:22 +00:00
snipe 11abb0fdb1 Merge remote-tracking branch 'origin/develop' 2025-03-11 22:13:34 +00:00
snipe deeb2fa543 Merge remote-tracking branch 'origin/develop' 2025-03-11 21:14:12 +00:00
snipe ef8d5ff11e Merge remote-tracking branch 'origin/develop' 2025-03-06 12:06:10 +00:00
snipe 91f3e07b83 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-03-05 17:05:28 +00:00
snipe c29bdbdacb Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	public/css/dist/skins/skin-blue.css
#	public/css/dist/skins/skin-blue.min.css
#	public/mix-manifest.json
2025-03-05 13:46:29 +00:00
snipe a20d104d2f Merge remote-tracking branch 'origin/develop' 2025-03-05 11:59:47 +00:00
snipe a61dd8ac17 Merge remote-tracking branch 'origin/develop' 2025-03-05 10:52:42 +00:00
snipe 7ee9a690ea Merge remote-tracking branch 'origin/develop' 2025-03-05 01:12:22 +00:00
snipe 5ba94c6c41 Merge remote-tracking branch 'origin/develop' 2025-03-05 00:12:09 +00:00
snipe 9fa855c837 Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 23:30:45 +00:00
snipe 9251007574 Merge remote-tracking branch 'origin/develop' 2025-03-04 23:29:31 +00:00
snipe cc73b984cb Merge remote-tracking branch 'origin/develop' 2025-03-04 21:13:43 +00:00
snipe 548ef97c32 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-03-04 19:57:33 +00:00
snipe ed8a486726 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:54:08 +00:00
snipe 1ab0911fc8 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:52:16 +00:00
snipe bdbaea7294 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:43:28 +00:00
snipe 5cfd1f6fb2 Merge remote-tracking branch 'origin/develop' 2025-03-04 17:16:26 +00:00
snipe 5eda67381f Merge remote-tracking branch 'origin/develop' 2025-03-04 17:07:13 +00:00
snipe 2c8b8bfaf2 Merge remote-tracking branch 'origin/develop' 2025-03-04 17:05:55 +00:00
snipe 8f3159751a Merge remote-tracking branch 'origin/develop' 2025-03-04 17:01:07 +00:00
snipe 4b05e55b29 Merge remote-tracking branch 'origin/develop' 2025-03-04 15:56:05 +00:00
snipe 3d3c13fcd0 Merge remote-tracking branch 'origin/develop' 2025-03-04 15:38:58 +00:00
snipe 88e1d8a8cf Merge remote-tracking branch 'origin/develop' 2025-03-04 15:28:53 +00:00
snipe e007db34e2 Merge remote-tracking branch 'origin/develop' 2025-03-03 22:12:26 +00:00
snipe f9f06d2c02 Merge remote-tracking branch 'origin/develop' 2025-02-27 19:08:45 +00:00
snipe 234f7d00c8 Merge remote-tracking branch 'origin/develop' 2025-02-27 16:18:18 +00:00
snipe 9924553da5 Merge remote-tracking branch 'origin/develop' 2025-02-27 15:45:57 +00:00
snipe df38d7e3ed Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-02-27 12:22:30 +00:00
snipe 44dd061619 Merge remote-tracking branch 'origin/develop' 2025-02-26 20:55:57 +00:00
snipe 7603a932b1 Merge remote-tracking branch 'origin/develop' 2025-02-26 20:29:42 +00:00
snipe 138e7acc13 Merge remote-tracking branch 'origin/develop' 2025-02-26 12:47:54 +00:00
snipe e863d3e7e5 Merge remote-tracking branch 'origin/develop' 2025-02-26 12:02:00 +00:00
snipe c8e401f5ed Merge remote-tracking branch 'origin/develop' 2025-02-26 11:59:53 +00:00
snipe 3ba20a8e28 Merge remote-tracking branch 'origin/develop' 2025-02-26 11:39:10 +00:00
snipe ebae63752f Merge remote-tracking branch 'origin/develop' 2025-02-26 10:25:18 +00:00
snipe 8bc73901cf Merge remote-tracking branch 'origin/develop' 2025-02-26 08:25:35 +00:00
snipe b4f70d9244 Merge remote-tracking branch 'origin/develop' 2025-02-26 07:16:59 +00:00
snipe 21e9f2bba3 Merge remote-tracking branch 'origin/develop' 2025-02-26 07:11:22 +00:00
snipe 881f4e3d6a Merge remote-tracking branch 'origin/develop' 2025-02-25 14:43:57 +00:00
snipe b141945add Updated branch
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:18:52 +00:00
287 changed files with 2853 additions and 152695 deletions
+1 -2
View File
@@ -3206,8 +3206,7 @@
"avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4",
"profile": "https://github.com/swift2512",
"contributions": [
"bug",
"code"
"bug"
]
},
{
-137
View File
@@ -1,137 +0,0 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
projects: ["grokability/snipe-it"]
type: bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Most issues are documented in the [Snipe-IT repository's issues](https://github.com/grokability/snipe-it/issues) or in the official [Common Issues section of the Documentation](https://snipe-it.readme.io/docs/common-issues#/) and are due to the following:
- `.env` misconfiguration
- [Server Permissions](https://snipe-it.readme.io/docs/debugging-permissions#/)
- [Database Migrations](https://snipe-it.readme.io/docs/database-issues#run-migrations)
Please make sure you've checked these resources before submitting a new issue. If you find an existing issue, please add your context to it instead of opening a new issue. If your issue is more of a question, consider [opening a new discussion](https://github.com/grokability/snipe-it/discussions) or [pop by our Discord](https://discord.gg/yZFtShAcKk) instead of creating an issue.
**Please write your bug report in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary.
**If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.**
- type: input
id: version
attributes:
label: Snipe-IT Version
description: What version of Snipe-IT are you seeing this issue on? You can find the version number in the footer of any page in Snipe-IT.
placeholder: ex. v8.3.1 - build 19577 (master)
validations:
required: true
- type: input
id: db-version
attributes:
label: MySQL/MariaDB version
description: What database are you using, and what version?
placeholder: ex. MySQL 5.7
validations:
required: true
- type: dropdown
id: install-method
attributes:
label: How did you install Snipe-IT?
options:
- Git install
- Manual install (downloading zip/tar.gz)
- Docker
- install.sh
- Hosted by Grokability
- Other
- Not sure
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see! (Be nice!)
validations:
required: true
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Firefox
- Chrome
- Safari
- Microsoft Edge
- Other
- type: dropdown
id: on-demo
attributes:
label: Can you reproduce this on the public demo?
description: You can check this at https://demo.snipeitapp.com.
options:
- 'Yes'
- 'No'
- N/A
validations:
required: true
- type: dropdown
id: fmcs
attributes:
label: Do you have full multiple company support enabled?
description: You can check this in your Snipe-IT installation at `Admin Settings > General Settings > Scoping`.
options:
- 'Yes'
- 'No'
validations:
required: true
- type: dropdown
id: fmcs-location
attributes:
label: If you have full multiple company support enabled, do you have location scoping to company enabled?
description: You can check this in your Snipe-IT installation at `Admin Settings > General Settings > Scoping`.
options:
- 'Yes'
- 'No'
- I do not have full multiple company support enabled
validations:
required: true
- type: textarea
id: server-logs
attributes:
label: Application log output
description: Please copy and paste any relevant log output from `storage/logs/laravel.log`. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: textarea
id: browser-logs
attributes:
label: Browser console output
description: Please copy and paste any relevant log output from your browser console. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: checkboxes
id: common-issues
attributes:
label: Common Issues
description: Please make sure you have done the following before submitting your issue.
options:
- label: I have searched this repo for existing issues related to my issue (including closed issues)
required: true
- label: My APP_URL is set correctly in my .env file (including http or https and no trailing slash)
required: true
- label: I have searched the official Snipe-IT documentation and have checked the Common Issues documentation (where applicable)
required: true
- label: I have run database migrations (where applicable).
required: true
- label: I have attached screenshots and/or videos of the issue (where applicable)
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md).
options:
- label: I agree to follow this project's Code of Conduct
required: true
@@ -1,38 +0,0 @@
name: Feature Request
description: Request a new feature.
title: "[Feature]: "
projects: ["grokability/snipe-it"]
type: feature
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request! Please make sure to search the existing issues in this repository to see if your feature has already been requested, and feel free to add your context to any existing requests.
**Please write your issue in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary.
**If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.**
- type: input
id: version
attributes:
label: Snipe-IT Version
description: What version of Snipe-IT are you currently running? You can find the version number in the footer of any page in Snipe-IT.
placeholder: ex. v8.3.1 - build 19577 (master)
validations:
required: true
- type: textarea
id: feature-description
attributes:
label: How can we help?
description: Let us know in detail what feature you'd like to see added. While we can't promise to implement every feature request, we do read every one and take them into consideration when planning future releases.
placeholder: Tell us what you'd like to see in Snipe-IT! (Be nice!)
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md).
options:
- label: I agree to follow this project's Code of Conduct
required: true
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
issues: write
# pull-requests: write
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
debug-only: true
ascending: true
-12
View File
@@ -76,16 +76,4 @@ jobs:
DB_DATABASE: snipeit
DB_PORT: ${{ job.services.mysql.ports[3306] }}
DB_USERNAME: root
LOG_CHANNEL: single
LOG_LEVEL: debug
run: php artisan test
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
storage/logs/*.log
if-no-files-found: ignore
retention-days: 7
-12
View File
@@ -75,16 +75,4 @@ jobs:
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
DB_USERNAME: snipeit
DB_PASSWORD: password
LOG_CHANNEL: single
LOG_LEVEL: debug
run: php artisan test
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
storage/logs/*.log
if-no-files-found: ignore
retention-days: 7
-12
View File
@@ -61,16 +61,4 @@ jobs:
- name: Execute tests (Unit and Feature tests) via PHPUnit
env:
DB_CONNECTION: sqlite
LOG_CHANNEL: single
LOG_LEVEL: debug
run: php artisan test
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
storage/logs/*.log
if-no-files-found: ignore
retention-days: 7
+1 -1
View File
@@ -52,7 +52,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") | [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") | [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") |
| [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") | [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") [💻](https://github.com/snipe/snipe-it/commits?author=swift2512 "Code") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") |
| [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/18550946?v=4" width="110px;"/><br /><sub>Adugna Gizaw</sub>](https://orbalia.pythonanywhere.com/)<br />[🌍](#translation-addex12 "Translation") | [<img src="https://avatars.githubusercontent.com/u/760989?v=4" width="110px;"/><br /><sub>Jesse Ostrander</sub>](https://github.com/jostrander)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") | [<img src="https://avatars.githubusercontent.com/u/31522486?v=4" width="110px;"/><br /><sub>James M</sub>](https://github.com/azmcnutt)<br />[💻](https://github.com/snipe/snipe-it/commits?author=azmcnutt "Code") | [<img src="https://avatars.githubusercontent.com/u/5183146?v=4" width="110px;"/><br /><sub>Fiala06</sub>](https://github.com/Fiala06)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Fiala06 "Code") | [<img src="https://avatars.githubusercontent.com/u/28693782?v=4" width="110px;"/><br /><sub>Nathan Taylor</sub>](https://github.com/ntaylor-86)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntaylor-86 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/16699443?v=4" width="110px;"/><br /><sub>fvollmer</sub>](https://github.com/fvollmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fvollmer "Code") | [<img src="https://avatars.githubusercontent.com/u/109086466?v=4" width="110px;"/><br /><sub>36864</sub>](https://github.com/36864)<br />[💻](https://github.com/snipe/snipe-it/commits?author=36864 "Code") | [<img src="https://avatars.githubusercontent.com/u/365751?v=4" width="110px;"/><br /><sub>Daniel O'Connor</sub>](http://clockwerx.blogspot.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CloCkWeRX "Code") | [<img src="https://avatars.githubusercontent.com/u/102852568?v=4" width="110px;"/><br /><sub>BeatSpark</sub>](https://github.com/BeatSpark)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BeatSpark "Code") | [<img src="https://avatars.githubusercontent.com/u/59203607?v=4" width="110px;"/><br /><sub>mrdahbi</sub>](https://github.com/mrdahbi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrdahbi "Code") | [<img src="https://avatars.githubusercontent.com/u/6661332?v=4" width="110px;"/><br /><sub>Fabian Schmid</sub>](http://sr.solutions)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chfsx "Code") | [<img src="https://avatars.githubusercontent.com/u/1288116?v=4" width="110px;"/><br /><sub>Chris Olin</sub>](https://www.chrisolin.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=realchrisolin "Code") |
| [<img src="https://avatars.githubusercontent.com/u/3803132?v=4" width="110px;"/><br /><sub>Dan</sub>](https://github.com/mnemonicly)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mnemonicly "Code") | [<img src="https://avatars.githubusercontent.com/u/43917728?v=4" width="110px;"/><br /><sub>Nebel</sub>](https://github.com/NebelKreis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NebelKreis "Code") | [<img src="https://avatars.githubusercontent.com/u/132433803?v=4" width="110px;"/><br /><sub>test1337ahp</sub>](https://github.com/test1337ahp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=test1337ahp "Code") | [<img src="https://avatars.githubusercontent.com/u/1916566?v=4" width="110px;"/><br /><sub>Jonathon Reinhart</sub>](https://github.com/JonathonReinhart)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JonathonReinhart "Code") | [<img src="https://avatars.githubusercontent.com/u/484742?v=4" width="110px;"/><br /><sub>aranar-pro</sub>](https://github.com/aranar-pro)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aranar-pro "Code") | [<img src="https://avatars.githubusercontent.com/u/27019397?v=4" width="110px;"/><br /><sub>Phil</sub>](https://github.com/phil-flip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phil-flip "Code") | [<img src="https://avatars.githubusercontent.com/u/6473460?v=4" width="110px;"/><br /><sub>Steffy Fort</sub>](https://fe80.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fe80 "Code") |
-3
View File
@@ -59,9 +59,6 @@ class PaveIt extends Command
'migrations',
'settings',
'users',
'telescope_entries',
'telescope_entries_tags',
'telescope_monitoring',
];
// We only need to find out what these are so we can nuke these columns on the assets table.
+1 -1
View File
@@ -65,7 +65,7 @@ class Purge extends Command
$maintenances = 0;
foreach ($assets as $asset) {
$this->info('- Asset "'.$asset->display_name.'" deleted.');
$this->info('- Asset "'.$asset->present()->name().'" deleted.');
$asset_assoc += $asset->assetlog()->count();
$asset->assetlog()->forceDelete();
$maintenances += $asset->maintenances()->count();
+3 -20
View File
@@ -2,7 +2,6 @@
namespace App\Console\Commands;
use App\Helpers\Helper;
use App\Mail\ExpiringAssetsMail;
use App\Mail\ExpiringLicenseMail;
use App\Models\Asset;
@@ -53,35 +52,19 @@ class SendExpirationAlerts extends Command
->filter(fn($item) => !empty($item))
->all();
// Expiring Assets
$assets = Asset::getExpiringWarrantyOrEol($alert_interval);
$assets = Asset::getExpiringWarrantee($alert_interval);
if ($assets->count() > 0) {
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval]));
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
$this->table(
['ID', 'Tag', 'Model', 'Model Number', 'EOL', 'EOL Months', 'Warranty Expires', 'Warranty Months'],
$assets->map(fn($item) => ['ID' => $item->id, 'Tag' => $item->asset_tag, 'Model' => $item->model->name, 'Model Number' => $item->model->model_number, 'EOL' => $item->asset_eol_date, 'EOL Months' => $item->model->eol, 'Warranty Expires' => $item->warranty_expires, 'Warranty Months' => $item->warranty_months])
);
}
// Expiring licenses
$licenses = License::getExpiringLicenses($alert_interval);
if ($licenses->count() > 0) {
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval]));
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval));
$this->table(
['ID', 'Name', 'Expires', 'Termination Date'],
$licenses->map(fn($item) => ['ID' => $item->id, 'Name' => $item->name, 'Expires' => $item->expiration_date, 'Termination Date' => $item->termination_date])
);
}
// Send a message even if the count is 0
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval]));
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval]));
} else {
if ($settings->alert_email == '') {
$this->error('Could not send email. No alert email configured in settings');
+3 -31
View File
@@ -95,7 +95,7 @@ class Helper
$Parsedown->setSafeMode(true);
if ($str) {
return $Parsedown->text(strip_tags($str));
return $Parsedown->text($str);
}
}
@@ -105,7 +105,7 @@ class Helper
$Parsedown->setSafeMode(true);
if ($str) {
return $Parsedown->line(strip_tags($str));
return $Parsedown->line($str);
}
}
@@ -435,34 +435,6 @@ class Helper
return $colors[$index];
}
/**
* Check if a string has any RTL characters
* @param $value
* @return bool
*/
public static function hasRtl($string) {
$rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u';
return preg_match($rtlChar, $string) != 0;
}
// is chinese, japanese or korean language
public static function isCjk($string) {
return Helper::isChinese($string) || Helper::isJapanese($string) || Helper::isKorean($string);
}
public static function isChinese($string) {
return preg_match("/\p{Han}+/u", $string);
}
public static function isJapanese($string) {
return preg_match('/[\x{4E00}-\x{9FBF}\x{3040}-\x{309F}\x{30A0}-\x{30FF}]/u', $string);
}
public static function isKorean($string) {
return preg_match('/[\x{3130}-\x{318F}\x{AC00}-\x{D7AF}]/u', $string);
}
/**
* Increases or decreases the brightness of a color by a percentage of the current brightness.
*
@@ -1734,5 +1706,5 @@ class Helper
}
}
return $mismatched;
}
}
}
-1
View File
@@ -16,7 +16,6 @@ class IconHelper
case 'clone':
return 'far fa-clone';
case 'delete':
case 'upload deleted':
return 'fas fa-trash';
case 'create':
return 'fa-solid fa-plus';
@@ -71,7 +71,6 @@ class AccessoryCheckoutController extends Controller
$this->authorize('checkout', $accessory);
$target = $this->determineCheckoutTarget();
session()->put(['checkout_to_type' => $target]);
$accessory->checkout_qty = $request->input('checkout_qty', 1);
@@ -8,23 +8,33 @@ use App\Events\ItemAccepted;
use App\Events\ItemDeclined;
use App\Http\Controllers\Controller;
use App\Mail\CheckoutAcceptanceResponseMail;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\Contracts\Acceptable;
use App\Models\Setting;
use App\Models\User;
use App\Models\AssetModel;
use App\Models\Accessory;
use App\Models\License;
use App\Models\Component;
use App\Models\Consumable;
use App\Notifications\AcceptanceAssetAcceptedNotification;
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
use App\Notifications\AcceptanceAssetDeclinedNotification;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use App\Http\Controllers\SettingsController;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use \Illuminate\Contracts\View\View;
use \Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Log;
use App\Helpers\Helper;
class AcceptanceController extends Controller
{
@@ -75,11 +85,6 @@ class AcceptanceController extends Controller
public function store(Request $request, $id) : RedirectResponse
{
$acceptance = CheckoutAcceptance::find($id);
$assigned_user = User::find($acceptance->assigned_to_id);
$settings = Setting::getSettings();
$path_logo = '';
$sig_filename='';
if (is_null($acceptance)) {
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
@@ -102,75 +107,140 @@ class AcceptanceController extends Controller
}
/**
* Check for the signature directory
* Get the signature and save it
*/
if (! Storage::exists('private_uploads/signatures')) {
Storage::makeDirectory('private_uploads/signatures', 775);
}
/**
* Check for the eula-pdfs directory
*/
if (! Storage::exists('private_uploads/eula-pdfs')) {
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
}
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
// If signatures are required, make sure we have one
if (Setting::getSettings()->require_accept_signature == '1') {
// The item was accepted, check for a signature
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
$data_uri = $request->input('signature_output');
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
// No image data is present, kick them back.
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
} else {
return redirect()->back()->with('error', trans('general.shitty_browser'));
}
}
// Get the data array ready for the notifications and PDF generation
$data = [
'item_tag' => $item->asset_tag,
'item_name' => $item->name, // this handles licenses seats, which don't have a 'name' field
'item_model' => $item->model?->name,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
'eula' => $item->getEula(),
'note' => $request->input('note'),
'check_out_date' => Helper::getFormattedDateObject($acceptance->created_at, 'datetime', false),
'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
'assigned_to' => $assigned_user->display_name,
'site_name' => $settings->site_name,
'company_name' => $item->company?->name?? $settings->site_name,
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
'logo' => ($settings->acceptance_pdf_logo) ? public_path() . '/uploads/' . $settings->acceptance_pdf_logo : null,
'date_settings' => $settings->date_display_format,
'admin' => auth()->user()->present()?->fullName,
'qty' => $acceptance->qty ?? 1,
];
$display_model = '';
$pdf_view_route = '';
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
$sig_filename='';
if ($request->input('asset_acceptance') == 'accepted') {
/**
* Check for the eula-pdfs directory
*/
if (! Storage::exists('private_uploads/eula-pdfs')) {
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
}
$pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$acceptance->display_checkoutable_type.'-eula-'.date('Y-m-d-h-i-s').'.pdf';
if (Setting::getSettings()->require_accept_signature == '1') {
// Check if the signature directory exists, if not create it
if (!Storage::exists('private_uploads/signatures')) {
Storage::makeDirectory('private_uploads/signatures', 775);
}
// Generate the PDF content
$pdf_content = $acceptance->generateAcceptancePdf($data, $acceptance);
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content);
// The item was accepted, check for a signature
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
$data_uri = $request->input('signature_output');
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
// No image data is present, kick them back.
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
} else {
return redirect()->back()->with('error', trans('general.shitty_browser'));
}
}
$assigned_user = User::find($acceptance->assigned_to_id);
// this is horrible
switch($acceptance->checkoutable_type){
case 'App\Models\Asset':
$pdf_view_route ='account.accept.accept-asset-eula';
$asset_model = AssetModel::find($item->model_id);
if (!$asset_model) {
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
}
$display_model = $asset_model->name;
break;
case 'App\Models\Accessory':
$pdf_view_route ='account.accept.accept-accessory-eula';
$accessory = Accessory::find($item->id);
$display_model = $accessory->name;
break;
case 'App\Models\LicenseSeat':
$pdf_view_route ='account.accept.accept-license-eula';
$license = License::find($item->license_id);
$display_model = $license->name;
break;
case 'App\Models\Component':
$pdf_view_route ='account.accept.accept-component-eula';
$component = Component::find($item->id);
$display_model = $component->name;
break;
case 'App\Models\Consumable':
$pdf_view_route ='account.accept.accept-consumable-eula';
$consumable = Consumable::find($item->id);
$display_model = $consumable->name;
break;
}
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
// $pdf_view_route ='account.accept.accept-asset-eula';
// $asset_model = AssetModel::find($item->model_id);
// $display_model = $asset_model->name;
// $assigned_to = User::find($item->assigned_to)->present()->fullName;
//
// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
// $pdf_view_route ='account.accept.accept-accessory-eula';
// $accessory = Accessory::find($item->id);
// $display_model = $accessory->name;
// $assigned_to = User::find($item->assignedTo);
//
// }
/**
* Gather the data for the PDF. We fire this whether there is a signature required or not,
* since we want the moment-in-time proof of what the EULA was when they accepted it.
*/
$branding_settings = SettingsController::getPDFBranding();
$path_logo = "";
// Check for the PDF logo path and use that, otherwise use the regular logo path
if (!is_null($branding_settings->acceptance_pdf_logo)) {
$path_logo = public_path() . '/uploads/' . $branding_settings->acceptance_pdf_logo;
} elseif (!is_null($branding_settings->logo)) {
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
}
$data = [
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
'eula' => $item->getEula(),
'note' => $request->input('note'),
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
'assigned_to' => $assigned_user->present()->fullName,
'company_name' => $branding_settings->site_name,
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
'logo' => $path_logo,
'date_settings' => $branding_settings->date_display_format,
'admin' => auth()->user()->present()?->fullName,
];
if ($pdf_view_route!='') {
Log::debug($pdf_filename.' is the filename, and the route was specified.');
$pdf = Pdf::loadView($pdf_view_route, $data);
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
}
// Log the acceptance
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
// Send the PDF to the signing user
@@ -178,8 +248,9 @@ class AcceptanceController extends Controller
// Add the attachment for the signing user into the $data array
$data['file'] = $pdf_filename;
$locale = $assigned_user->locale;
try {
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale));
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($locale));
} catch (\Exception $e) {
Log::warning($e);
}
@@ -193,21 +264,95 @@ class AcceptanceController extends Controller
$return_msg = trans('admin/users/message.accepted');
// Item was declined
} else {
for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) {
$acceptance->decline($sig_filename, $request->input('note'));
/**
* Check for the eula-pdfs directory
*/
if (! Storage::exists('private_uploads/eula-pdfs')) {
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
}
if (Setting::getSettings()->require_accept_signature == '1') {
// Check if the signature directory exists, if not create it
if (!Storage::exists('private_uploads/signatures')) {
Storage::makeDirectory('private_uploads/signatures', 775);
}
// The item was accepted, check for a signature
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
$data_uri = $request->input('signature_output');
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
// No image data is present, kick them back.
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
} else {
return redirect()->back()->with('error', trans('general.shitty_browser'));
}
}
// Format the data to send the declined notification
$branding_settings = SettingsController::getPDFBranding();
// This is the most horriblest
switch($acceptance->checkoutable_type){
case 'App\Models\Asset':
$asset_model = AssetModel::find($item->model_id);
$display_model = $asset_model->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Accessory':
$accessory = Accessory::find($item->id);
$display_model = $accessory->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\LicenseSeat':
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Component':
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Consumable':
$consumable = Consumable::find($item->id);
$display_model = $consumable->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
}
$data = [
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
'note' => $request->input('note'),
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'date_settings' => $branding_settings->date_display_format,
];
if ($pdf_view_route!='') {
Log::debug($pdf_filename.' is the filename, and the route was specified.');
$pdf = Pdf::loadView($pdf_view_route, $data);
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
}
$acceptance->decline($sig_filename, $request->input('note'));
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
Log::debug('New event acceptance.');
event(new CheckoutDeclined($acceptance));
$return_msg = trans('admin/users/message.declined');
}
// Send an email notification if one is requested
if ($acceptance->alert_on_response_id) {
try {
$recipient = User::find($acceptance->alert_on_response_id);
@@ -226,10 +371,9 @@ class AcceptanceController extends Controller
Log::warning($e);
}
}
return redirect()->to('account/accept')->with('success', $return_msg);
}
}
+10 -24
View File
@@ -3,13 +3,11 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use \Illuminate\Http\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class ActionlogController extends Controller
{
public function displaySig($filename) : RedirectResponse | Response | bool
@@ -41,29 +39,17 @@ class ActionlogController extends Controller
public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse
{
$this->authorize('view', \App\Models\Asset::class);
if ($actionlog = Actionlog::where('filename', $filename)->with('user')->with('target')->firstOrFail()) {
$this->authorize('view', $actionlog->target);
$this->authorize('view', $actionlog->user);
if (config('filesystems.default') == 's3_private') {
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/' . $filename, now()->addMinutes(5)));
}
if (Storage::exists('private_uploads/eula-pdfs/' . $filename)) {
if (request()->input('inline') == 'true') {
return response()->file(config('app.private_uploads') . '/eula-pdfs/' . $filename);
}
return response()->download(config('app.private_uploads') . '/eula-pdfs/' . $filename);
}
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
if (config('filesystems.default') == 's3_private') {
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/'.$filename, now()->addMinutes(5)));
}
return redirect()->back()->with('error', trans('general.record_not_found'));
if (Storage::exists('private_uploads/eula-pdfs/'.$filename)) {
return response()->download(config('app.private_uploads').'/eula-pdfs/'.$filename);
}
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
}
}
@@ -288,42 +288,32 @@ class AccessoriesController extends Controller
'note' => $request->input('note'),
]);
$accessory_checkout->created_by = auth()->id();
$accessory_checkout->save();
$payload = [
'accessory_id' => $accessory->id,
'assigned_to' => $target->id,
'assigned_type' => $target::class,
'note' => $request->input('note'),
'created_by' => auth()->id(),
'pivot' => $accessory_checkout->id,
];
}
// Set this value to be able to pass the qty through to the event
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkout.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
}
/**
* Check in the item so that it can be checked out again to someone else
*
* @uses Accessory::checkin_email() to determine if an email can and should be sent
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param int $accessoryUserId
* @param string $backto
* @return JsonResponse
* @uses Accessory::checkin_email() to determine if an email can and should be sent
* @author [A. Gianotto] [<snipe@snipe.net>]
* @return \Illuminate\Http\RedirectResponse
* @internal param int $accessoryId
*/
public function checkin(Request $request, $accessoryUserId = null)
{
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist', ['id' => $accessoryUserId])));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
}
$accessory = Accessory::find($accessory_checkout->accessory_id);
@@ -337,14 +327,7 @@ class AccessoriesController extends Controller
$user = User::find($accessory_checkout->assigned_to);
}
$payload = [
'accessory_id' => $accessory->id,
'note' => $request->input('note'),
'created_by' => auth()->id(),
'pivot' => $accessory_checkout->id,
];
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkin.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
@@ -50,7 +50,6 @@ class AssetModelsController extends Controller
'fieldset',
'deleted_at',
'updated_at',
'require_serial',
];
$assetmodels = AssetModel::select([
@@ -70,7 +69,6 @@ class AssetModelsController extends Controller
'models.fieldset_id',
'models.deleted_at',
'models.updated_at',
'models.require_serial'
])
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
->withCount('assets as assets_count');
+2 -12
View File
@@ -1290,19 +1290,9 @@ class AssetsController extends Controller
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
{
$this->authorize('view', Asset::class);
$this->authorize('view', $asset);
$query = Asset::where([
'assigned_to' => $asset->id,
'assigned_type' => Asset::class,
]);
$total = $query->count();
$assets = $query->applyOffsetAndLimit($total)->get();
return (new AssetsTransformer)->transformAssets($assets, $total);
return [];
// to do
}
public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array
@@ -38,8 +38,6 @@ class CategoriesController extends Controller
'consumables_count',
'components_count',
'licenses_count',
'created_at',
'updated_at',
'image',
'notes',
];
@@ -69,7 +69,7 @@ class ImportController extends Controller
if (function_exists('iconv')) {
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
$encoding = $detector->getEncoding($file_contents);
\Log::debug("Discovered encoding: $encoding in uploaded CSV");
\Log::warning("Discovered encoding: $encoding in uploaded CSV");
$reader = null;
if (strcasecmp($encoding, 'UTF-8') != 0) {
$transliterated = false;
@@ -103,7 +103,7 @@ class ImportController extends Controller
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
try {
$import->header_row = $reader->nth(0);
$import->header_row = $reader->fetchOne(0);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
@@ -136,7 +136,7 @@ class ImportController extends Controller
try {
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->nth(1);
$import->first_row = $reader->fetchOne(1);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
@@ -128,9 +128,7 @@ class LicenseSeatsController extends Controller
// nothing to update
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
if( $touched && $licenseSeat->unreassignable_seat) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.unavailable')));
}
// the logging functions expect only one "target". if both asset and user are present in the request,
// we simply let assets take precedence over users...
if ($licenseSeat->isDirty('assigned_to')) {
@@ -147,11 +145,7 @@ class LicenseSeatsController extends Controller
if ($licenseSeat->save()) {
if ($is_checkin) {
if(!$licenseSeat->license->reassignable){
$licenseSeat->unreassignable_seat = true;
$licenseSeat->save();
}
$licenseSeat->logCheckin($target, $licenseSeat->notes);
$licenseSeat->logCheckin($target, $request->input('notes'));
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
@@ -26,12 +26,6 @@ class LicensesController extends Controller
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
if ($request->input('status')=='inactive') {
$licenses->ExpiredLicenses();
} else {
$licenses->ActiveLicenses();
}
if ($request->filled('company_id')) {
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
}
@@ -100,8 +94,6 @@ class LicensesController extends Controller
$licenses->onlyTrashed();
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -37,14 +37,10 @@ class LocationsController extends Controller
'address',
'address2',
'assets_count',
'assigned_assets_count',
'rtd_assets_count',
'accessories_count',
'assets_count',
'assigned_accessories_count',
'components_count',
'consumables_count',
'users_count',
'children_count',
'assigned_assets_count',
'assigned_assets_count',
'city',
'country',
'created_at',
@@ -58,6 +54,7 @@ class LocationsController extends Controller
'rtd_assets_count',
'state',
'updated_at',
'users_count',
'zip',
'notes',
];
@@ -82,9 +79,8 @@ class LocationsController extends Controller
'locations.currency',
'locations.company_id',
'locations.notes',
'locations.created_by',
'locations.deleted_at',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
@@ -92,8 +88,6 @@ class LocationsController extends Controller
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')
->with('adminuser');
// Only scope locations if the setting is enabled
@@ -137,14 +131,6 @@ class LocationsController extends Controller
$locations->where('locations.company_id', '=', $request->input('company_id'));
}
if ($request->filled('parent_id')) {
$locations->where('locations.parent_id', '=', $request->input('parent_id'));
}
if ($request->input('status') == 'deleted') {
$locations->onlyTrashed();
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -238,13 +224,8 @@ class LocationsController extends Controller
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')
->findOrFail($id);
return (new LocationsTransformer)->transformLocation($location);
@@ -339,15 +320,11 @@ class LocationsController extends Controller
{
$this->authorize('delete', Location::class);
$location = Location::withCount('assignedAssets as assigned_assets_count')
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')
->withCount('accessories as accessories_count')
->findOrFail($id);
if (! $location->isDeletable()) {
@@ -69,7 +69,7 @@ class ProfileController extends Controller
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
$assets = [
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
'name' => e($checkoutRequest->itemRequested()->display_name),
'name' => e($checkoutRequest->itemRequested()->present()->name()),
'type' => e($checkoutRequest->itemType()),
'qty' => (int) $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
@@ -32,7 +32,7 @@ class UploadedFilesController extends Controller
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
@@ -51,7 +51,11 @@ class UploadedFilesController extends Controller
];
$uploads = self::$map_object_type[$object_type]::withTrashed()->find($id)->uploads()
$uploads = Actionlog::select('action_logs.*')
->whereNotNull('filename')
->where('item_type', self::$map_object_type[$object_type])
->where('item_id', $object->id)
->where('action_type', '=', 'uploaded')
->with('adminuser');
$offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset'));
@@ -92,7 +96,7 @@ class UploadedFilesController extends Controller
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
@@ -140,7 +144,7 @@ class UploadedFilesController extends Controller
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
@@ -184,7 +188,7 @@ class UploadedFilesController extends Controller
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('update', self::$map_object_type[$object_type]);
if (!$object) {
@@ -202,7 +206,7 @@ class UploadedFilesController extends Controller
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
}
// Delete the record of the file
if ($log->logUploadDelete($object, $log->filename)) {
if ($log->delete()) {
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
}
+2 -2
View File
@@ -435,7 +435,7 @@ class UsersController extends Controller
$user->password = $user->noPassword();
}
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
@@ -560,7 +560,7 @@ 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, 'avatar', 'avatars', 'avatar');
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
// Check if the request has groups passed and has a value, AND that the user us a superuser
@@ -82,7 +82,6 @@ class AssetModelsController extends Controller
$model->notes = $request->input('notes');
$model->created_by = auth()->id();
$model->requestable = $request->has('requestable');
$model->require_serial = $request->input('require_serial', 0);
if ($request->input('fieldset_id') != '') {
$model->fieldset_id = $request->input('fieldset_id');
@@ -156,7 +155,7 @@ class AssetModelsController extends Controller
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->requestable = $request->input('requestable', '0');
$model->require_serial = $request->input('require_serial', 0);
$model->fieldset_id = $request->input('fieldset_id');
if ($model->save()) {
@@ -65,8 +65,6 @@ class AssetCheckoutController extends Controller
*/
public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse
{
try {
// Check if the asset exists
if (! $asset = Asset::find($assetId)) {
@@ -83,7 +81,6 @@ class AssetCheckoutController extends Controller
$admin = auth()->user();
$target = $this->determineCheckoutTarget();
session()->put(['checkout_to_type' => $target]);
$asset = $this->updateAssetLocation($asset, $target);
@@ -110,35 +110,17 @@ class AssetsController extends Controller
// This is only necessary on create, not update, since bulk editing is handled
// differently
$asset_tags = $request->input('asset_tags');
$model = AssetModel::find($request->input('model_id'));
$serial_errors = [];
$serials = $request->input('serials');
$settings = Setting::getSettings();
//Validate required serial based on model setting
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
if ($model && $model->require_serial === 1 && empty($serials[$a])) {
$serial_errors["serials.$a"] = trans('admin/hardware/form.serial_required', ['number' => $a]);
}
}
if (!empty($serial_errors)) {
return redirect()->back()
->withInput()
->withErrors($serial_errors);
}
$asset = null;
$companyId = Company::getIdForCurrentUser($request->input('company_id'));
$successes = [];
$failures = [];
$serials = $request->input('serials');
$asset = null;
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
for ($a = 1; $a <= count($asset_tags); $a++) {
$asset = new Asset();
$asset->model()->associate($model);
$asset->model()->associate(AssetModel::find($request->input('model_id')));
$asset->name = $request->input('name');
// Check for a corresponding serial
@@ -150,7 +132,7 @@ class AssetsController extends Controller
$asset->asset_tag = $asset_tags[$a];
}
$asset->company_id = $companyId;
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->notes = $request->input('notes');
@@ -190,6 +172,7 @@ class AssetsController extends Controller
// Update custom fields in the database.
// Validation for these fields is handled through the AssetRequest form request
$model = AssetModel::find($request->get('model_id'));
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
@@ -470,13 +453,6 @@ class AssetsController extends Controller
]);
//Validate required serial based on model setting
if ($model && $model->require_serial === 1 && empty($serial[1])) {
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('warning', trans('admin/hardware/form.serial_required_post_model_update', [
'asset_model' => $model->name
]));
}
if ($asset->save()) {
return Helper::getRedirectOption($request, $asset->id, 'Assets')
->with('success', trans('admin/hardware/message.update.success'));
@@ -637,7 +637,6 @@ class BulkAssetsController extends Controller
$admin = auth()->user();
$target = $this->determineCheckoutTarget();
session()->put(['checkout_to_type' => $target]);
if (! is_array($request->get('selected_assets'))) {
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
@@ -647,15 +646,6 @@ class BulkAssetsController extends Controller
$assets = Asset::findOrFail($asset_ids);
// Prevent checking out assets that are already checked out
if ($assets->pluck('assigned_to')->unique()->filter()->isNotEmpty()) {
// re-add the asset ids so the assets select is re-populated
$request->session()->flashInput(['selected_assets' => $asset_ids]);
return redirect(route('hardware.bulkcheckout.show'))
->with('error', trans('general.error_assets_already_checked_out'));
}
if (request('checkout_to_type') == 'asset') {
foreach ($asset_ids as $asset_id) {
if ($target->id == $asset_id) {
@@ -92,9 +92,7 @@ class BulkAssetModelsController extends Controller
$update_array['min_amt'] = $request->input('min_amt');
}
if ($request->filled('require_serial')) {
$update_array['require_serial'] = $request->input('require_serial');
}
if (count($update_array) > 0) {
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
@@ -102,15 +102,13 @@ class ComponentCheckoutController extends Controller
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
}
$component->checkout_qty = $request->input('assigned_qty');
// Update the component data
$component->asset_id = $request->input('asset_id');
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'created_by' => auth()->user()->id,
'created_at' => date('Y-m-d H:i:s'),
'assigned_qty' => $component->checkout_qty,
'assigned_qty' => $request->input('assigned_qty'),
'asset_id' => $request->input('asset_id'),
'note' => $request->input('note'),
]);
@@ -64,7 +64,12 @@ class LicenseCheckinController extends Controller
$this->authorize('checkout', $license);
if (! $license->reassignable) {
// Not allowed to checkin
Session::flash('error', trans('admin/licenses/message.checkin.not_reassignable') . '.');
return redirect()->back()->withInput();
}
// Declare the rules for the form validation
$rules = [
@@ -93,9 +98,6 @@ class LicenseCheckinController extends Controller
$licenseSeat->assigned_to = null;
$licenseSeat->asset_id = null;
$licenseSeat->notes = $request->input('notes');
if (! $licenseSeat->license->reassignable) {
$licenseSeat->unreassignable_seat = true;
}
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($request->get('redirect_option') === 'target'){
@@ -104,7 +106,7 @@ class LicenseCheckinController extends Controller
// Was the asset updated?
if ($licenseSeat->save()) {
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes));
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
return Helper::getRedirectOption($request, $license->id, 'Licenses')
@@ -130,17 +132,21 @@ class LicenseCheckinController extends Controller
$license = License::findOrFail($licenseId);
$this->authorize('checkin', $license);
if (! $license->reassignable) {
// Not allowed to checkin
Session::flash('error', 'License not reassignable.');
return redirect()->back()->withInput();
}
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
->whereNotNull('assigned_to')
->with('user', 'license')
->with('user')
->get();
$license = $licenseSeatsByUser->first()?->license;
foreach ($licenseSeatsByUser as $user_seat) {
$user_seat->assigned_to = null;
if ($license && ! $license->reassignable) {
$user_seat->unreassignable_seat = true;
}
if ($user_seat->save()) {
Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
@@ -153,12 +159,9 @@ class LicenseCheckinController extends Controller
->get();
$count = 0;
$license = $licenseSeatsByAsset->first()?->license;
foreach ($licenseSeatsByAsset as $asset_seat) {
$asset_seat->asset_id = null;
if ($license && ! $license->reassignable) {
$asset_seat->unreassignable_seat = true;
}
if ($asset_seat->save()) {
Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
@@ -25,7 +25,7 @@ class LicenseCheckoutController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param $id
* @return \Illuminate\Contracts\View\View |\Illuminate\Http\RedirectResponse
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(License $license)
@@ -39,16 +39,6 @@ class LicenseCheckoutController extends Controller
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}
// Make sure the license is expired or terminated
if ($license->isInactive()) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
}
// We don't currently allow checking out licenses to locations, so we'll reset that to user if needed
if (session()->get('checkout_to_type') == 'location') {
session()->put(['checkout_to_type' => 'user']);
}
// Return the checkout view
return view('licenses/checkout', compact('license'));
}
@@ -75,31 +65,22 @@ class LicenseCheckoutController extends Controller
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}
$this->authorize('checkout', $license);
// Make sure there is at least one available to checkout
if ($license->availCount()->count() < 1) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}
// Make sure the license is expired or terminated
if ($license->isInactive()) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
}
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
$licenseSeat->created_by = auth()->id();
$licenseSeat->notes = $request->input('notes');
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
if ($request->filled('asset_id')) {
session()->put(['checkout_to_type' => 'asset']);
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
} elseif ($request->filled('assigned_to')) {
session()->put(['checkout_to_type' => 'user']);
$checkoutTarget = $this->checkoutToUser($licenseSeat);
$request->request->add(['assigned_user' => $checkoutTarget->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
@@ -108,7 +89,6 @@ class LicenseCheckoutController extends Controller
if ($checkoutTarget) {
return Helper::getRedirectOption($request, $license->id, 'Licenses')
->with('success', trans('admin/licenses/message.checkout.success'));
}
@@ -130,7 +110,6 @@ class LicenseCheckoutController extends Controller
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
}
if (! $licenseSeat->license->is($license)) {
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
}
@@ -245,28 +245,16 @@ class LicensesController extends Controller
$license = License::with('assignedusers')->find($license->id);
$users_count = User::where('autoassign_licenses', '1')->count();
$total_seats_count = (int) $license->totalSeatsByLicenseID();
$total_seats_count = $license->totalSeatsByLicenseID();
$available_seats_count = $license->availCount()->count();
$unreassignable_seats_count = License::unReassignableCount($license);
if(!$license->reassignable){
$checkedout_seats_count = ($total_seats_count - $available_seats_count - $unreassignable_seats_count );
}
else {
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
}
if($license->isInactive()){
session()->flash('warning', (trans('admin/licenses/message.checkout.license_is_inactive')));
}
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
$this->authorize('view', $license);
return view('licenses.view', compact('license'))
->with('users_count', $users_count)
->with('total_seats_count', $total_seats_count)
->with('available_seats_count', $available_seats_count)
->with('checkedout_seats_count', $checkedout_seats_count)
->with('unreassignable_seats_count', $unreassignable_seats_count);
->with('checkedout_seats_count', $checkedout_seats_count);
}
+50 -61
View File
@@ -189,36 +189,30 @@ class LocationsController extends Controller
{
$this->authorize('delete', Location::class);
$location = Location::withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')
->find($locationId);
if (!$location) {
if (is_null($location = Location::find($locationId))) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
}
if ($location->isDeletable()) {
if ($location->image) {
try {
Storage::disk('public')->delete('locations/'.$location->image);
} catch (\Exception $e) {
Log::error($e);
}
}
$location->delete();
return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success'));
} else {
if ($location->users()->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users'));
} elseif ($location->children()->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_child_loc'));
} elseif ($location->assets()->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
} elseif ($location->assignedassets()->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
}
if ($location->image) {
try {
Storage::disk('public')->delete('locations/'.$location->image);
} catch (\Exception $e) {
Log::error($e);
}
}
$location->delete();
return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success'));
}
/**
@@ -253,41 +247,23 @@ class LocationsController extends Controller
$this->authorize('view', Location::class);
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$company = Company::where('id', $location->company_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
return view('locations/print')
->with('assigned', false)
->with('assets', $location->assets)
->with('assignedAssets', $location->assignedAssets)
->with('accessories', $location->accessories)
->with('assignedAccessories', $location->assignedAccessories)
->with('users',$location->users)
->with('assets', $assets)
->with('users',$users)
->with('location', $location)
->with('consumables', $location->consumables)
->with('components', $location->components)
->with('children', $location->children);
->with('parent', $parent)
->with('manager', $manager)
->with('company', $company);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
public function print_all_assigned($id) : View | RedirectResponse
{
$this->authorize('view', Location::class);
if ($location = Location::where('id', $id)->first()) {
return view('locations/print')
->with('assigned', true)
->with('assets', $location->assets)
->with('assignedAssets', $location->assignedAssets)
->with('accessories', $location->accessories)
->with('assignedAccessories', $location->assignedAccessories)
->with('users',$location->users)
->with('location', $location)
->with('consumables', $location->consumables)
->with('components', $location->components)
->with('children', $location->children);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
/**
* Returns a view that presents a form to clone a location.
@@ -345,12 +321,33 @@ class LocationsController extends Controller
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
}
// Check validation
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
}
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
}
public function print_all_assigned($id) : View | RedirectResponse
{
$this->authorize('view', Location::class);
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$company = Company::where('id', $location->company_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
return view('locations/print')
->with('assets', $assets)
->with('users',$users)
->with('location', $location)
->with('parent', $parent)
->with('manager', $manager)
->with('company', $company);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
/**
* Returns a view that allows the user to bulk delete locations
@@ -369,12 +366,8 @@ class LocationsController extends Controller
$locations = Location::whereIn('id', $locations_raw_array)
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')
->withCount('users as users_count')->get();
$valid_count = 0;
@@ -407,13 +400,9 @@ class LocationsController extends Controller
$locations = Location::whereIn('id', $locations_raw_array)
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('consumables as consumables_count')
->withCount('components as components_count')->get();
->withCount('users as users_count')->get();
$success_count = 0;
$error_count = 0;
+15 -11
View File
@@ -159,7 +159,7 @@ class ReportsController extends Controller
$row[] = e($asset->serial);
if ($target = $asset->assignedTo) {
$row[] = e($target->display_name);
$row[] = e($target->present()->name());
} else {
$row[] = ''; // Empty string if unassigned
}
@@ -274,18 +274,22 @@ class ReportsController extends Controller
$target_name = '';
if ($actionlog->target) {
$target_name = $actionlog->target->display_name;
if ($actionlog->targetType() == 'user') {
$target_name = $actionlog->target->display_name;
} else {
$target_name = $actionlog->target->getDisplayNameAttribute();
}
}
if ($actionlog->item){
$item_name = e($actionlog->item->display_name);
if($actionlog->item){
$item_name = e($actionlog->item->getDisplayNameAttribute());
} else {
$item_name = '';
}
$row = [
$actionlog->created_at,
($actionlog->adminuser) ? $actionlog->adminuser->display_name : '',
($actionlog->adminuser) ? e($actionlog->adminuser->display_name) : '',
$actionlog->present()->actionType(),
e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
@@ -294,10 +298,10 @@ class ReportsController extends Controller
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
$target_name,
($actionlog->note) ? e($actionlog->note) : '',
$actionlog->log_meta,
$actionlog->remote_ip,
$actionlog->user_agent,
$actionlog->action_source,
$actionlog->log_meta,
];
fputcsv($handle, $row);
}
@@ -826,7 +830,7 @@ class ReportsController extends Controller
}
if ($request->filled('location')) {
$row[] = ($asset->location) ? $asset->location->display_name : '';
$row[] = ($asset->location) ? $asset->location->present()->name() : '';
}
if ($request->filled('location_address')) {
@@ -839,7 +843,7 @@ class ReportsController extends Controller
}
if ($request->filled('rtd_location')) {
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->display_name : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->present()->name() : '';
}
if ($request->filled('rtd_location_address')) {
@@ -852,8 +856,8 @@ class ReportsController extends Controller
}
if ($request->filled('assigned_to')) {
$row[] = ($asset->assigned) ? $asset->assigned->display_name : '';
$row[] = ($asset->assigned) ? $asset->assignedType() : '';
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ?? $asset->assigned->display_name;
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ? 'user' : $asset->assignedType();
}
if ($request->filled('username')) {
@@ -1256,7 +1260,7 @@ class ReportsController extends Controller
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
$row[] = str_replace(',', '', e($item['assetItem']->name));
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user')));
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
$rows[] = implode(',', $row);
}
}
@@ -36,7 +36,7 @@ class UploadedFilesController extends Controller
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('update', $object);
if (!$object) {
@@ -85,7 +85,7 @@ class UploadedFilesController extends Controller
public function show($object_type, $id, $file_id) : RedirectResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('view', $object);
if (!$object) {
@@ -130,7 +130,7 @@ class UploadedFilesController extends Controller
{
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$object = self::$map_object_type[$object_type]::find($id);
$this->authorize('update', self::$map_object_type[$object_type]);
if (!$object) {
@@ -139,7 +139,7 @@ class UploadedFilesController extends Controller
// Check for the file
$log = Actionlog::where('id',$file_id)->where('item_type', self::$map_object_type[$object_type])
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
->where('item_id', $object->id)->first();
if ($log) {
@@ -148,7 +148,7 @@ class UploadedFilesController extends Controller
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
}
// Delete the record of the file
if ($log->logUploadDelete($object, $log->filename)) {
if ($log->delete()) {
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1));
}
+4 -1
View File
@@ -34,7 +34,10 @@ class AssetCountForSidebar
}
try {
$total_assets = Asset::AssetsForShow()->count();
$total_assets = Asset::count();
if ($settings->show_archived_in_list != '1') {
$total_assets -= Asset::Archived()->count();
}
view()->share('total_assets', $total_assets);
} catch (\Exception $e) {
Log::debug($e);
@@ -36,7 +36,6 @@ class AccessoriesTransformer
'qty' => ($accessory->qty) ? (int) $accessory->qty : null,
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'total_cost' => Helper::formatCurrencyOutput($accessory->totalCostSum()),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, // Legacy - should phase out - replaced by below, for the bootstrap table formatter
'min_amt' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
@@ -50,20 +50,17 @@ class ActionlogsTransformer
public function transformActionlog (Actionlog $actionlog, $settings = null)
{
$icon = $actionlog->present()->icon();
if (($actionlog->filename!='') && ($actionlog->action_type!='upload deleted')) {
$icon = Helper::filetype_icon($actionlog->filename);
}
static $custom_fields = false;
if ($custom_fields === false) {
$custom_fields = CustomField::all();
}
if ($actionlog->filename!='') {
$icon = Helper::filetype_icon($actionlog->filename);
}
// This is necessary since we can't escape special characters within a JSON object
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
@@ -147,7 +144,7 @@ class ActionlogsTransformer
[
'url' => $actionlog->uploads_file_url(),
'filename' => $actionlog->filename,
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_path()),
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_url()),
'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false,
] : null,
@@ -155,7 +152,7 @@ class ActionlogsTransformer
'id' => (int) $actionlog->item->id,
'name' => e($actionlog->item->display_name) ?? null,
'type' => e($actionlog->itemType()),
'serial' => e($actionlog->item->serial) ? e($actionlog->item->serial) : null
'serial' =>e($actionlog->item->serial) ? e($actionlog->item->serial) : null
] : null,
'location' => ($actionlog->location) ? [
'id' => (int) $actionlog->location->id,
@@ -168,7 +165,7 @@ class ActionlogsTransformer
'action_type' => $actionlog->present()->actionType(),
'admin' => ($actionlog->adminuser) ? [
'id' => (int) $actionlog->adminuser->id,
'name' => e($actionlog->adminuser->display_name) ?? null,
'name' => e($actionlog->adminuser->display_name),
'first_name'=> e($actionlog->adminuser->first_name),
'last_name'=> e($actionlog->adminuser->last_name)
] : null,
@@ -180,7 +177,7 @@ class ActionlogsTransformer
] : null,
'target' => ($actionlog->target) ? [
'id' => (int) $actionlog->target->id,
'name' => e($actionlog->target->display_name) ?? null,
'name' => ($actionlog->target->display_name) ?? null,
'type' => e($actionlog->targetType()),
] : null,
@@ -65,7 +65,6 @@ class AssetModelsTransformer
'default_fieldset_values' => $default_field_values,
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
'requestable' => ($assetmodel->requestable == '1') ? true : false,
'require_serial' => $assetmodel->require_serial,
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
'created_by' => ($assetmodel->adminuser) ? [
'id' => (int) $assetmodel->adminuser->id,
@@ -43,7 +43,6 @@ class ComponentsTransformer
'order_number' => e($component->order_number),
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost),
'total_cost' => Helper::formatCurrencyOutput($component->totalCostSum()),
'remaining' => (int) $component->numRemaining(),
'company' => ($component->company) ? [
'id' => (int) $component->company->id,
@@ -77,7 +76,7 @@ class ComponentsTransformer
$array[] = [
'assigned_pivot_id' => $asset->pivot->id,
'id' => (int) $asset->id,
'name' => e($asset->model->display_name).' '.e($asset->display_name),
'name' => e($asset->model->present()->name).' '.e($asset->present()->name),
'qty' => $asset->pivot->assigned_qty,
'note' => $asset->pivot->note,
'type' => 'asset',
@@ -37,7 +37,6 @@ class ConsumablesTransformer
'remaining' => $consumable->numRemaining(),
'order_number' => e($consumable->order_number),
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
'total_cost' => Helper::formatCurrencyOutput($consumable->totalCostSum()),
'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'),
'qty' => (int) $consumable->qty,
'notes' => ($consumable->notes) ? Helper::parseEscapedMarkedownInline($consumable->notes) : null,
@@ -7,6 +7,7 @@ use App\Models\License;
use App\Models\LicenseSeat;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
class LicenseSeatsTransformer
{
public function transformLicenseSeats(Collection $seats, $total)
@@ -51,7 +52,6 @@ class LicenseSeatsTransformer
'reassignable' => (bool) $seat->license->reassignable,
'notes' => e($seat->notes),
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
'disabled' => $seat->unreassignable_seat || $seat->license->isInactive(),
];
$permissions_array['available_actions'] = [
@@ -31,13 +31,13 @@ class LicensesTransformer
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
'purchase_cost_numeric' => $license->purchase_cost,
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'seats' => (int) $license->seats,
'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license),
'free_seats_count' => (int) $license->free_seats_count,
'remaining' => (int) $license->free_seats_count,
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
'license_name' => ($license->license_name) ? e($license->license_name) : null,
@@ -54,7 +54,7 @@ class LicensesTransformer
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
'user_can_checkout' => (bool) ($license->free_seats_count > 0),
'disabled' => $license->isInactive(),
];
$permissions_array['available_actions'] = [
@@ -53,9 +53,6 @@ class LocationsTransformer
'assets_count' => (int) $location->assets_count,
'rtd_assets_count' => (int) $location->rtd_assets_count,
'users_count' => (int) $location->users_count,
'consumables_count' => (int) $location->consumables_count,
'components_count' => (int) $location->components_count,
'children_count' => (int) $location->children_count,
'currency' => ($location->currency) ? e($location->currency) : null,
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
@@ -79,13 +76,12 @@ class LocationsTransformer
];
$permissions_array['available_actions'] = [
'update' => (Gate::allows('update', Location::class) && ($location->deleted_at == '')),
'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => $location->isDeletable(),
'bulk_selectable' => [
'delete' => $location->isDeletable()
],
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
'restore' => (Gate::allows('create', Location::class) && ($location->deleted_at != '')),
];
$array += $permissions_array;
+2 -1
View File
@@ -4,6 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Database\Eloquent\Collection;
class ProfileTransformer
@@ -25,7 +26,7 @@ class ProfileTransformer
'id' => (int) $file->id,
'icon' => Helper::filetype_icon($file->filename),
'item' => ($file->item) ? [
'name' => $file->item->display_name ? e($file->item->display_name) : null,
'name' => ($file->itemType()=='user') ? e($file->item->display_name) : e($file->item->getDisplayNameAttribute()),
'type' => e($file->itemType()),
] : null,
'filename' => e($file->filename),
+2 -2
View File
@@ -22,7 +22,7 @@ class UsersTransformer
public function transformUser(User $user)
{
$role = null;
$role = '';
if ($user->isSuperUser()) {
$role = 'superadmin';
} elseif ($user->isAdmin()) {
@@ -34,7 +34,7 @@ class UsersTransformer
'name' => e($user->getFullNameAttribute()) ?? null,
'first_name' => e($user->first_name) ?? null,
'last_name' => e($user->last_name) ?? null,
'display_name' => ($user->getRawOriginal('display_name')) ? e($user->getRawOriginal('display_name')) : null,
'display_name' => e($user->getRawOriginal('display_name')) ?? null,
'username' => e($user->username) ?? null,
'remote' => ($user->remote == '1') ? true : false,
'locale' => ($user->locale) ? e($user->locale) : null,
+2 -24
View File
@@ -40,32 +40,11 @@ class AssetModelImporter extends ItemImporter
{
$editingAssetModel = false;
/**
* This part gets a little confusing, since folks might be importing multiple models with the same name and different model numbers for the first time
* or they might be wanting to update existing models with new model numbers.
*/
// They are not trying to update existing models, so we'll check for duplicates with model name *and* number
if (! $this->updating) {
$this->log('Finding model by name and model number: '.$this->findCsvMatch($row, 'name').' / '.$this->findCsvMatch($row, 'model_number'));
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->where('model_number', '=', $this->findCsvMatch($row, 'model_number'))->first();
} else {
if ($this->findCsvMatch($row, 'id')!='') {
// Override model if an ID was given
$this->log('Finding model by ID: '.$this->findCsvMatch($row, 'id'));
$assetModel = AssetModel::find($this->findCsvMatch($row, 'id'));
} else {
$this->log('Finding model by name: '.$this->findCsvMatch($row, 'name'));
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
}
}
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
if ($assetModel) {
if (! $this->updating) {
$this->log('A matching Model '.$this->item['name'].' already exists and we are not updating. Skipping.');
$this->log('A matching Model '.$this->item['name'].' already exists');
return;
}
@@ -87,7 +66,6 @@ class AssetModelImporter extends ItemImporter
$this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset'));
$this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation'));
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0;
$this->item['require_serial'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_serial'))) == 1) ? 1 : 0;
if (!empty($this->item['category'])) {
if ($category = $this->createOrFetchCategory($this->item['category'])) {
+11 -37
View File
@@ -96,8 +96,8 @@ class CheckoutableListener
if (!empty($to)) {
try {
$toMail = (clone $mailable)->locale($notifiable->locale);
Mail::to(array_flatten($to))->send($toMail);
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
Log::info('Checkout Mail sent to checkout target');
} catch (ClientException $e) {
Log::debug("Exception caught during checkout email: " . $e->getMessage());
@@ -105,16 +105,6 @@ class CheckoutableListener
Log::debug("Exception caught during checkout email: " . $e->getMessage());
}
}
if (!empty($cc)) {
try {
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
Mail::to(array_flatten($cc))->send($ccMail);
} catch (ClientException $e) {
Log::debug("Exception caught during checkout email: " . $e->getMessage());
} catch (Exception $e) {
Log::debug("Exception caught during checkout email: " . $e->getMessage());
}
}
}
if ($shouldSendWebhookNotification) {
@@ -189,26 +179,16 @@ class CheckoutableListener
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
if (!empty($to)) {
try {
$toMail = (clone $mailable)->locale($notifiable->locale);
Mail::to(array_flatten($to))->send($toMail);
Log::info('Checkin Mail sent to checkin target');
} catch (ClientException $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
} catch (Exception $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
}
}
if (!empty($cc)) {
try {
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
Mail::to(array_flatten($cc))->send($ccMail);
} catch (ClientException $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
} catch (Exception $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
try {
if (!empty($to)) {
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
Log::info('Checkin Mail sent to CC addresses');
}
} catch (ClientException $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
} catch (Exception $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
}
}
@@ -262,12 +242,6 @@ class CheckoutableListener
$acceptance->checkoutable()->associate($event->checkoutable);
$acceptance->assignedTo()->associate($event->checkedOutTo);
$acceptance->qty = 1;
if (isset($event->checkoutable->checkout_qty)) {
$acceptance->qty = $event->checkoutable->checkout_qty;
}
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
if ($category?->alert_on_response) {
-6
View File
@@ -403,7 +403,6 @@ class Importer extends Component
$this->assetmodels_fields = [
'id' => trans('general.id'),
'category' => trans('general.category'),
'eol' => trans('general.eol'),
'fieldset' => trans('admin/models/general.fieldset'),
@@ -413,7 +412,6 @@ class Importer extends Component
'model_number' => trans('general.model_no'),
'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
'requestable' => trans('admin/models/general.requestable'),
'require_serial' => trans('admin/hardware/general.require_serial'),
];
@@ -537,10 +535,6 @@ class Importer extends Component
'product key',
'key',
],
'require_serial' =>
[
'serial required',
],
'model_number' =>
[
'model',
+4 -6
View File
@@ -43,7 +43,7 @@ class CheckoutAccessoryMail extends Mailable
return new Envelope(
from: $from,
subject: trans_choice('mail.Accessory_Checkout_Notification', $this->checkout_qty),
subject: trans('mail.Accessory_Checkout_Notification'),
);
}
@@ -83,19 +83,17 @@ class CheckoutAccessoryMail extends Mailable
],
);
}
private function introductionLine(): string
{
if ($this->target instanceof Location) {
return trans_choice('mail.new_item_checked_location', $this->checkout_qty, ['location' => $this->target->name]);
return trans('mail.new_item_checked_location', ['location' => $this->target->name ]);
}
if ($this->requiresAcceptance()) {
return trans_choice('mail.new_item_checked_with_acceptance', $this->checkout_qty);
return trans('mail.new_item_checked_with_acceptance');
}
if (!$this->requiresAcceptance()) {
return trans_choice('mail.new_item_checked', $this->checkout_qty);
return trans('mail.new_item_checked');
}
// we shouldn't get here but let's send a default message just in case
+3 -4
View File
@@ -138,15 +138,14 @@ class CheckoutAssetMail extends Mailable
private function introductionLine(): string
{
if ($this->firstTimeSending && $this->target instanceof Location) {
return trans_choice('mail.new_item_checked_location', 1, ['location' => $this->target->name]);
return trans('mail.new_item_checked_location', ['location' => $this->target->name ]);
}
if ($this->firstTimeSending && $this->requiresAcceptance()) {
return trans_choice('mail.new_item_checked_with_acceptance', 1);
return trans('mail.new_item_checked_with_acceptance');
}
if ($this->firstTimeSending && !$this->requiresAcceptance()) {
return trans_choice('mail.new_item_checked', 1);
return trans('mail.new_item_checked');
}
if (!$this->firstTimeSending && $this->requiresAcceptance()) {
+1 -1
View File
@@ -26,7 +26,7 @@ class CheckoutComponentMail extends Mailable
$this->note = $note;
$this->target = $checkedOutTo;
$this->acceptance = $acceptance;
$this->qty = $component->checkout_qty;
$this->qty = $component->assets->first()?->pivot?->assigned_qty;
$this->settings = Setting::getSettings();
}
+22 -6
View File
@@ -4,7 +4,6 @@ namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
@@ -66,7 +65,7 @@ class Accessory extends SnipeModel
'company_id' => 'integer|nullable',
'location_id' => 'exists:locations,id|nullable|fmcs_location',
'min_amt' => 'integer|min:0|nullable',
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
'purchase_date' => 'date_format:Y-m-d|nullable',
];
@@ -309,6 +308,27 @@ class Accessory extends SnipeModel
return $this->category->require_acceptance ?? false;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return string
*/
public function getEula()
{
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
}
return null;
}
/**
* Check how many items within an accessory are checked out
*
@@ -357,10 +377,6 @@ class Accessory extends SnipeModel
$accessory_checkout->limit(1)->delete();
}
public function totalCostSum() {
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
}
/**
* -----------------------------------------------
+13 -21
View File
@@ -2,7 +2,6 @@
namespace App\Models;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Carbon\Carbon;
@@ -246,6 +245,19 @@ class Actionlog extends SnipeModel
}
/**
* Establishes the actionlog -> uploads relationship
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function uploads()
{
return $this->morphTo('item')
->where('action_type', '=', 'uploaded')
->withTrashed();
}
/**
* Establishes the actionlog -> userlog relationship
@@ -443,26 +455,6 @@ class Actionlog extends SnipeModel
}
/**
* @author Godfrey Martinez
* @since [v8.0.4]
* @return \App\Models\Actionlog
*/
public function logUploadDelete($object, $filename)
{
$log = new Actionlog;
$log->item_type = $object instanceof SnipeModel ? get_class($object) : $object;
$log->item_id = $object->id;
$log->created_by = auth()->id();
$log->target_id = null;
$log->filename = $filename;
$log->created_at = date('Y-m-d H:i:s');
$log->logaction('upload deleted');
return $log;
}
public function uploads_file_url()
{
+43 -47
View File
@@ -7,20 +7,19 @@ use App\Exceptions\CheckoutNotAllowed;
use App\Helpers\Helper;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\AssetPresenter;
use App\Presenters\Presentable;
use App\Presenters\AssetPresenter;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
/**
* Model for Assets.
@@ -114,7 +113,7 @@ class Asset extends Depreciable
'rtd_location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'],
'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'],
'serial' => ['nullable', 'string', 'unique_undeleted:assets,serial'],
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:99999999999999999.99'],
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:9999999999999'],
'supplier_id' => ['nullable', 'exists:suppliers,id'],
'asset_eol_date' => ['nullable', 'date'],
'eol_explicit' => ['nullable', 'boolean'],
@@ -161,6 +160,7 @@ class Asset extends Depreciable
'eol_explicit',
'last_audit_date',
'next_audit_date',
'asset_eol_date',
'last_checkin',
'last_checkout',
];
@@ -823,26 +823,21 @@ class Asset extends Depreciable
* @since [v2.0]
* @return mixed
*/
public static function getExpiringWarrantyOrEol($days = 30)
public static function getExpiringWarrantee($days = 30)
{
return self::where('archived', '=', '0')
->NotArchived()
$days = (is_null($days)) ? 30 : $days;
return self::where('archived', '=', '0') // this can stay for right now, as `archived` defaults to 0 at the db level, but should probably be replaced with assetstatus->archived?
->whereNotNull('warranty_months')
->whereNotNull('purchase_date')
->whereNull('deleted_at')
->where(function ($query) use ($days) {
// Check for manual asset EOL first
$query->where(function ($query) use ($days) {
$query->whereNotNull('asset_eol_date')
->whereBetween('asset_eol_date', [Carbon::now(), Carbon::now()->addDays($days)]);
// Otherwise use the warranty months + purchase date + threshold
})->orWhere(function ($query) use ($days) {
$query->whereNotNull('purchase_date')
->whereNotNull('warranty_months')
->whereBetween('purchase_date', [Carbon::now(), Carbon::now()->addMonths('assets.warranty_months')->addDays($days)]);
});
})
->orderBy('asset_eol_date', 'ASC')
->orderBy('purchase_date', 'ASC')
->NotArchived()
->whereRaw(
'DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) <= DATE_ADD(NOW(), INTERVAL '
. $days
. ' DAY) AND DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) > NOW()'
)
->orderByRaw('DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH)')
->get();
}
@@ -1023,6 +1018,31 @@ class Asset extends Depreciable
return false;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string | false
*/
public function getEula()
{
if (($this->model) && ($this->model->category)) {
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula == 0)) {
return Helper::parseEscapedMarkedown($this->model->category->eula_text);
} elseif ($this->model->category->use_default_eula == 1) {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
} else {
return false;
}
}
return false;
}
public function getComponentCost()
{
$cost = 0;
@@ -1872,30 +1892,6 @@ class Asset extends Depreciable
);
}
if ($fieldname == 'jobtitle') {
$query->where(function ($query) use ($search_val) {
if (is_array($search_val)) {
$query->whereHasMorph(
'assignedTo',
[User::class],
function ($query) use ($search_val) {
$query->whereIn('users.jobtitle', $search_val);
}
);
} else {
$query->whereHasMorph(
'assignedTo',
[User::class],
function ($query) use ($search_val) {
$query->where(function ($query) use ($search_val) {
$query->where('users.jobtitle', 'LIKE', '%' . $search_val . '%');
});
}
);
}
});
}
/**
* THIS CLUNKY BIT IS VERY IMPORTANT
@@ -1920,7 +1916,7 @@ class Asset extends Depreciable
*/
if (($fieldname!='category') && ($fieldname!='model_number') && ($fieldname!='rtd_location') && ($fieldname!='location') && ($fieldname!='supplier')
&& ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='jobtitle') && ($fieldname!='company') && ($fieldname!='manufacturer')
&& ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='company') && ($fieldname!='manufacturer')
) {
$query->where('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%');
}
-1
View File
@@ -71,7 +71,6 @@ class AssetModel extends SnipeModel
'name',
'notes',
'requestable',
'require_serial'
];
use Searchable;
+3 -105
View File
@@ -2,14 +2,11 @@
namespace App\Models;
use App\Helpers\Helper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Notifications\Notifiable;
use TCPDF;
class CheckoutAcceptance extends Model
{
@@ -132,7 +129,8 @@ class CheckoutAcceptance extends Model
/**
* Filter checkout acceptences by the user
*
* @param User $user
* @param Illuminate\Database\Eloquent\Builder $query
* @param User $user
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeForUser(Builder $query, User $user)
@@ -143,111 +141,11 @@ class CheckoutAcceptance extends Model
/**
* Filter to only get pending acceptances
*
* @param Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePending(Builder $query)
{
return $query->whereNull('accepted_at')->whereNull('declined_at');
}
public function scopeDeclined(Builder $query)
{
return $query->whereNull('accepted_at')->whereNotNull('declined_at');
}
protected function displayCheckoutableType(): Attribute
{
return Attribute:: make(
get: fn(mixed $value) => strtolower(str_replace('App\Models\\', '', $this->checkoutable_type)),
);
}
public function generateAcceptancePdf($data, $pdf_filename) {
// set some language dependent data:
$lg = Array();
$lg['a_meta_charset'] = 'UTF-8';
$lg['w_page'] = 'page';
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
$pdf->setRTL(false);
$pdf->setLanguageArray($lg);
$pdf->SetFontSubsetting(true);
$pdf->SetCreator('Snipe-IT Asset Management System');
$pdf->SetAuthor($data['assigned_to']);
$pdf->SetTitle('Asset Acceptance: '.$data['item_tag']);
$pdf->SetSubject('Asset Acceptance: '.$data['item_tag']);
$pdf->SetKeywords('Snipe-IT, assets, acceptance, eula, tos');
$pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->SetPrintHeader(false);
$pdf->SetPrintFooter(false);
$pdf->AddPage();
if ($data['logo'] != null) {
$pdf->writeHTML('<img src="'.$data['logo'].'">', true, 0, true, 0, '');
} else {
$pdf->writeHTML('<h3>'.$data['site_name'].'</h3><br /><br />', true, 0, true, 0, 'C');
}
$pdf->Ln();
$pdf->writeHTML(trans('general.date') . ': ' . Helper::getFormattedDateObject(now(), 'datetime', false), true, 0, true, 0, '');
if ($data['company_name'] != null) {
$pdf->writeHTML(trans('general.company') . ': ' . e($data['company_name']), true, 0, true, 0, '');
}
if ($data['item_tag'] != null) {
$pdf->writeHTML(trans('general.asset_tag') . ': ' . e($data['item_tag']), true, 0, true, 0, '');
}
if ($data['item_name'] != null) {
$pdf->writeHTML(trans('general.name') . ': ' . e($data['item_name']), true, 0, true, 0, '');
}
if ($data['item_model'] != null) {
$pdf->writeHTML(trans('general.asset_model') . ': ' . e($data['item_model']), true, 0, true, 0, '');
}
if ($data['item_serial'] != null) {
$pdf->writeHTML(trans('admin/hardware/form.serial').': '.e($data['item_serial']), true, 0, true, 0, '');
}
if (($data['qty'] != null) && ($data['qty'] > 1)) {
$pdf->writeHTML(trans('general.qty').': '.e($data['qty']), true, 0, true, 0, '');
}
$pdf->writeHTML(trans('general.assignee').': '.e($data['assigned_to']), true, 0, true, 0, '');
$pdf->Ln();
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
// Break the EULA into lines based on newlines, and check each line for RTL or CJK characters
$eula_lines = preg_split("/\r\n|\n|\r/", $data['eula']);
foreach ($eula_lines as $eula_line) {
Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false);
Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
}
$pdf->Ln();
$pdf->Ln();
$pdf->setRTL(false);
$pdf->Ln();
if ($data['signature'] != null) {
$pdf->writeHTML('<img src="'.$data['signature'].'">', true, 0, true, 0, '');
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
$pdf->writeHTML(e($data['assigned_to']), true, 0, true, 0, 'C');
$pdf->Ln();
}
if ($data['note'] != null) {
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->writeHTML(trans('general.notes') . ': ' . e($data['note']), true, 0, true, 0, '');
$pdf->Ln();
}
$pdf->writeHTML(trans('general.assigned_date').': '.e($data['check_out_date']), true, 0, true, 0, '');
$pdf->writeHTML(trans('general.accepted_date').': '.e($data['accepted_date']), true, 0, true, 0, '');
return $pdf->Output($pdf_filename, 'S');
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ class CheckoutRequest extends Model
public function name()
{
if ($this->itemType() == 'asset') {
return $this->itemRequested()->display_name;
return $this->itemRequested()->present()->name();
}
return $this->itemRequested()->name;
+2 -4
View File
@@ -2,16 +2,14 @@
namespace App\Models;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Gate;
use Watson\Validating\ValidatingTrait;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Watson\Validating\ValidatingTrait;
/**
* Model for Companies.
*
@@ -1,8 +1,6 @@
<?php
namespace App\Models\Traits;
use App\Models\CompanyableChildScope;
namespace App\Models;
trait CompanyableChildTrait
{
@@ -1,9 +1,6 @@
<?php
namespace App\Models\Traits;
use App\Models\CompanyableScope;
use App\Models\Setting;
namespace App\Models;
trait CompanyableTrait
{
+20 -5
View File
@@ -3,13 +3,13 @@
namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
/**
@@ -43,7 +43,7 @@ class Component extends SnipeModel
'location_id' => 'exists:locations,id|nullable|fmcs_location',
'min_amt' => 'integer|min:0|nullable',
'purchase_date' => 'date_format:Y-m-d|nullable',
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
'manufacturer_id' => 'integer|exists:manufacturers,id|nullable',
];
@@ -217,6 +217,24 @@ class Component extends SnipeModel
return $this->category->require_acceptance;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string | false
*/
public function getEula()
{
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
} else {
return null;
}
}
/**
* Establishes the component -> action logs relationship
@@ -288,10 +306,7 @@ class Component extends SnipeModel
return $this->qty - $this->numCheckedOut();
}
public function totalCostSum() {
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
}
/**
* -----------------------------------------------
* BEGIN MUTATORS
+29 -7
View File
@@ -4,16 +4,22 @@ namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\ConsumablePresenter;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Relations\Relation;
use App\Presenters\ConsumablePresenter;
use App\Models\Actionlog;
use App\Models\ConsumableAssignment;
use App\Models\User;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Supplier;
use App\Models\Category;
class Consumable extends SnipeModel
{
@@ -47,7 +53,7 @@ class Consumable extends SnipeModel
'company_id' => 'integer|nullable',
'location_id' => 'exists:locations,id|nullable|fmcs_location',
'min_amt' => 'integer|min:0|max:99999|nullable',
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
'purchase_date' => 'date_format:Y-m-d|nullable',
];
@@ -285,6 +291,25 @@ class Consumable extends SnipeModel
return $this->category->require_acceptance;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string | false
*/
public function getEula()
{
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
} else {
return null;
}
}
/**
* Check how many items within a consumable are checked out
*
@@ -312,10 +337,7 @@ class Consumable extends SnipeModel
return $remaining;
}
public function totalCostSum() {
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
}
/**
* -----------------------------------------------
* BEGIN MUTATORS
-1
View File
@@ -2,7 +2,6 @@
namespace App\Models;
use App\Models\Traits\CompanyableTrait;
use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait;
-1
View File
@@ -3,7 +3,6 @@
namespace App\Models;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\Searchable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Watson\Validating\ValidatingTrait;
+5 -7
View File
@@ -78,13 +78,6 @@ class Ldap extends Model
if (env('LDAPTLS_CACERT')) {
putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT'));
}
// You _were_ allowed to do this *after* the ldap_connect() in some versions of PHP, but it's not how they want
// you to anymore, and it seems to not work at all in later PHP versions.
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
}
$connection = @ldap_connect($ldap_host);
if (! $connection) {
@@ -96,6 +89,11 @@ 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(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
}
if ($ldap_use_tls=='1') {
ldap_start_tls($connection);
}
+40 -122
View File
@@ -3,18 +3,17 @@
namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Watson\Validating\ValidatingTrait;
class License extends Depreciable
{
use HasFactory;
@@ -52,7 +51,7 @@ class License extends Depreciable
'notes' => 'string|nullable',
'category_id' => 'required|exists:categories,id',
'company_id' => 'integer|nullable',
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
'purchase_cost'=> 'numeric|nullable|gte:0',
'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id',
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
@@ -297,38 +296,6 @@ class License extends Depreciable
}
$this->attributes['termination_date'] = $value;
}
public function isInactive(): bool
{
$day = now()->startOfDay();
$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);
$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);
return $this->isExpired() || $this->isTerminated();
}
public function isExpired(): bool
{
$day = now()->startOfDay();
$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);
return $expired;
}
public function isTerminated(): bool
{
$day = now()->startOfDay();
$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);
return $terminated;
}
/**
* Sets free_seat_count attribute
*
@@ -408,6 +375,27 @@ class License extends Depreciable
return false;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string | false
*/
public function getEula()
{
if ($this->category) {
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ($this->category->use_default_eula == '1') {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
}
}
return false;
}
/**
* Establishes the license -> assigned user relationship
@@ -546,7 +534,6 @@ class License extends Depreciable
return $this->licenseSeatsRelation()
->whereNull('asset_id')
->whereNull('assigned_to')
->where('unreassignable_seat', '=', false)
->whereNull('deleted_at');
}
@@ -598,22 +585,7 @@ class License extends Depreciable
return 0;
}
/**
* Calculates the number of unreassignable seats
*
* @author G. Martinez
* @since [v7.1.15]
*/
public static function unReassignableCount($license) : int
{
$count = 0;
if (!$license->reassignable) {
$count = LicenseSeat::query()->where('unreassignable_seat', '=', true)
->where('license_id', '=', $license->id)
->count();
}
return $count;
}
/**
* Calculates the number of remaining seats
*
@@ -621,12 +593,11 @@ class License extends Depreciable
* @since [v1.0]
* @return int
*/
public function remaincount() : int
public function remaincount()
{
$total = $this->licenseSeatsCount;
$taken = $this->assigned_seats_count;
$unreassignable = self::unReassignableCount($this);
$diff = ($total - $taken - $unreassignable);
$diff = ($total - $taken);
return (int) $diff;
}
@@ -684,11 +655,12 @@ class License extends Depreciable
{
return $this->licenseseats()
->whereNull('deleted_at')
->where('unreassignable_seat', '=', false)
->where(function ($query) {
$query->whereNull('assigned_to')
->whereNull('asset_id');
})
->where(
function ($query) {
$query->whereNull('assigned_to')
->whereNull('asset_id');
}
)
->orderBy('id', 'asc')
->first();
}
@@ -707,80 +679,26 @@ class License extends Depreciable
}
/**
* Returns expiring licenses.
* Returns expiring licenses
*
* This checks if:
*
* 1) The license has not been deleted
* 2) The expiration date is between now and the number of days specified
* 3) There is an expiration date set and the termination date has not passed
* 4) The license termination date is null or has not passed
* @todo should refactor. I don't like get() in model methods
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v1.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
* @see \App\Console\Commands\SendExpiringLicenseNotifications
*/
public static function getExpiringLicenses($days = 60)
{
$days = (is_null($days)) ? 60 : $days;
return self::whereNull('licenses.deleted_at')
// The termination date is null or within range
->where(function ($query) use ($days) {
$query->whereNull('termination_date')
->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
})
->where(function ($query) use ($days) {
$query->whereNotNull('expiration_date')
// Handle expired licenses without termination dates
->where(function ($query) use ($days) {
$query->whereNull('termination_date')
->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]);
})
// Handle expired licenses with termination dates in the future
->orWhere(function ($query) use ($days) {
$query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
});
})
return self::whereNotNull('expiration_date')
->whereNull('deleted_at')
->whereRaw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) ')
->where('expiration_date', '>', date('Y-m-d'))
->orderBy('expiration_date', 'ASC')
->orderBy('termination_date', 'ASC')
->get();
}
public function scopeActiveLicenses($query)
{
return $query->whereNull('licenses.deleted_at')
// The termination date is null or within range
->where(function ($query) {
$query->whereNull('termination_date')
->orWhereDate('termination_date', '>', [Carbon::now()]);
})
->where(function ($query) {
$query->whereNull('expiration_date')
->orWhereDate('expiration_date', '>', [Carbon::now()]);
});
}
public function scopeExpiredLicenses($query)
{
return $query->whereNull('licenses.deleted_at')
// The termination date is null or within range
->where(function ($query) {
$query->whereNull('termination_date')
->orWhereDate('termination_date', '<=', [Carbon::now()]);
})
->orWhere(function ($query) {
$query->whereNull('expiration_date')
->orWhereDate('expiration_date', '<=', [Carbon::now()]);
});
}
/**
* Query builder scope to order on manufacturer
*
-20
View File
@@ -3,11 +3,9 @@
namespace App\Models;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableChildTrait;
use App\Notifications\CheckinLicenseNotification;
use App\Notifications\CheckoutLicenseNotification;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -23,9 +21,6 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
protected $guarded = 'id';
protected $table = 'license_seats';
protected $casts = [
'unreassignable_seat' => 'boolean',
];
/**
* The attributes that are mass assignable.
@@ -65,21 +60,6 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
return $this->license->getEula();
}
protected function name(): Attribute
{
return Attribute:: make(
get: fn(mixed $value) => $this->license->name,
);
}
protected function displayName(): Attribute
{
return Attribute:: make(
get: fn(mixed $value) => $this->license->name,
);
}
/**
* Establishes the seat -> license relationship
*
+11 -13
View File
@@ -3,11 +3,16 @@
namespace App\Models;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\CompanyableTrait;
use App\Models\Asset;
use App\Models\Setting;
use App\Models\SnipeModel;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Models\User;
use App\Presenters\Presentable;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate;
use Watson\Validating\ValidatingTrait;
@@ -43,7 +48,6 @@ class Location extends SnipeModel
'company_id' => 'integer',
];
/**
* Whether the model should inject its identifier to the unique
* validation rules before attempting validation. If this property
@@ -114,19 +118,13 @@ class Location extends SnipeModel
{
return Gate::allows('delete', $this)
&& ($this->deleted_at == '')
&& (($this->assets_count ?? $this->assets()->count()) === 0)
&& (($this->assigned_assets_count ?? $this->assignedAssets()->count()) === 0)
&& (($this->accessories_count ?? $this->accessories()->count()) === 0)
&& (($this->assigned_accessories_count ?? $this->assignedAccessories()->count()) === 0)
&& (($this->children_count ?? $this->children()->count()) === 0)
&& (($this->components_count ?? $this->components()->count()) === 0)
&& (($this->consumables_count ?? $this->consumables()->count()) === 0)
&& (($this->rtd_assets_count ?? $this->rtd_assets()->count()) === 0)
&& (($this->users_count ?? $this->users()->count()) === 0);
&& ($this->assets_count == 0)
&& ($this->assigned_assets_count == 0)
&& ($this->children_count == 0)
&& ($this->accessories_count == 0)
&& ($this->users_count == 0);
}
/**
* Establishes the user -> location relationship
*
+3 -4
View File
@@ -3,13 +3,12 @@
namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableChildTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
use App\Models\Traits\HasUploads;
/**
* Model for Asset Maintenances.
@@ -32,12 +31,12 @@ class Maintenance extends SnipeModel implements ICompanyableChild
'asset_id' => 'required|integer',
'supplier_id' => 'nullable|integer',
'asset_maintenance_type' => 'required',
'name' => 'required|max:100',
'name' => 'required|max:100',
'is_warranty' => 'boolean',
'start_date' => 'required|date_format:Y-m-d',
'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date',
'notes' => 'string|nullable',
'cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
'cost' => 'numeric|nullable',
];
-38
View File
@@ -3,10 +3,8 @@
namespace App\Models;
use App\Helpers\Helper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Request;
class SnipeModel extends Model
{
@@ -158,20 +156,6 @@ class SnipeModel extends Model
$this->attributes['status_id'] = $value;
}
/**
* Applies offset (from request) and limit to query.
*
* @param Builder $query
* @param int $total
* @return void
*/
public function scopeApplyOffsetAndLimit(Builder $query, int $total)
{
$offset = (Request::input('offset') > $total) ? $total : app('api_offset_value');
$limit = app('api_limit_value');
$query->skip($offset)->take($limit);
}
protected function displayName(): Attribute
{
@@ -180,27 +164,5 @@ class SnipeModel extends Model
);
}
public function getEula()
{
// This is - for now - only for assets, where the asset model is the thing tied to the category
if (($this->model) && ($this->model->category)) {
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula == 0)) {
return $this->model->category->eula_text;
} elseif ($this->model->category->use_default_eula == 1) {
return Setting::getSettings()->default_eula_text;
} else {
return false;
}
// For everything else, just check the category for EULA info
} elseif (($this->category) && ($this->category->eula_text)) {
return $this->category->eula_text;
} elseif ((Setting::getSettings()->default_eula_text) && (($this->category) && ($this->category->use_default_eula == '1'))) {
return Setting::getSettings()->default_eula_text;
}
return null;
}
}
+1 -8
View File
@@ -12,14 +12,7 @@ trait HasUploads
return $this->hasMany(Actionlog::class, 'item_id')
->where('item_type', self::class)
->where('action_type', '=', 'uploaded')
->whereNotNull('filename')
->whereNotIn('filename', function ($query) {
$query->select('filename')
->from('action_logs')
->where('item_type', '=', self::class)
->where('action_type', '=', 'upload deleted')
->where('item_id', $this->id);
});
->whereNotNull('filename');
}
+3 -4
View File
@@ -3,11 +3,9 @@
namespace App\Models;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable;
use App\Models\Traits\HasUploads;
use App\Presenters\Presentable;
use App\Presenters\UserPresenter;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
@@ -15,7 +13,6 @@ use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -25,6 +22,8 @@ use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use App\Presenters\UserPresenter;
class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference
{
@@ -2,7 +2,6 @@
namespace App\Notifications;
use AllowDynamicProperties;
use App\Helpers\Helper;
use App\Models\Setting;
use Illuminate\Bus\Queueable;
@@ -11,7 +10,7 @@ use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
#[AllowDynamicProperties] class AcceptanceAssetAcceptedNotification extends Notification
class AcceptanceAssetAcceptedNotification extends Notification
{
use Queueable;
@@ -23,18 +22,15 @@ use Illuminate\Notifications\Notification;
public function __construct($params)
{
$this->item_tag = $params['item_tag'];
$this->item_name = $params['item_name'];
$this->item_model = $params['item_model'];
$this->item_serial = $params['item_serial'];
$this->item_status = $params['item_status'];
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false);
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false);
$this->assigned_to = $params['assigned_to'];
$this->note = $params['note'];
$this->company_name = $params['company_name'];
$this->settings = Setting::getSettings();
$this->file = $params['file'] ?? null;
$this->qty = $params['qty'] ?? null;
$this->note = $params['note'] ?? null;
$this->admin = $params['admin'] ?? null;
$this->settings = Setting::getSettings();
}
@@ -69,7 +65,6 @@ use Illuminate\Notifications\Notification;
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
[
'item_tag' => $this->item_tag,
'item_name' => $this->item_name,
'item_model' => $this->item_model,
'item_serial' => $this->item_serial,
'item_status' => $this->item_status,
@@ -77,9 +72,8 @@ use Illuminate\Notifications\Notification;
'accepted_date' => $this->accepted_date,
'assigned_to' => $this->assigned_to,
'company_name' => $this->company_name,
'admin' => $this->admin,
'qty' => $this->qty,
'intro_text' => trans('mail.acceptance_asset_accepted'),
'admin' => $this->admin,
])
->subject(trans('mail.acceptance_asset_accepted'));
@@ -2,14 +2,13 @@
namespace App\Notifications;
use AllowDynamicProperties;
use App\Helpers\Helper;
use App\Models\Setting;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
#[AllowDynamicProperties] class AcceptanceAssetAcceptedToUserNotification extends Notification
class AcceptanceAssetAcceptedToUserNotification extends Notification
{
use Queueable;
@@ -21,18 +20,16 @@ use Illuminate\Notifications\Notification;
public function __construct($params)
{
$this->item_tag = $params['item_tag'];
$this->item_name = $params['item_name'];
$this->item_model = $params['item_model'];
$this->item_serial = $params['item_serial'];
$this->item_status = $params['item_status'];
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false);
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false);
$this->assigned_to = $params['assigned_to'];
$this->note = $params['note'] ?? null;
$this->note = $params['note'];
$this->company_name = $params['company_name'];
$this->settings = Setting::getSettings();
$this->file = $params['file'] ?? null;
$this->qty = $params['qty'] ?? null;
$this->admin = $params['admin'] ?? null;
}
/**
@@ -62,7 +59,6 @@ use Illuminate\Notifications\Notification;
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
[
'item_tag' => $this->item_tag,
'item_name' => $this->item_name,
'item_model' => $this->item_model,
'item_serial' => $this->item_serial,
'item_status' => $this->item_status,
@@ -70,12 +66,10 @@ use Illuminate\Notifications\Notification;
'accepted_date' => $this->accepted_date,
'assigned_to' => $this->assigned_to,
'company_name' => $this->company_name,
'admin' => $this->admin,
'qty' => $this->qty,
'intro_text' => trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name]),
'intro_text' => trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->company_name ?? $this->settings->site_name]),
])
->attach($pdf_path)
->subject(trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name]));
->subject(trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->settings->site_name]));
return $message;
}
@@ -30,7 +30,6 @@ class AcceptanceAssetDeclinedNotification extends Notification
$this->assigned_to = $params['assigned_to'];
$this->company_name = $params['company_name'];
$this->settings = Setting::getSettings();
$this->qty = $params['qty'] ?? null;
}
/**
@@ -70,7 +69,6 @@ class AcceptanceAssetDeclinedNotification extends Notification
'declined_date' => $this->declined_date,
'assigned_to' => $this->assigned_to,
'company_name' => $this->company_name,
'qty' => $this->qty,
'intro_text' => trans('mail.acceptance_asset_declined'),
])
->subject(trans('mail.acceptance_asset_declined'));
+2 -2
View File
@@ -61,7 +61,7 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
->from(($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot')
->to($channel)
->attachment(function ($attachment) {
$item = $this->params['item'] ?? null;
$item = $this->params['item'];
$admin_user = $this->params['admin'];
$fields = [
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->display_name.'>',
@@ -93,7 +93,7 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
}
$message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name;
$details = [
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
trans('mail.notes') => $note ?: '',
trans('general.location') => $location ?: '',
];
@@ -90,7 +90,7 @@ class CheckinAccessoryNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -107,7 +107,7 @@ class CheckinAccessoryNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('Accessory_Checkin_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
@@ -116,7 +116,7 @@ class CheckinAccessoryNotification extends Notification
$message = trans('mail.Accessory_Checkin_Notification');
$details = [
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->display_name,
trans('admin/consumables/general.remaining')=> $item->numRemaining(),
@@ -135,7 +135,7 @@ class CheckinAccessoryNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
+10 -10
View File
@@ -93,11 +93,11 @@ class CheckinAssetNotification extends Notification
return (new SlackMessage)
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification', ['tag' => '']))
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification'))
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -112,21 +112,21 @@ class CheckinAssetNotification extends Notification
return MicrosoftTeamsMessage::create()
->to($this->settings->webhook_endpoint)
->type('success')
->title(trans('mail.Asset_Checkin_Notification', ['tag' => '']))
->title(trans('mail.Asset_Checkin_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
->fact(trans('general.administrator'), $admin->display_name)
->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->display_name)
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
->fact(trans('mail.notes'), $note ?: '');
}
$message = trans('mail.Asset_Checkin_Notification', ['tag' => '']);
$message = trans('mail.Asset_Checkin_Notification');
$details = [
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
trans('general.administrator') => $admin->display_name,
trans('mail.Asset_Checkin_Notification')." by " => $admin->display_name,
trans('admin/hardware/form.status') => $item->assetstatus?->name,
trans('mail.notes') => $note ?: '',
];
@@ -144,8 +144,8 @@ class CheckinAssetNotification extends Notification
->card(
Card::create()
->header(
'<strong>'.trans('mail.Asset_Checkin_Notification', ['tag' =>'']).'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
'<strong>'.trans('mail.Asset_Checkin_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -100,7 +100,7 @@ class CheckinComponentNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -118,7 +118,7 @@ class CheckinComponentNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.Component_checkin_notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
->fact(trans('mail.Component_checkin_notification')." by ", $admin->display_name ?: 'CLI tool')
->fact(trans('mail.checkedin_from'), $target->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
@@ -147,7 +147,7 @@ class CheckinComponentNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.Component_checkin_notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -101,7 +101,7 @@ class CheckinLicenseSeatNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -119,7 +119,7 @@ class CheckinLicenseSeatNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.License_Checkin_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
->fact(trans('mail.License_Checkin_Notification')." by ", $admin->display_name ?: 'CLI tool')
->fact(trans('mail.checkedin_from'), $target->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
@@ -129,7 +129,7 @@ class CheckinLicenseSeatNotification extends Notification
$message = trans('mail.License_Checkin_Notification');
$details = [
trans('mail.checkedin_from')=> $target->display_name,
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
trans('mail.License_Checkin_Notification')." by " => $admin->display_name ?: 'CLI tool',
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
trans('mail.notes') => $note ?: '',
@@ -149,7 +149,7 @@ class CheckinLicenseSeatNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -117,7 +117,7 @@ class CheckoutAccessoryNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -136,8 +136,8 @@ class CheckoutAccessoryNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.Accessory_Checkout_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
->fact(trans('mail.assigned_to'), $target->display_name)
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.assigned_to'), $target->present()->name)
->fact(trans('general.qty'), $this->checkout_qty)
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->display_name)
@@ -148,7 +148,7 @@ class CheckoutAccessoryNotification extends Notification
$message = trans('mail.Accessory_Checkout_Notification');
$details = [
trans('mail.assigned_to') => $target->present()->name,
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
trans('general.qty') => $this->checkout_qty,
trans('mail.checkedout_from') => $item->location->name ? $item->location->name : '',
trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->display_name,
@@ -169,7 +169,7 @@ class CheckoutAccessoryNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
+11 -11
View File
@@ -110,11 +110,11 @@ class CheckoutAssetNotification extends Notification
}
return (new SlackMessage)
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification', ['tag' => '']))
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification'))
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -131,19 +131,19 @@ class CheckoutAssetNotification extends Notification
return MicrosoftTeamsMessage::create()
->to($this->settings->webhook_endpoint)
->type('success')
->title(trans('mail.Asset_Checkout_Notification', ['tag' => '']))
->title(trans('mail.Asset_Checkout_Notification'))
->addStartGroupToSection('activityText')
->fact(trans('mail.assigned_to'), $target->display_name)
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
->fact(trans('general.administrator'), $admin->display_name)
->fact(trans('mail.assigned_to'), $target->present()->name)
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
->fact(trans('mail.Asset_Checkout_Notification') . " by ", $admin->display_name)
->fact(trans('mail.notes'), $note ?: '');
}
$message = trans('mail.Asset_Checkout_Notification', ['tag' => '']);
$message = trans('mail.Asset_Checkout_Notification');
$details = [
trans('mail.assigned_to') => $target->present()->name,
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
trans('general.administrator') => $admin->display_name,
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
trans('mail.Asset_Checkout_Notification'). ' by' => $admin->display_name,
trans('mail.notes') => $note ?: '',
];
return array($message, $details);
@@ -159,8 +159,8 @@ public function toGoogleChat()
->card(
Card::create()
->header(
'<strong>'.trans('mail.Asset_Checkout_Notification', ['tag' => '']).'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
'<strong>'.trans('mail.Asset_Checkout_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -97,7 +97,7 @@ class CheckoutComponentNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -116,7 +116,7 @@ class CheckoutComponentNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.Component_checkout_notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.Component_checkout_notification')." by ", $admin->display_name)
->fact(trans('mail.assigned_to'), $target->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
@@ -126,7 +126,7 @@ class CheckoutComponentNotification extends Notification
$message = trans('mail.Component_checkout_notification');
$details = [
trans('mail.assigned_to') => $target->display_name,
trans('mail.item') => htmlspecialchars_decode($item->display_name),
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
trans('mail.Component_checkout_notification').' by' => $admin->display_name,
trans('admin/consumables/general.remaining') => $item->numRemaining(),
trans('mail.notes') => $note ?: '',
@@ -146,7 +146,7 @@ class CheckoutComponentNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.Component_checkout_notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -97,7 +97,7 @@ class CheckoutConsumableNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -116,7 +116,7 @@ class CheckoutConsumableNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.Consumable_checkout_notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->display_name)
->fact(trans('mail.assigned_to'), $target->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
@@ -126,7 +126,7 @@ class CheckoutConsumableNotification extends Notification
$message = trans('mail.Consumable_checkout_notification');
$details = [
trans('mail.assigned_to') => $target->display_name,
trans('mail.item') => htmlspecialchars_decode($item->display_name),
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
trans('mail.Consumable_checkout_notification').' by' => $admin->display_name,
trans('admin/consumables/general.remaining') => $item->numRemaining(),
trans('mail.notes') => $note ?: '',
@@ -146,7 +146,7 @@ class CheckoutConsumableNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -95,7 +95,7 @@ class CheckoutLicenseSeatNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -114,7 +114,7 @@ class CheckoutLicenseSeatNotification extends Notification
->addStartGroupToSection('activityTitle')
->title(trans('mail.License_Checkout_Notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.License_Checkout_Notification')." by ", $admin->display_name)
->fact(trans('mail.assigned_to'), $target->display_name)
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
@@ -124,7 +124,7 @@ class CheckoutLicenseSeatNotification extends Notification
$message = trans('mail.License_Checkout_Notification');
$details = [
trans('mail.assigned_to') => $target->display_name,
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
trans('mail.License_Checkout_Notification').' by' => $admin->display_name,
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
trans('mail.notes') => $note ?: '',
@@ -143,7 +143,7 @@ class CheckoutLicenseSeatNotification extends Notification
Card::create()
->header(
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
htmlspecialchars_decode($item->display_name) ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
@@ -50,11 +50,11 @@ class ExpectedCheckinNotification extends Notification
$message = (new MailMessage)->markdown('notifications.markdown.expected-checkin',
[
'date' => Helper::getFormattedDateObject($this->params->expected_checkin, 'date', false),
'asset' => $this->params->display_name,
'asset' => $this->params->present()->name(),
'serial' => $this->params->serial,
'asset_tag' => $this->params->asset_tag,
])
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name]));
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->present()->name()]));
return $message;
}
@@ -91,7 +91,7 @@ class RequestAssetCancelation extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
@@ -86,7 +86,7 @@ class RequestAssetNotification extends Notification
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $fields) {
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
+1 -7
View File
@@ -120,13 +120,7 @@ class AccessoryPresenter extends Presenter
'field' => 'purchase_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.unit_cost'),
'class' => 'text-right text-padding-number-cell',
], [
'field' => 'total_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.total_cost'),
'title' => trans('general.purchase_cost'),
'footerFormatter' => 'sumFormatterQuantity',
'class' => 'text-right text-padding-number-cell',
], [
+2 -6
View File
@@ -62,10 +62,6 @@ class ActionlogPresenter extends Presenter
return 'fa-solid fa-user-minus';
}
if ($this->action_type == 'upload deleted') {
return 'fa-solid fa-trash';
}
if ($this->action_type == 'update') {
return 'fa-solid fa-user-pen';
}
@@ -78,7 +74,7 @@ class ActionlogPresenter extends Presenter
return 'fa-solid fa-plus';
}
if (($this->action_type == 'delete') || ($this->action_type == 'upload deleted')) {
if ($this->action_type == 'delete') {
return 'fa-solid fa-trash';
}
@@ -145,7 +141,7 @@ class ActionlogPresenter extends Presenter
return $target->present()->nameUrl();
}
return '<del>'.$target->display_name.'</del>';
return '<del>'.$target->present()->name().'</del>';
}
return '';
-8
View File
@@ -143,14 +143,6 @@ class AssetModelPresenter extends Presenter
'title' => trans('admin/hardware/general.requestable'),
'formatter' => 'trueFalseFormatter',
],
[
'field' => 'require_serial',
'searchable' => false,
'sortable' => true,
'visible' => false,
'title' => trans('admin/hardware/general.require_serial'),
'formatter' => 'trueFalseFormatter',
],
[
'field' => 'notes',
'searchable' => true,
+21 -27
View File
@@ -79,25 +79,6 @@ class ComponentPresenter extends Presenter
'title' => trans('general.manufacturer'),
'visible' => false,
'formatter' => 'manufacturersLinkObjFormatter',
], [
'field' => 'location',
'searchable' => true,
'sortable' => true,
'title' => trans('general.location'),
'formatter' => 'locationsLinkObjFormatter',
], [
'field' => 'order_number',
'searchable' => true,
'sortable' => true,
'title' => trans('general.order_number'),
'visible' => true,
], [
'field' => 'purchase_date',
'searchable' => true,
'sortable' => true,
'title' => trans('general.purchase_date'),
'visible' => true,
'formatter' => 'dateDisplayFormatter',
], [
'field' => 'min_amt',
'searchable' => false,
@@ -122,20 +103,33 @@ class ComponentPresenter extends Presenter
'visible' => true,
'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'location',
'searchable' => true,
'sortable' => true,
'title' => trans('general.location'),
'formatter' => 'locationsLinkObjFormatter',
], [
'field' => 'order_number',
'searchable' => true,
'sortable' => true,
'title' => trans('general.order_number'),
'visible' => true,
], [
'field' => 'purchase_date',
'searchable' => true,
'sortable' => true,
'title' => trans('general.purchase_date'),
'visible' => true,
'formatter' => 'dateDisplayFormatter',
], [
'field' => 'purchase_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.unit_cost'),
'title' => trans('general.purchase_cost'),
'visible' => true,
'class' => 'text-right',
], [
'field' => 'total_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.total_cost'),
'footerFormatter' => 'sumFormatterQuantity',
'class' => 'text-right text-padding-number-cell',
'class' => 'text-right',
], [
'field' => 'notes',
'searchable' => true,
+30 -37
View File
@@ -67,6 +67,35 @@ class ConsumablePresenter extends Presenter
'searchable' => true,
'sortable' => true,
'title' => trans('general.model_no'),
], [
'field' => 'item_no',
'searchable' => true,
'sortable' => true,
'title' => trans('admin/consumables/general.item_no'),
], [
'field' => 'qty',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/components/general.total'),
'visible' => true,
'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'remaining',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/components/general.remaining'),
'visible' => true,
'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'min_amt',
'searchable' => false,
'sortable' => true,
'title' => trans('general.min_amt'),
'visible' => true,
'formatter' => 'minAmtFormatter',
'class' => 'text-right text-padding-number-cell',
], [
'field' => 'location',
'searchable' => true,
@@ -74,12 +103,6 @@ class ConsumablePresenter extends Presenter
'title' => trans('general.location'),
'formatter' => 'locationsLinkObjFormatter',
], [
'field' => 'item_no',
'searchable' => true,
'sortable' => true,
'title' => trans('admin/consumables/general.item_no'),
], [
'field' => 'manufacturer',
'searchable' => true,
'sortable' => true,
@@ -99,42 +122,12 @@ class ConsumablePresenter extends Presenter
'title' => trans('general.purchase_date'),
'visible' => true,
'formatter' => 'dateDisplayFormatter',
], [
'field' => 'min_amt',
'searchable' => false,
'sortable' => true,
'title' => trans('general.min_amt'),
'visible' => true,
'formatter' => 'minAmtFormatter',
'class' => 'text-right text-padding-number-cell',
], [
'field' => 'qty',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/components/general.total'),
'visible' => true,
'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'remaining',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/components/general.remaining'),
'visible' => true,
'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'purchase_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.unit_cost'),
'title' => trans('general.purchase_cost'),
'visible' => true,
'class' => 'text-right text-padding-number-cell',
], [
'field' => 'total_cost',
'searchable' => true,
'sortable' => true,
'title' => trans('general.total_cost'),
'footerFormatter' => 'sumFormatterQuantity',
'class' => 'text-right text-padding-number-cell',
], [
+1 -1
View File
@@ -202,7 +202,7 @@ class LicensePresenter extends Presenter
'switchable' => false,
'title' => trans('general.checkin').'/'.trans('general.checkout'),
'visible' => true,
'formatter' => 'licenseInOutFormatter',
'formatter' => 'licensesInOutFormatter',
'printIgnore' => true,
];
+5 -34
View File
@@ -61,15 +61,6 @@ class LocationPresenter extends Presenter
'title' => trans('admin/locations/table.parent'),
'visible' => true,
'formatter' => 'locationsLinkObjFormatter',
], [
'field' => 'users_count',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.people'),
'titleTooltip' => trans('general.people'),
'visible' => true,
'class' => 'css-house-user',
], [
'field' => 'assets_count',
'searchable' => false,
@@ -107,7 +98,7 @@ class LocationPresenter extends Presenter
'titleTooltip' => trans('general.accessories'),
'visible' => true,
'class' => 'css-accessory',
],[
], [
'field' => 'assigned_accessories_count',
'searchable' => false,
'sortable' => true,
@@ -117,34 +108,14 @@ class LocationPresenter extends Presenter
'visible' => true,
'class' => 'css-accessory-alt',
], [
'field' => 'components_count',
'field' => 'users_count',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.components'),
'titleTooltip' => trans('general.components'),
'title' => trans('general.people'),
'titleTooltip' => trans('general.people'),
'visible' => true,
'class' => 'css-component',
],
[
'field' => 'consumables_count',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.consumables'),
'titleTooltip' => trans('general.consumables'),
'visible' => true,
'class' => 'css-consumable',
],
[
'field' => 'children_count',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.child_locations'),
'titleTooltip' => trans('general.child_locations'),
'visible' => true,
'class' => 'css-child-locations',
'class' => 'css-house-user',
], [
'field' => 'currency',
'searchable' => true,

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