Compare commits
1740 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1abd669de5 | |||
| ac9df2fc08 | |||
| eba24b9242 | |||
| edd61705dc | |||
| 3f20e29901 | |||
| 36ae162626 | |||
| 00f7cb9dbb | |||
| 1ca3dc26eb | |||
| 2f3be267b3 | |||
| 5b8f6910fb | |||
| 9fe26ba814 | |||
| 5e97ed1c7e | |||
| 947fb7af7a | |||
| 44bcc157e5 | |||
| 278bf3da13 | |||
| 446bc81d3a | |||
| 9527aac242 | |||
| c57f1f9d7d | |||
| e372527d13 | |||
| 96be1e1275 | |||
| 8ce17d0585 | |||
| 6af1eaa4e4 | |||
| da01487301 | |||
| 708d7b5fc5 | |||
| 62b5a159a9 | |||
| a6d04509a5 | |||
| 0071596274 | |||
| 59f66051f8 | |||
| 9f1e59cf78 | |||
| f1f68b8ef6 | |||
| f22c3cdda9 | |||
| 5e15cc3bbe | |||
| a6690493b0 | |||
| 17a6335d13 | |||
| ca57f6de85 | |||
| aefaabdb1a | |||
| 9211c8d3b1 | |||
| eff1980df5 | |||
| 1553ba5630 | |||
| ec24120d2a | |||
| 50df750202 | |||
| dab4aced48 | |||
| 1774952312 | |||
| d66d6e70a6 | |||
| 4635e9269d | |||
| 574867536d | |||
| 5488a4d118 | |||
| e34f3c7c2c | |||
| ceaff7b645 | |||
| d27a025347 | |||
| 2b2853a183 | |||
| a25263f868 | |||
| 4b9727067b | |||
| 00fc392a12 | |||
| 1da90fe1ec | |||
| 25ba50d6f7 | |||
| f22e99aec8 | |||
| f027fd5f21 | |||
| 37a038c24f | |||
| 3a8f825de5 | |||
| d2df83cf2f | |||
| d481850d4c | |||
| 6c55e2bd9d | |||
| 2fd357c346 | |||
| 0a5e58201a | |||
| d687b20467 | |||
| 7dbcedad40 | |||
| b6e8d28ed3 | |||
| 85ce47f5bb | |||
| 55c98cc27a | |||
| 422f3ec81e | |||
| 54fb91c03b | |||
| 6df9742664 | |||
| f23a221750 | |||
| 4637accb51 | |||
| 74f067d893 | |||
| 43773954cd | |||
| 30cafef9f2 | |||
| 251f2d82b3 | |||
| e905550778 | |||
| adee99db34 | |||
| eda2eb2283 | |||
| a7123a04ba | |||
| 8a562f1d15 | |||
| d4861a74df | |||
| 8971cc4b8b | |||
| bca6dd41d2 | |||
| 221c4eeb0c | |||
| bbb1fbfbe8 | |||
| 5a874a90ac | |||
| 1c14c2fdef | |||
| 73a038afd4 | |||
| 4d55765e28 | |||
| 2b43f3cb84 | |||
| 52c4885335 | |||
| aa5fe52e89 | |||
| ce107dd688 | |||
| 72affd7a5b | |||
| ba4c51dd68 | |||
| 294fb1f774 | |||
| a846afe733 | |||
| 5fb3cea0bb | |||
| 4ae89c23cd | |||
| 3d32fe662b | |||
| 468674a517 | |||
| ebe4354a85 | |||
| f47bc5ea7d | |||
| 427615f627 | |||
| 829b560794 | |||
| f97a15c5c3 | |||
| 25fcf523e3 | |||
| c1be94c4ad | |||
| 3a05d72124 | |||
| 7ec44e46ce | |||
| 060b17df01 | |||
| 74c78d7577 | |||
| 1ef0c1adac | |||
| c2e649e2bf | |||
| 196db9718e | |||
| 9f5b264e04 | |||
| 3825f5fb61 | |||
| e60dbc883c | |||
| bbbfa91db9 | |||
| 5ec8e2da66 | |||
| 9e59bd5687 | |||
| 1d26ccac4e | |||
| 0e2526f627 | |||
| dd9e9c7a6d | |||
| e19922abd0 | |||
| d27bde6047 | |||
| 61f76dedc6 | |||
| 06737f45ad | |||
| 65e8765bdd | |||
| c6a0212384 | |||
| e03614d91b | |||
| b82770d0a8 | |||
| 55e1326164 | |||
| b0aff68c8b | |||
| 6a99855c8c | |||
| 665aa6eb23 | |||
| 42caacbaf9 | |||
| 3531256c3f | |||
| 9a0db72eb4 | |||
| e11a42cf68 | |||
| 114769c2d9 | |||
| 9594596b8a | |||
| 69cf697aa3 | |||
| 45dbe5cb77 | |||
| a1ff35f6ce | |||
| 077a6949e2 | |||
| 44022f07ca | |||
| 30c1e1e86a | |||
| 9a90813877 | |||
| 1113218c6c | |||
| 2556c80250 | |||
| 8f8a5c639b | |||
| 9e9c37c1e8 | |||
| 6cbdbcb1f1 | |||
| c8835bf5db | |||
| 6dfedac7a7 | |||
| 83794eaf33 | |||
| bd1f43f9ee | |||
| 66ffe21ce2 | |||
| f2e86b7d30 | |||
| 5251e6787d | |||
| 856aee0a72 | |||
| 6b4c71f966 | |||
| dd6d040da5 | |||
| 203b60383f | |||
| 61ced0b221 | |||
| ae7675fee0 | |||
| 66ed26fbf9 | |||
| 98662c2a77 | |||
| 7099358985 | |||
| 9a706b3e3e | |||
| 71c9b03779 | |||
| dc7b9315b5 | |||
| 6c17b141db | |||
| 5d2cca855e | |||
| 61e10be04d | |||
| 20d5587851 | |||
| d8eccf03f1 | |||
| 6e40b58dc5 | |||
| 30dd8bcf2b | |||
| f0a11be0b8 | |||
| b8882fa00e | |||
| af337b7018 | |||
| f60267d208 | |||
| a0c844f4f6 | |||
| 7b84b92e72 | |||
| ce338c632d | |||
| d9f70c16f7 | |||
| d0299de898 | |||
| 9380c9ec81 | |||
| 941582ac2a | |||
| 04560b4475 | |||
| 0b30ad0da2 | |||
| cb6ea2c6fb | |||
| 89a5bbb10e | |||
| 2f59bb74cd | |||
| 6c6a3649ea | |||
| 05b97db747 | |||
| 543e4c0666 | |||
| e28619f769 | |||
| 4d8c2d3f4e | |||
| f53eeb8b33 | |||
| aba6d9b338 | |||
| cd5bef414c | |||
| 4f2d2ae4b8 | |||
| 1bd0ab7389 | |||
| 8799276c6e | |||
| 672aabf4ac | |||
| 796d6909d5 | |||
| a3dea99bbb | |||
| fc351a1896 | |||
| d9164281ab | |||
| cbb5b6e846 | |||
| 08bd39dbba | |||
| 430808e180 | |||
| 6976dc2b26 | |||
| 27063d5bae | |||
| 5be86b9dbb | |||
| afc78524fc | |||
| eb33a2451f | |||
| 891a0a0965 | |||
| 50f0797850 | |||
| 36cdf0e0be | |||
| d9cc3c3ec7 | |||
| 069a1608de | |||
| 60accfd601 | |||
| b1f2051b43 | |||
| 233e4af7f8 | |||
| dc1b808a28 | |||
| 91a423e60e | |||
| bd03a6d206 | |||
| d87da78eb5 | |||
| f3e82c2c80 | |||
| 569f05a99e | |||
| ece7c22df9 | |||
| 4eefd39172 | |||
| daae5d6859 | |||
| df76769a29 | |||
| fe72639925 | |||
| c3e6e1144f | |||
| cacb5d62dc | |||
| a8b47a55bc | |||
| 3159fdec9f | |||
| ea990a5381 | |||
| 134183ef16 | |||
| 67ab2536bc | |||
| 756a2ac25c | |||
| acaceb4103 | |||
| 7e3d66ec53 | |||
| 1ca9bb5aa8 | |||
| c641b733e1 | |||
| 16cf6bc852 | |||
| c51b7d7104 | |||
| 5c0ca92fd7 | |||
| 241e9bc253 | |||
| c8820adb56 | |||
| 0f4c6dd5b0 | |||
| f8ab9f62f6 | |||
| 217ed03b8e | |||
| 77e6058e4c | |||
| 4a60026162 | |||
| 3621292a0e | |||
| 6c296ccf8e | |||
| 6df1c36011 | |||
| 924da00f3e | |||
| 44dae22a3c | |||
| d35e251d6e | |||
| e19d2d6ec9 | |||
| 871255f28c | |||
| 9044aa4ed9 | |||
| 60c7efae3c | |||
| 48fc6ca60e | |||
| 7ac315e1eb | |||
| 374c6845d6 | |||
| c5cbe37007 | |||
| a2346e4666 | |||
| 2479ccc4c6 | |||
| 64dd8f5d65 | |||
| 47420a802a | |||
| 5cdb2b7163 | |||
| d4c080c7e4 | |||
| 065a47a446 | |||
| 5bd9ecb8df | |||
| 1cdec61be6 | |||
| b0ddb26e73 | |||
| 181bafd012 | |||
| e054fc1ef1 | |||
| 9d9ad86dd5 | |||
| afe4e5d62e | |||
| 52950f1322 | |||
| 026c80992e | |||
| 0ee2b74ff3 | |||
| 3a0f7eca54 | |||
| f4d530b4b1 | |||
| 4ccbfb56a4 | |||
| d02904c9a3 | |||
| c8279c0b99 | |||
| f4f184e115 | |||
| b2a86e312b | |||
| 9d56617caf | |||
| de7b8940fe | |||
| 09e94ec176 | |||
| 832ceeba56 | |||
| ea7c3c8485 | |||
| bc36c8074e | |||
| 9fccafa3ac | |||
| fa083098fc | |||
| 7688c437c0 | |||
| 697ac83040 | |||
| a742105c21 | |||
| 7a76ec9e02 | |||
| b2a0e7958b | |||
| 99439f0a5c | |||
| ef91c8123e | |||
| 5eb5742b3d | |||
| 296cf3e34b | |||
| e98c3f92c1 | |||
| d202dfc225 | |||
| 6202f6157a | |||
| b1e8e5389b | |||
| 95f6381da4 | |||
| b07e3b4a91 | |||
| 86bd9a2674 | |||
| 29a36839aa | |||
| 85cb7c92e7 | |||
| e827bc9a07 | |||
| a6f19a1657 | |||
| 6229d0c616 | |||
| bc6c969f21 | |||
| 8f4ede7785 | |||
| 877adb082c | |||
| 90818bb147 | |||
| f767a94c84 | |||
| 89e50b94d3 | |||
| c4d97d095f | |||
| 67fb3f10d5 | |||
| ea8d390596 | |||
| cff382605c | |||
| 52af8afac2 | |||
| 03b0268dc2 | |||
| c09e93e288 | |||
| 694e3b7f3a | |||
| 32c367090b | |||
| abcfe2b757 | |||
| f7687008b7 | |||
| b156264684 | |||
| 3f9a80942e | |||
| dc62e393c3 | |||
| 46be0f6610 | |||
| dd0a16c3d5 | |||
| a15ed6eaee | |||
| 3005565bba | |||
| cf45e7536f | |||
| 1d97d95c10 | |||
| 4a1b1675cb | |||
| 8c5249ba4b | |||
| b936591240 | |||
| 76e664d647 | |||
| 0253c2a756 | |||
| d27613f55c | |||
| ca8d478e87 | |||
| c63c17d49f | |||
| 801e58d52e | |||
| 06e9625c64 | |||
| 5800e8d8e9 | |||
| 623aa58163 | |||
| 45cfec5b29 | |||
| 5a9a231359 | |||
| 1736bf5510 | |||
| ee8931f886 | |||
| 1a1b891309 | |||
| 2eaac3d381 | |||
| f03249898a | |||
| 0981cfa902 | |||
| 37fbcfa22b | |||
| 0ee441a976 | |||
| cf8de3baa9 | |||
| 404ee238a3 | |||
| 5a5d171ba2 | |||
| aadee068b3 | |||
| a46e2ebfd8 | |||
| f710b1aac3 | |||
| f6fe6e70b9 | |||
| bed8861179 | |||
| 180d7b1b5b | |||
| 386416ee5d | |||
| 6b5aa91f3d | |||
| e80b80f5d1 | |||
| 9e35441281 | |||
| e28ad50bec | |||
| f48c5ee252 | |||
| 98a94dec29 | |||
| 7d95e7765d | |||
| ee75b30683 | |||
| ca9d4e3155 | |||
| 633bcbb6c4 | |||
| 2d4af61e6c | |||
| 45329912e6 | |||
| b9d56a8ecc | |||
| 91c1e53e52 | |||
| 73a87a8ea8 | |||
| bb0a614c39 | |||
| f11ea79406 | |||
| e817b20840 | |||
| 516f766a44 | |||
| f5791c79a5 | |||
| f6a1a76095 | |||
| bbb9145744 | |||
| 194853d860 | |||
| 92670d5711 | |||
| 8a2ea971e1 | |||
| 8d924b60d7 | |||
| 34595c266d | |||
| 638ae9bdd5 | |||
| 713ce7836f | |||
| 093c6652a8 | |||
| 17f0ac1eae | |||
| 43616d1874 | |||
| 9dc4f2ca80 | |||
| 73e3ac7dd8 | |||
| 8ff639913d | |||
| 45419586fe | |||
| d8a480b2a8 | |||
| 29d87246a2 | |||
| 58e638d3cb | |||
| b52380f376 | |||
| 4ae74fb7f6 | |||
| 7d1acd3d79 | |||
| 12e107a71b | |||
| fba72e1e8d | |||
| 7bbee053c6 | |||
| 6ea1a3bacf | |||
| 603afe4466 | |||
| 037ee8c07a | |||
| df1cef59d5 | |||
| 3fcd196c04 | |||
| 8ee5e7cd0a | |||
| 1ec85063ee | |||
| 92ba889cae | |||
| f17162c2e2 | |||
| fb233c0aa4 | |||
| 369c819a27 | |||
| f1eb4bd3a5 | |||
| 2f828683da | |||
| 13db151297 | |||
| bb95c231e5 | |||
| dcea14fb99 | |||
| 282fed27da | |||
| cf3ffe9c74 | |||
| 5d01a06245 | |||
| 02cdda56e2 | |||
| ffecd97665 | |||
| 779cf9418e | |||
| 34b4452645 | |||
| da1c4c23e6 | |||
| a5d0a21757 | |||
| 29454f7288 | |||
| e271711c5b | |||
| 4c78da3bbf | |||
| 71bab2c315 | |||
| fceba13b03 | |||
| 8ac3937bf4 | |||
| 1c1729854e | |||
| 14c78d9065 | |||
| b1cb9259da | |||
| 7d2af61989 | |||
| 03b5c2e246 | |||
| 33d5d5e24f | |||
| 3df2a4a70b | |||
| 6b41970e97 | |||
| 92eb6eb1b6 | |||
| 206238e83f | |||
| df882bbcbc | |||
| 6c1c3a99dd | |||
| 54067ec449 | |||
| 4c11e97922 | |||
| 8df9007a8e | |||
| 702b944698 | |||
| 172d24fd3c | |||
| 28b450fd3c | |||
| 485caf1d92 | |||
| 29cd75a6d2 | |||
| b3fe10baa8 | |||
| 093cc9faf0 | |||
| be4e809254 | |||
| dc5e15f919 | |||
| ad7b291062 | |||
| b54c1caa74 | |||
| c3cf123189 | |||
| 3a2900621c | |||
| 639cbf6d53 | |||
| e03b5754a8 | |||
| 4ce86a061f | |||
| fa6e170feb | |||
| 51f72daba1 | |||
| a130033480 | |||
| ef95ede833 | |||
| d06e5f25b0 | |||
| 2777ac96cc | |||
| fd42f1ef24 | |||
| 8b3ff5a82d | |||
| 482ebfbb68 | |||
| 67c4fa2966 | |||
| a3389a31cd | |||
| 8d74a976a1 | |||
| 6d104251b3 | |||
| f16c79bb9a | |||
| 1fe22e4b7b | |||
| c7fa2c04ad | |||
| 8ca882d1c8 | |||
| 5d368990dc | |||
| 4adbd7af4c | |||
| 1935a4aca3 | |||
| c4d96f6ea3 | |||
| 986d5641f6 | |||
| e163d5cfc7 | |||
| b1e7c772ae | |||
| dce1854ac4 | |||
| c4b4923ff8 | |||
| c20d10d4f2 | |||
| b0479d543d | |||
| 81704c1d40 | |||
| d3798bf251 | |||
| 4bb7c1701f | |||
| 5fd0f56258 | |||
| 37d7e89e93 | |||
| 3ab197075a | |||
| 12e8ac8b41 | |||
| 6783dc1312 | |||
| b489c71fa2 | |||
| cf5f6f9b13 | |||
| 860432acc5 | |||
| c9f7847fb3 | |||
| 6fad085a7d | |||
| 4b23ef4021 | |||
| bb96a190fd | |||
| e1eb457f3d | |||
| 51025aad57 | |||
| 14c4765be2 | |||
| 3afe996755 | |||
| 0891bd747a | |||
| f2693ee957 | |||
| 0327e71f0f | |||
| 69c2cf2c4f | |||
| 9f02be0823 | |||
| b5553af8ed | |||
| 4d6f4303f5 | |||
| 34f1ea1c0e | |||
| e3561ad38e | |||
| a7ccf0efff | |||
| f422c2ecad | |||
| db9c435ae0 | |||
| a53f89cd2c | |||
| 280c03dcad | |||
| e70fb42f87 | |||
| f633dbba64 | |||
| cc0f2d7074 | |||
| a820f248c8 | |||
| 6a6272ace3 | |||
| bcb747f886 | |||
| 771c85e347 | |||
| e5c358a1fe | |||
| 52c906f6b8 | |||
| ca1555d962 | |||
| 0d4f13219b | |||
| 7fdbbc846e | |||
| dbbbb103a0 | |||
| 2182ea1ce8 | |||
| f2cc9ec1dd | |||
| 54b24434e1 | |||
| 653ad562a4 | |||
| 7743b03129 | |||
| 84a601f364 | |||
| 88d131666c | |||
| d691f3b315 | |||
| 00a9d5f33e | |||
| eb0fd2f519 | |||
| 81efaa7481 | |||
| 2539c9e697 | |||
| 3dfd471fa4 | |||
| 4119526889 | |||
| 6b3346d90c | |||
| 312ce51de6 | |||
| 09914f508f | |||
| 45eda0f611 | |||
| de088d452f | |||
| 2f18430ce4 | |||
| 8d67e02d63 | |||
| 1b85eea28e | |||
| fb9a5f928f | |||
| 4459483862 | |||
| a0cf7ecc98 | |||
| 8e35a56386 | |||
| 30f738646e | |||
| 55281313d8 | |||
| 786799225c | |||
| c137fafa97 | |||
| cb22a3d556 | |||
| c7accb4599 | |||
| 72c85f93b6 | |||
| c1d5b8713b | |||
| 8310b91e00 | |||
| 71b5bf2eef | |||
| ab8b40745e | |||
| 16ec47573b | |||
| 556d0b44a3 | |||
| 0734d5b0b6 | |||
| f158a369a4 | |||
| bdbfb0f2a1 | |||
| e5653eaa93 | |||
| 3c4098038d | |||
| 8841e21dc9 | |||
| f5e03b264f | |||
| eb09a99eb0 | |||
| dc418a7033 | |||
| 15cc4345ab | |||
| 5272824d85 | |||
| 9bce0f2ff7 | |||
| d2e7e11dca | |||
| 6823aabf92 | |||
| f2dddc1226 | |||
| 957becabb9 | |||
| 7df03722ee | |||
| 4642f50d6b | |||
| 2decc3d6d3 | |||
| 2adc4ffa96 | |||
| c8fbf7640c | |||
| 46779ca865 | |||
| 86661e79d1 | |||
| b2a5d86e30 | |||
| d7f0ee49b7 | |||
| 5b86ee7291 | |||
| ad2ba252ee | |||
| 17ef20ea92 | |||
| 8c327e6523 | |||
| 386b2839e8 | |||
| 934593e0b6 | |||
| a7aa178f24 | |||
| 69122034e7 | |||
| 1117f4289d | |||
| 97bc4a092f | |||
| d942b8f1fb | |||
| 49dc9767b6 | |||
| 482965197d | |||
| 410b547f3c | |||
| f769e8247f | |||
| 2b4a536f85 | |||
| 92ae069629 | |||
| 6f40b21986 | |||
| 3084521521 | |||
| 4f12c86e74 | |||
| 204de99a64 | |||
| fd929f5dd9 | |||
| 7e9c8ba290 | |||
| 6f639f7bf0 | |||
| 3594ed67d1 | |||
| d36a06d8e1 | |||
| c816b960b5 | |||
| 5b02a43957 | |||
| 4913e56086 | |||
| 4d00bb98d1 | |||
| db2baae758 | |||
| fdecdf4b15 | |||
| 5c1d4aff23 | |||
| bf0edcb92e | |||
| 39fa8ef3c0 | |||
| 9e8a369bc8 | |||
| 3f3fe8935f | |||
| 82387630c7 | |||
| 16c5033514 | |||
| 46ffaee1e4 | |||
| d936f92a7d | |||
| b424ddf42d | |||
| b3d5a893fc | |||
| 69ea6eebae | |||
| 0892c34125 | |||
| 52e14d501f | |||
| 4d093160fc | |||
| 0bcca99573 | |||
| 63516c4a4f | |||
| 19fb79ffff | |||
| 02835de13d | |||
| 55b004d53d | |||
| c1b72a8ce6 | |||
| fa0bea87e6 | |||
| c94a7613ca | |||
| d146426dd8 | |||
| 1e1782c232 | |||
| dab5874fd7 | |||
| 4850227c04 | |||
| eb9a654cc3 | |||
| 4224bc0c43 | |||
| f893b23129 | |||
| 8c65880504 | |||
| 53cadf80fa | |||
| e177993bcc | |||
| 6a7f3ecc2e | |||
| 39cc99c89b | |||
| 25480293dc | |||
| 8b3bfc6bc9 | |||
| 19cff25300 | |||
| 848e1fe1f6 | |||
| fe147adec3 | |||
| 103809b65f | |||
| a398496dd4 | |||
| 839db8ef44 | |||
| bfd0530597 | |||
| 494ec5cd9c | |||
| fc61a4b88d | |||
| 50d8b02f8b | |||
| 860764a436 | |||
| 52d6a8990a | |||
| 87de67e4a9 | |||
| 8356b57fb4 | |||
| 3f04afee5c | |||
| 2117f61e8c | |||
| d40604b574 | |||
| 76129e9011 | |||
| 9c8411c7ff | |||
| c661d732b3 | |||
| fbe9daace6 | |||
| 651001bf6e | |||
| 9167f8a3ba | |||
| 6dc9ccffcd | |||
| 4b4e3badb7 | |||
| fe4dd23d39 | |||
| de6d71cc3b | |||
| 9e44052709 | |||
| 2d112f227a | |||
| bd8737d986 | |||
| 4b6d236eb7 | |||
| bf058bd5c6 | |||
| dfaf01e8aa | |||
| 2888dd6fd8 | |||
| 2e92ee8eee | |||
| 14b6a75507 | |||
| 2484a9db2c | |||
| bfc30794c5 | |||
| 27bc7a847b | |||
| 2a71877bec | |||
| 30bd920497 | |||
| 1d5b48b88d | |||
| 4295bad12f | |||
| 3a2eeaea7a | |||
| 12418ae91b | |||
| 783a24eb68 | |||
| 3f5c5cbe82 | |||
| 2439758ef3 | |||
| ac4aa97103 | |||
| 0bc93c6a1e | |||
| 685f1cbfb8 | |||
| e2d1e6b0c5 | |||
| 56cb9a0f4e | |||
| c8c81a360c | |||
| bdd43b7134 | |||
| c50d5a678a | |||
| 96b3af7cbc | |||
| 9e7bbc968d | |||
| 5fc6771543 | |||
| 0d049a0be7 | |||
| 01c24ab4cd | |||
| 155f5f35cd | |||
| 7ad6caf30a | |||
| ac8aab0043 | |||
| 14ddf36d46 | |||
| 25f1167c9d | |||
| 420225c2d5 | |||
| 45f5eaac5b | |||
| 5229dd65ce | |||
| cfe39afc11 | |||
| 2aa3ce15bd | |||
| c9873da732 | |||
| 8dd71f99cc | |||
| ab45975883 | |||
| 7f38ca239e | |||
| c3b982e759 | |||
| e330e80c46 | |||
| f0836d4d3a | |||
| 1289920217 | |||
| a6a58094c9 | |||
| 424cbd3248 | |||
| e59b9627c7 | |||
| f080c0cdcd | |||
| 29bda2ef7d | |||
| e8d9701a26 | |||
| 1d64692fd6 | |||
| 6f195cb8ec | |||
| 4c02a63acc | |||
| 0fc9fc7516 | |||
| 4450351b75 | |||
| 9bb15aaf1b | |||
| 65dd729e19 | |||
| c21142605d | |||
| 86e274faa3 | |||
| 5e8c129c7f | |||
| ab3b5ca4ef | |||
| 60a5afd752 | |||
| 9d0ea857fe | |||
| f763aea4fc | |||
| e16c04250e | |||
| ad99aa460b | |||
| e47f64f62d | |||
| c6d9da1571 | |||
| ab561d1ce8 | |||
| f39ba0136c | |||
| df60045bfe | |||
| 5e122f780f | |||
| eefe377159 | |||
| 20920c262d | |||
| 870612be1c | |||
| 266424ff0e | |||
| a8d48b758e | |||
| 67a8e0b5c6 | |||
| 7b7d424962 | |||
| a4e959818a | |||
| c3a71cc182 | |||
| da03cfdbe5 | |||
| 2b137d76fa | |||
| 81b8c111ca | |||
| fce98b9ca4 | |||
| c0dcae16f7 | |||
| c604f08749 | |||
| da21424416 | |||
| b5c83721ad | |||
| 9b21fca1a0 | |||
| af94b07771 | |||
| 0d23d28a65 | |||
| 710370ac24 | |||
| ed0a441e4d | |||
| 24e87cc0bb | |||
| 460693c153 | |||
| f54a94bd4c | |||
| a19b86add0 | |||
| 570944a48b | |||
| 5829b02323 | |||
| 5567a1e9ac | |||
| fa5016713f | |||
| f28a82de71 | |||
| 7c2fae7b9d | |||
| 70934e54cf | |||
| f6ad275030 | |||
| 6666a78936 | |||
| bbb2cdcceb | |||
| 6b6e18695f | |||
| b63962e90b | |||
| 4434de6241 | |||
| a2bca0e358 | |||
| 6d572424ac | |||
| d371d14c1f | |||
| 72eda1e909 | |||
| 7dbf8a8a8e | |||
| 133fdd7a37 | |||
| 0849262243 | |||
| 17095feb33 | |||
| f42ae46338 | |||
| 37ebf1827f | |||
| e65252725a | |||
| 6f53f2ac64 | |||
| e2679852ce | |||
| deaba46e1c | |||
| 989dab6259 | |||
| adacdc038d | |||
| f0aefaac42 | |||
| 1aeaa0094a | |||
| 6d3fa12f37 | |||
| 052f1eedd0 | |||
| 858da800be | |||
| 954cac3af7 | |||
| d0f171ebc6 | |||
| 90cf612ac7 | |||
| 802b5863ab | |||
| 4baa949a99 | |||
| 3bed04a6d3 | |||
| d548b800d5 | |||
| f7f199d929 | |||
| 5519fddb78 | |||
| a9ed748fb2 | |||
| dcba2bfd25 | |||
| 72c91ead8b | |||
| 774d0aa90c | |||
| 2eea67ce34 | |||
| db1c44f921 | |||
| e11287ec25 | |||
| 4f10adfb76 | |||
| f22803c59f | |||
| a72d4e5dc1 | |||
| 08f9aae8ae | |||
| 43c32fa1bf | |||
| 5afe024644 | |||
| c01bdb42fc | |||
| e3ef8d295f | |||
| ce1d677cdc | |||
| df5cacf8a2 | |||
| bb2c73348d | |||
| 4327653d70 | |||
| 5f7f4c9b91 | |||
| d44202e55b | |||
| df95447ea4 | |||
| 01852c7188 | |||
| 79c5697042 | |||
| 65e21faa3e | |||
| 658ba092e2 | |||
| b221d99e7b | |||
| b7af049589 | |||
| c2d863da99 | |||
| 6f9ba6ede4 | |||
| df4e6a0023 | |||
| d60fa65f85 | |||
| 8081a82fe4 | |||
| f42e5d5292 | |||
| 5a3f5b03d0 | |||
| 721902c2d4 | |||
| a450530c74 | |||
| 2b4886f37f | |||
| b45de3e17f | |||
| b2eea3e5a5 | |||
| f411c0fdd8 | |||
| 74d8431d01 | |||
| 3ea0cd75a5 | |||
| 5f6c746d25 | |||
| 1f2d30ebf4 | |||
| e6b366020a | |||
| 6dd6b45829 | |||
| e5800a2dac | |||
| 0d3d172108 | |||
| 86677b5f13 | |||
| 3f5b94f8ad | |||
| cf8cb8521b | |||
| ccd00caa70 | |||
| 57010b4c23 | |||
| 545a185614 | |||
| 1572e339f9 | |||
| 7782e5cc93 | |||
| bcdda551b3 | |||
| bc66c0f223 | |||
| 1b8c7ff4ec | |||
| 3bb81d1e4d | |||
| 756c44fcba | |||
| befa4428d0 | |||
| 60c678680a | |||
| 8bc9688d71 | |||
| aa8af2220c | |||
| b124b9af4d | |||
| ae403da8c1 | |||
| b5b8777c94 | |||
| 850f85ff59 | |||
| 84cc88831d | |||
| f4f9b165a7 | |||
| 3222d4c8df | |||
| 3173ead2e7 | |||
| 040f826c52 | |||
| 89d733d442 | |||
| df49e8350f | |||
| 3ced85080a | |||
| 0611ab9b4c | |||
| f450cafe3e | |||
| 1f29eb1875 | |||
| a4e5ae0938 | |||
| 77dacfcc30 | |||
| 0d9b6eaf71 | |||
| 7060ffaf34 | |||
| 02a37e2f89 | |||
| 9c1b1bc2b5 | |||
| b34156ca25 | |||
| 61bdb57b5d | |||
| 9df84e235c | |||
| 566ba4783e | |||
| b41b4b1732 | |||
| ccf9457c45 | |||
| 53aabdab66 | |||
| 8ff85c952e | |||
| afe1cb8234 | |||
| bd42505799 | |||
| 6c735c97c6 | |||
| 31a57cdf14 | |||
| 7ebbef25e7 | |||
| f836342194 | |||
| 5cf1a6c300 | |||
| bd506820b7 | |||
| 5815607924 | |||
| 9b40c9788f | |||
| 67b5e9093e | |||
| 57d1c036ec | |||
| 71722b753d | |||
| a2625c889a | |||
| c98b9da612 | |||
| 675717ff82 | |||
| 83ef7c6fe8 | |||
| 5f4c964309 | |||
| 66ba96d531 | |||
| d67b2da064 | |||
| e45fd4088f | |||
| 7e4a0eedf0 | |||
| 3f812f696d | |||
| 633249b08a | |||
| 21c3b1fbd2 | |||
| e9e6f925bf | |||
| 828b84084d | |||
| a6a0bfacc2 | |||
| c4b7e77498 | |||
| 91c7180bfd | |||
| b368acf941 | |||
| 7c39f516b9 | |||
| ce1ddcfcee | |||
| 945e8b402f | |||
| 5ed2bd0fb7 | |||
| bc908b854d | |||
| 2067b1138a | |||
| 1ffbdee156 | |||
| bd2812cac1 | |||
| f2a5eac256 | |||
| b4e647dbd1 | |||
| 530291f81c | |||
| de18e449a6 | |||
| dce19e0bea | |||
| 1f586d3102 | |||
| e5d01170d2 | |||
| 393dc51167 | |||
| 984cc7a4f2 | |||
| 0f11963127 | |||
| d8378f2a10 | |||
| a0a5480c97 | |||
| 3391108551 | |||
| 52551dad0f | |||
| 321414f6e3 | |||
| 7787fe42c8 | |||
| 3b66912742 | |||
| 278a25c63b | |||
| 0d124bb5a1 | |||
| 417caae589 | |||
| 3d306aacc5 | |||
| ea4ecaea03 | |||
| 6c90f9e395 | |||
| ddf81ba135 | |||
| 8ebb41caa6 | |||
| faf48b1684 | |||
| b8232d205b | |||
| 62745923cf | |||
| 090466123f | |||
| 38a3e36cd6 | |||
| e8dc634a40 | |||
| 0d0984a400 | |||
| 8640cad033 | |||
| dc29717623 | |||
| 814914924f | |||
| c7083488b2 | |||
| 4b4d383509 | |||
| b9986033cc | |||
| 3680e04817 | |||
| 21e23baa37 | |||
| fcd130ae15 | |||
| 8b52d5da85 | |||
| d1dffb84dc | |||
| 541350916d | |||
| 01afa9a749 | |||
| 57f5d4a570 | |||
| 4588393b76 | |||
| 0fd99d410e | |||
| 002fd4ce30 | |||
| 7b4ecb275f | |||
| 2df5d3a8ff | |||
| 7070bad53b | |||
| da62d6af26 | |||
| d0d4d14787 | |||
| 09d69b214b | |||
| 0e2aaebda4 | |||
| ec2c58163f | |||
| a28bee86ba | |||
| fb64892971 | |||
| 95ff692b14 | |||
| 8003615b1f | |||
| 948dc3c974 | |||
| 1afb724606 | |||
| 451281d833 | |||
| 485f11c945 | |||
| dbc79655b0 | |||
| 02f6aa6161 | |||
| 07c5264b41 | |||
| 7c178a6a78 | |||
| f56d53d7c1 | |||
| 4cd4a936d8 | |||
| 7bae4c39c6 | |||
| d55d95bbea | |||
| 5e48d56561 | |||
| 6a5098fb0c | |||
| 4e835e1772 | |||
| cce8cb4f5e | |||
| 8aed26aab1 | |||
| 01d5d4c2c8 | |||
| 592385cb07 | |||
| 85123b3e66 | |||
| 0fcf223960 | |||
| bf0bd06f20 | |||
| f07b0b6bd7 | |||
| 717b26c834 | |||
| 8bb8eab69b | |||
| 693d1c9452 | |||
| b049bb1d5c | |||
| c5c6b3bbc6 | |||
| 1df56a7cab | |||
| 3f5cc2507d | |||
| 5a85424295 | |||
| a53a8cca74 | |||
| 3fdee881f9 | |||
| a289dfaf88 | |||
| 8abd359b5b | |||
| 9359809b4f | |||
| cde5502f94 | |||
| 04e0a9d4a5 | |||
| 28ec0b8ebb | |||
| 37dfecf098 | |||
| 9d8ce872a4 | |||
| 07880dfe50 | |||
| 7eed9f8542 | |||
| a2e70dd6b2 | |||
| b9aeded957 | |||
| 027361f079 | |||
| ff10d1540f | |||
| 0f63fa23e0 | |||
| 22ef569e5e | |||
| f3663f0983 | |||
| 112ddaf55b | |||
| bda6fdf09c | |||
| a62198f33f | |||
| 4b0bfc52b4 | |||
| 78868813b1 | |||
| e8be178ac7 | |||
| 695428cd44 | |||
| 9ae779e442 | |||
| db92febdc7 | |||
| 5cf10cec34 | |||
| 7939c691f7 | |||
| ea2d54b0f7 | |||
| c66267a0f9 | |||
| f1d2f24534 | |||
| d83974e07f | |||
| f270f30728 | |||
| 55c237913c | |||
| 806671df7c | |||
| d64ee42ec3 | |||
| fe08f39900 | |||
| 5123ab57c9 | |||
| 313b327cd7 | |||
| 855d922a3e | |||
| cbe07ad23b | |||
| b3aba4ad99 | |||
| 21ad7f549d | |||
| 4b13fa45c5 | |||
| 485d40c752 | |||
| 8346ae8235 | |||
| 109c0f202a | |||
| 4231058aa1 | |||
| 6156d67e4a | |||
| 58bf036f52 | |||
| ff7d25c0f2 | |||
| 5f0b7f328c | |||
| 6559581bad | |||
| d78262f52b | |||
| bd566324ed | |||
| b65bf5082d | |||
| 939e4cba3e | |||
| 015a8763a0 | |||
| 02862d80eb | |||
| 7b0a3fc6d3 | |||
| b40b31b7b1 | |||
| 149d3d13d1 | |||
| 0f64d66cd8 | |||
| a85e2f7aad | |||
| 4f883b1264 | |||
| feb78d00cf | |||
| c9d54baa10 | |||
| 940f54dab1 | |||
| d83827a44e | |||
| 3a0a13d06d | |||
| 23f8e35716 | |||
| a251e61d73 | |||
| af06b1cd06 | |||
| 5b9120ba6c | |||
| 7769a93a10 | |||
| 95a6c7058f | |||
| 6c3a668400 | |||
| ad0f873ece | |||
| 3008a4ed7a | |||
| 95ef3a336b | |||
| 9a5c1b8126 | |||
| e926db76a0 | |||
| 9419c7fdeb | |||
| 9dbb4abe7e | |||
| 19e0fb7955 | |||
| 5b9b21a7d1 | |||
| 93e69ab0c6 | |||
| bc5c559413 | |||
| 9b2fcbff08 | |||
| ad2674d20b | |||
| 10ac2c830f | |||
| df3053eafb | |||
| aaae952acb | |||
| 8ace30ee23 | |||
| eb0657c953 | |||
| b1cd44341b | |||
| 3da47cdacd | |||
| 658dda916c | |||
| 7c3d8b896b | |||
| 1ce9df7998 | |||
| a0cbf66c81 | |||
| a4941031cb | |||
| 9fd6aea325 | |||
| a52181c995 | |||
| ee75df0f0a | |||
| 92eff653f1 | |||
| 1e66985a78 | |||
| a059a42799 | |||
| b5603fbfe9 | |||
| a0423a9cc3 | |||
| 4ab7112988 | |||
| 767cf96010 | |||
| 4ffb7790df | |||
| 3ccc55a78f | |||
| d0d29e03db | |||
| 92b7c4b5ec | |||
| dff7c43aed | |||
| 9efbcbbd5e | |||
| 31fa0a7044 | |||
| fcb2bf7fea | |||
| 0bd27d61b0 | |||
| 369ecfa490 | |||
| 551354b1bb | |||
| 03b7891edc | |||
| 8978dff054 | |||
| d20844fefa | |||
| cd579a04dd | |||
| 15b8140bff | |||
| 9a93ad2e06 | |||
| bd4d3aa52b | |||
| bf32ab177f | |||
| 2ea883aa15 | |||
| 43cc296582 | |||
| 4c1aadd74e | |||
| 7d3719bf70 | |||
| c08164d864 | |||
| b156aa74a5 | |||
| 87ba2cb407 | |||
| 5084e5d3ef | |||
| a5516e3511 | |||
| 0e460baf82 | |||
| ef52777ffb | |||
| b67ceab849 | |||
| 69022bb8b6 | |||
| 5ffade663a | |||
| 29d729171c | |||
| 9475871edb | |||
| b69364d5ff | |||
| 10dad8e6e6 | |||
| a184b4e67c | |||
| 8cd0a90ecd | |||
| 4a37632ef3 | |||
| 3271d020e9 | |||
| e494a2670f | |||
| d3a0a337b9 | |||
| 3951ee746d | |||
| 84e4257e75 | |||
| c401c88702 | |||
| 550f9e2afa | |||
| b55a19cebb | |||
| 4caadcfa19 | |||
| dba837b1d2 | |||
| 714fc63050 | |||
| b6fa6cba22 | |||
| 2df026bcb5 | |||
| 6ee24a7527 | |||
| e2dcee1959 | |||
| 4fbea9512f | |||
| b7850ab839 | |||
| c0215baca5 | |||
| c62758c5b5 | |||
| 14358651e4 | |||
| f04aeb9f2b | |||
| dc902e7a5a | |||
| 4fc66e19bb | |||
| e12d2b2a42 | |||
| cb78451d6c | |||
| 7979bc63ae | |||
| e8ad8a7448 | |||
| eb61f5aa9e | |||
| 3351998efd | |||
| 20dbacd22f | |||
| 0f3be4fdf8 | |||
| 3ae8adfbf9 | |||
| aa2632fe46 | |||
| 8f2843bfcf | |||
| 14c86d447b | |||
| bee016e0be | |||
| 54552fc95c | |||
| 9397372f87 | |||
| 8bbf6da052 | |||
| ffa7d25fc0 | |||
| a37d3b00d0 | |||
| 04891c7c61 | |||
| d67ff54f4b | |||
| ccec190985 | |||
| 26728a85ad | |||
| c6d85a1b0b | |||
| 71610fb20f | |||
| cb0f9024b1 | |||
| 1797480128 | |||
| 972b198248 | |||
| 9010b7acd0 | |||
| b57b68571e | |||
| 1ca9420baa | |||
| 0383938536 | |||
| 50b841d54d | |||
| 8f71460fa1 | |||
| d5324bce6a | |||
| 660f3ccba1 | |||
| bc8db3deab | |||
| b2c8fbf349 | |||
| c3f21d9292 | |||
| 9b146ae1d2 | |||
| a32c679519 | |||
| 1e602793b2 | |||
| a6a65b7523 | |||
| 04c1d9cbff | |||
| a6dfd67cd7 | |||
| 7d178da61c | |||
| 30f9acfcf3 | |||
| 1e351b4d63 | |||
| cb5b691ec1 | |||
| b47b401245 | |||
| 119e79e248 | |||
| d7254053b6 | |||
| 8f8edd4126 | |||
| 10bb844087 | |||
| ba3baabb50 | |||
| c76fbe4edb | |||
| cae2de4fc9 | |||
| 7c346d977a | |||
| 9847934de9 | |||
| db73f80058 | |||
| 4dd479dad7 | |||
| d01e1e8eeb | |||
| e3ef737ac4 | |||
| 69317fb403 | |||
| 1b80c8938a | |||
| dc77c01fd3 | |||
| 83474d6e59 | |||
| 529310c93a | |||
| 70f26f33a5 | |||
| 414bc10c40 | |||
| 250b0a7afb | |||
| e5355db672 | |||
| aef45a90b2 | |||
| 9221641bba | |||
| 6bca1e3b22 | |||
| 00cea3eb3c | |||
| 19b52a2f24 | |||
| 6237f6192c | |||
| cc58d4c3ad | |||
| 6a78706a3e | |||
| 060c59bf9d | |||
| 6fd3c494be | |||
| 8adfa8dd83 | |||
| 6c9001df09 | |||
| d6159d8cb5 | |||
| 81b9753b79 | |||
| d8b1eec91b | |||
| b871813cfd | |||
| 6f7dce53cc | |||
| 13d2af2155 | |||
| bf3794822c | |||
| 1fa8fba5fe | |||
| 3d7697da6f | |||
| 42cf17d3bf | |||
| 783e37f06d | |||
| 9a4cda0bf6 | |||
| b6279af1d8 | |||
| bc0a7542ac | |||
| 232fad0145 | |||
| 5cbcac28b1 | |||
| aec59f2da6 | |||
| 905df5ec25 | |||
| bacfdc5049 | |||
| 3cc72021b6 | |||
| 115e0fc119 | |||
| 4354e126b1 | |||
| 02f39472f9 | |||
| d7aed2edc9 | |||
| af513946a2 | |||
| 7bfd02054b | |||
| 1ceb703129 | |||
| fb28882f65 | |||
| d9c61fdb02 | |||
| 72c118a70f | |||
| b136e9e29d | |||
| 50c910461a | |||
| 88a84e9350 | |||
| 43bb8ae0a8 | |||
| 638071dadd | |||
| 8a4c90ade8 | |||
| 1dfa1da0ee | |||
| 71ebade641 | |||
| b86b05c4fc | |||
| 35a70988cb | |||
| 56ba26eb45 | |||
| adb8be9345 | |||
| abc9ee22c6 | |||
| e5ee9760c0 | |||
| 7868a8c174 | |||
| 03df4cec45 | |||
| 25241542d2 | |||
| 57a75e68b9 | |||
| ad1846fed6 | |||
| dcf2168454 | |||
| 9ab56fe9ca | |||
| f708b8b299 | |||
| c5e8d1c276 | |||
| 4093327b7f | |||
| 391b832613 | |||
| b653d19579 | |||
| 4a57cfaf3e | |||
| 31a75bd252 | |||
| e2c3386c33 | |||
| 0506f3bef9 | |||
| a866d6b16e | |||
| a76a69d085 | |||
| 852b0b3f11 | |||
| 307b39bd38 | |||
| d55358652b | |||
| 955f75f733 | |||
| 280e778749 | |||
| 60ba898167 | |||
| 2c9d5b9ea3 | |||
| eb6e2636b5 | |||
| 4c1964d509 | |||
| 7547277352 | |||
| 3e00bc49fd | |||
| 99e0b65de7 | |||
| 70ef904951 | |||
| fcf023e3d2 | |||
| 8c882ddead | |||
| 7d136f9970 | |||
| f4c1460c2b | |||
| bb2e1de0a8 | |||
| c81bc1d2ee | |||
| 7154d23759 | |||
| df23fd0dee | |||
| adfb8895df | |||
| c8e12ddb5c | |||
| 5b181ecea7 | |||
| 728aaaab20 | |||
| f7d0cecdac | |||
| 095a7d9b34 | |||
| cf53f2778f | |||
| 65e20282b6 | |||
| 405c5b5ad0 | |||
| 6f0fe16b87 | |||
| 111daffc17 | |||
| b8a478f558 | |||
| 9f7084d077 | |||
| 0840cd3df3 | |||
| cefdaf9a9b | |||
| 13335b19e9 | |||
| 6e471a27e7 | |||
| 513ea67e7d | |||
| 3868e711f4 | |||
| f33f712de7 | |||
| c12e1f6d6c | |||
| 479abd5231 | |||
| a60a24a4a8 | |||
| 55b3050ca8 | |||
| 2c996a8508 | |||
| 84f8eee869 | |||
| 590c19dbd7 | |||
| fa47707974 | |||
| ca62481083 | |||
| 1c3306046c | |||
| f4fc845375 | |||
| a7af987322 | |||
| c4eaae923a | |||
| 849ba02516 | |||
| 9dcd14a712 | |||
| 3412b4dc5a | |||
| a3b96aff1f | |||
| 9bb191f29f | |||
| 4a43ccfa92 | |||
| bcfa913450 | |||
| 43d8474caa | |||
| b73e8642d3 | |||
| cfe2277a64 | |||
| e776c2cffa | |||
| ca59bc3c9c | |||
| 575362f4dc | |||
| f0139c5e41 | |||
| 5f8ac66036 | |||
| a49e66c689 | |||
| 1630e4bc2f | |||
| bf674a0f4d | |||
| b170755c3d | |||
| b25612bbac | |||
| a43183ff96 | |||
| 5aa34695a1 | |||
| 3b36372a66 | |||
| e763693829 | |||
| e08d60ed18 | |||
| 9e6e2de71e | |||
| b49935701b | |||
| 76cc5995d9 | |||
| c0fbf106ed | |||
| 7b4020c5e9 | |||
| 383e3829e5 | |||
| 91356af838 | |||
| 4c967a43a7 | |||
| deca842eb0 | |||
| 44366746dd | |||
| 3806cec10e | |||
| a800fa07f9 | |||
| 32c360f032 | |||
| 25f1445afc | |||
| 0042359e5f | |||
| cf2e2bfbc1 | |||
| 60f9a8be9a | |||
| 8316db9702 | |||
| 1a480435de | |||
| ebc373744a | |||
| 650aa25659 | |||
| 212dd06948 | |||
| b6eea2e170 | |||
| 688017bd8a | |||
| 58a9c27342 | |||
| f52b00256d | |||
| 2d48d96b3c | |||
| abd13a1140 | |||
| 5882d71f9b | |||
| dc92bbf61e | |||
| e6fdeb0e8a | |||
| 3b948c7b7e | |||
| d965fe759a | |||
| 5e4a3379a9 | |||
| 9dc428b720 | |||
| 8a5b469ff8 | |||
| ed06f32a7a | |||
| a876703f8f | |||
| 01bb8d8c9a | |||
| f452204d62 | |||
| 51ae485f20 | |||
| 0eabb147b2 | |||
| 2e0e39ccc8 | |||
| 63e733f0d6 | |||
| 2406d2cfdb | |||
| e074ca0bf9 | |||
| 13c37e708f | |||
| 3f76d65b95 | |||
| 87bce0c097 | |||
| 6d41c8cf67 | |||
| 22385a8e35 | |||
| 77fa213ccd | |||
| d0a82adc3f | |||
| de2aa903c5 | |||
| 42ec2548c9 | |||
| a2cba67f4e | |||
| 7d45cfff2c | |||
| f1ab8253f0 | |||
| e5d3df7d24 | |||
| 987676df08 | |||
| f16f62f76c | |||
| 8a2f3405d5 | |||
| dfa33f651a | |||
| 30c2927987 | |||
| e8159d97fa | |||
| 1248260df3 | |||
| 4cb804cf03 | |||
| 2b0dd8851c | |||
| 2deba17d91 | |||
| 3574ef5bb9 | |||
| abf13f1619 | |||
| 4a7df470f0 | |||
| c9101f4d97 | |||
| 6e9a46e582 | |||
| 1d3124f89f | |||
| ada1a593a4 | |||
| 25db35e41e | |||
| 99000fada1 | |||
| 58b2f8ca17 | |||
| 8be3c1aaf2 | |||
| 2ee8639eaf | |||
| 32605578dd | |||
| fe0bba6df6 | |||
| 5fdcd6298f | |||
| 55943dbff6 | |||
| d12e571b20 | |||
| 0c15f05316 | |||
| 25c9f8e038 | |||
| a3811371cc | |||
| f734e196e5 | |||
| 6129f4722f | |||
| 585d7d0b87 | |||
| cdfc198f28 | |||
| 6fcb3d3d5e | |||
| 358d9ec06d | |||
| 322c8c1cf3 | |||
| 47eb0c34a2 | |||
| 4a290a85e6 | |||
| 5489c50cc0 | |||
| 066e40dada | |||
| 123d04ff7b | |||
| d5881736cf | |||
| 5e539da3da | |||
| ba58ca9d5c | |||
| 117007dfa1 | |||
| d29b3633d1 | |||
| 41e0275c95 | |||
| 7cf4baa92a | |||
| 6c3dfdfe6d | |||
| 149d159c05 | |||
| c0ad16f497 | |||
| 9edb631d52 | |||
| 58d2f0a41e | |||
| 255d9427b6 | |||
| d29f4489de | |||
| 4367fc54bf | |||
| b89116eb55 | |||
| 9430e9c8e2 | |||
| b01d53a247 | |||
| 65cbba3c2e | |||
| f93e7b91ff | |||
| 04069bab82 | |||
| 3106035ef9 | |||
| 18720b3302 | |||
| 12e546e63a | |||
| c28936fefb | |||
| 080d196138 | |||
| d3967b37cd | |||
| 0089ea2321 | |||
| 3f35124838 | |||
| 6ca5fb6b20 | |||
| a3b0273445 | |||
| 2a54797dce | |||
| 9770016eec | |||
| 6210716199 | |||
| e41a16dbf3 | |||
| 01f4aa018f | |||
| f9baeefbaf | |||
| af3417d6cc | |||
| 17bf8d0124 | |||
| c3e02286d3 | |||
| a9d82bf157 | |||
| e097df912e | |||
| 477bb6165f | |||
| 19850e8c5a | |||
| 12dcf76da9 | |||
| 36aac328e4 | |||
| 9cf81c7ad4 | |||
| 6c6417e595 | |||
| efa8ba5965 | |||
| fd02385c22 | |||
| 713b21de14 | |||
| af144a5184 | |||
| 9b31ae3146 | |||
| 4cb0012872 | |||
| eaa68327f7 | |||
| 68ef618028 | |||
| 3ecdafa685 | |||
| 20ae9dea19 | |||
| c9d46856a3 | |||
| 6d65f6646f | |||
| 34cd106357 | |||
| 714fce7e59 | |||
| 08e4ea384e | |||
| fe0f9743d3 | |||
| 57019e170f | |||
| 9f303cc116 | |||
| e504b20235 | |||
| f64b0d3818 | |||
| 1a26ea0911 | |||
| 7098ab6509 | |||
| 0d3589ca24 | |||
| f02ff62a08 | |||
| fbfc817c5f | |||
| 13601031cb | |||
| 442cad69a7 | |||
| be6545a366 | |||
| 32fdd36802 | |||
| fbc54526ed | |||
| a3306e4a81 | |||
| 3d858b21fa | |||
| 62b557f82c | |||
| 158c82ff5f | |||
| fd410c0281 | |||
| 65e3696029 | |||
| 690a5119f4 | |||
| cc0653c68a | |||
| 042a15d294 | |||
| 8e4c0f60a1 | |||
| 5615fc09e6 | |||
| d68f1e4cfa | |||
| 0c4901487d | |||
| 7f4b2d6e42 | |||
| 715a49d9fe | |||
| d556f0d275 | |||
| b98c1a0627 | |||
| da30292d84 | |||
| 7bda5c06de | |||
| 3d5847f4b3 | |||
| db400dffb5 | |||
| 199cdf6899 | |||
| 752171d5b8 | |||
| 7a5714cc85 | |||
| c77f5eee8c | |||
| aacfed40f8 | |||
| ec1059e74c | |||
| 3500217f94 | |||
| 427f8b1522 | |||
| 8b52bad16f | |||
| daed0b60bc | |||
| 4654f7aa37 | |||
| 70e87dad1c | |||
| ba8d8a6f05 | |||
| 605d267fe8 | |||
| 8f2a17585e | |||
| 51424d01a9 | |||
| f5ff9b2208 | |||
| 457f4c410a | |||
| bb013d5c3c | |||
| a9c7dbd17a | |||
| 09fdc946a0 | |||
| 31f1bce16b | |||
| 2f3ddaec20 | |||
| 7cd37e6e95 | |||
| a938009074 | |||
| 21d08ff742 | |||
| da8b41b12a | |||
| 6e031727fa | |||
| 381890b578 | |||
| 71fa6d765f | |||
| 9793130f6c | |||
| aadfa9aa9c | |||
| 645bba96cd |
@@ -3018,6 +3018,124 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "koiakoia",
|
||||||
|
"name": "koiakoia",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/60405354?v=4",
|
||||||
|
"profile": "https://github.com/koiakoia",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "mustafa-online",
|
||||||
|
"name": "Mustafa Online",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/5323832?v=4",
|
||||||
|
"profile": "https://github.com/mustafa-online",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "franceslui",
|
||||||
|
"name": "franceslui",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/104601439?v=4",
|
||||||
|
"profile": "https://github.com/franceslui",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Q4kK",
|
||||||
|
"name": "Q4kK",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/125313163?v=4",
|
||||||
|
"profile": "https://github.com/Q4kK",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "squintfox",
|
||||||
|
"name": "squintfox",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/55590532?v=4",
|
||||||
|
"profile": "https://github.com/squintfox",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jeffclay",
|
||||||
|
"name": "Jeff Clay",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1380084?v=4",
|
||||||
|
"profile": "https://github.com/jeffclay",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "PP-JN-RL",
|
||||||
|
"name": "Phil J R",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/52716446?v=4",
|
||||||
|
"profile": "https://github.com/PP-JN-RL",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "chandanchowdhury",
|
||||||
|
"name": "i_virus",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1496725?v=4",
|
||||||
|
"profile": "https://www.corelight.com/",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "gitgrimbo",
|
||||||
|
"name": "Paul Grime",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1020541?v=4",
|
||||||
|
"profile": "https://github.com/gitgrimbo",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "LeePorte",
|
||||||
|
"name": "Lee Porte",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/922815?v=4",
|
||||||
|
"profile": "https://leeporte.co.uk",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "bryanlopezinc",
|
||||||
|
"name": "BRYAN ",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/23613427?v=4",
|
||||||
|
"profile": "https://github.com/bryanlopezinc",
|
||||||
|
"contributions": [
|
||||||
|
"code",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "U-H-T",
|
||||||
|
"name": "U-H-T",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/64061710?v=4",
|
||||||
|
"profile": "https://github.com/U-H-T",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Tyree",
|
||||||
|
"name": "Matt Tyree",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/5395363?v=4",
|
||||||
|
"profile": "https://github.com/Tyree",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+166
@@ -0,0 +1,166 @@
|
|||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DB SETUP
|
||||||
|
# --------------------------------------------
|
||||||
|
MYSQL_DATABASE=snipeit
|
||||||
|
MYSQL_USER=snipeit
|
||||||
|
MYSQL_PASSWORD=changeme1234
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme1234
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: BASIC APP SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
APP_ENV=develop
|
||||||
|
APP_DEBUG=false
|
||||||
|
# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here
|
||||||
|
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
APP_TIMEZONE='UTC'
|
||||||
|
APP_LOCALE=en
|
||||||
|
MAX_RESULTS=500
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: UPLOADED FILE STORAGE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
PRIVATE_FILESYSTEM_DISK=local
|
||||||
|
PUBLIC_FILESYSTEM_DISK=local_public
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DATABASE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=mariadb
|
||||||
|
DB_DATABASE=snipeit
|
||||||
|
DB_USERNAME=snipeit
|
||||||
|
DB_PASSWORD=changeme1234
|
||||||
|
DB_PREFIX=null
|
||||||
|
DB_DUMP_PATH='/usr/bin'
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
DB_COLLATION=utf8mb4_unicode_ci
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SSL DATABASE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
DB_SSL=false
|
||||||
|
DB_SSL_IS_PAAS=false
|
||||||
|
DB_SSL_KEY_PATH=null
|
||||||
|
DB_SSL_CERT_PATH=null
|
||||||
|
DB_SSL_CA_PATH=null
|
||||||
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MAIL_DRIVER=smtp
|
||||||
|
MAIL_HOST=mailhog
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDR=you@example.com
|
||||||
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: IMAGE LIBRARY
|
||||||
|
# This should be gd or imagick
|
||||||
|
# --------------------------------------------
|
||||||
|
IMAGE_LIB=gd
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: BACKUP SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
||||||
|
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||||
|
BACKUP_ENV=true
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SESSION SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
SESSION_LIFETIME=12000
|
||||||
|
EXPIRE_ON_CLOSE=false
|
||||||
|
ENCRYPT=false
|
||||||
|
COOKIE_NAME=snipeit_session
|
||||||
|
COOKIE_DOMAIN=null
|
||||||
|
SECURE_COOKIES=false
|
||||||
|
API_TOKEN_EXPIRATION_YEARS=40
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
||||||
|
ALLOW_IFRAMING=false
|
||||||
|
REFERRER_POLICY=same-origin
|
||||||
|
ENABLE_CSP=false
|
||||||
|
CORS_ALLOWED_ORIGINS=null
|
||||||
|
ENABLE_HSTS=false
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: CACHE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
QUEUE_DRIVER=sync
|
||||||
|
CACHE_PREFIX=snipeit
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: REDIS SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: MEMCACHED SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MEMCACHED_HOST=null
|
||||||
|
MEMCACHED_PORT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: PUBLIC S3 Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
PUBLIC_AWS_SECRET_ACCESS_KEY=null
|
||||||
|
PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||||
|
PUBLIC_AWS_DEFAULT_REGION=null
|
||||||
|
PUBLIC_AWS_BUCKET=null
|
||||||
|
PUBLIC_AWS_URL=null
|
||||||
|
PUBLIC_AWS_BUCKET_ROOT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: PRIVATE S3 Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
PRIVATE_AWS_ACCESS_KEY_ID=null
|
||||||
|
PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||||
|
PRIVATE_AWS_DEFAULT_REGION=null
|
||||||
|
PRIVATE_AWS_BUCKET=null
|
||||||
|
PRIVATE_AWS_URL=null
|
||||||
|
PRIVATE_AWS_BUCKET_ROOT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: AWS Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
AWS_ACCESS_KEY_ID=null
|
||||||
|
AWS_SECRET_ACCESS_KEY=null
|
||||||
|
AWS_DEFAULT_REGION=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: LOGIN THROTTLING
|
||||||
|
# --------------------------------------------
|
||||||
|
LOGIN_MAX_ATTEMPTS=5
|
||||||
|
LOGIN_LOCKOUT_DURATION=60
|
||||||
|
RESET_PASSWORD_LINK_EXPIRES=900
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: MISC
|
||||||
|
# --------------------------------------------
|
||||||
|
LOG_CHANNEL=stderr
|
||||||
|
LOG_MAX_DAYS=10
|
||||||
|
APP_LOCKED=false
|
||||||
|
APP_CIPHER=AES-256-CBC
|
||||||
|
APP_FORCE_TLS=false
|
||||||
|
GOOGLE_MAPS_API=
|
||||||
|
LDAP_MEM_LIM=500M
|
||||||
|
LDAP_TIME_LIM=600
|
||||||
+21
-14
@@ -1,18 +1,18 @@
|
|||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: DB SETUP
|
# REQUIRED: DOCKER SPECIFIC SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MYSQL_DATABASE=snipeit
|
APP_VERSION=v6.4.1
|
||||||
MYSQL_USER=snipeit
|
APP_PORT=8000
|
||||||
MYSQL_PASSWORD=changeme1234
|
|
||||||
MYSQL_ROOT_PASSWORD=changeme1234
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: BASIC APP SETTINGS
|
# REQUIRED: BASIC APP SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
APP_ENV=develop
|
APP_ENV=production
|
||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here
|
# Please regenerate the APP_KEY value by calling `docker compose run --rm snipeit php artisan key:generate --show`. Copy paste the value here
|
||||||
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||||
APP_URL=http://localhost:8000
|
APP_URL=http://localhost:8000
|
||||||
|
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
||||||
APP_TIMEZONE='UTC'
|
APP_TIMEZONE='UTC'
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
MAX_RESULTS=500
|
MAX_RESULTS=500
|
||||||
@@ -27,10 +27,12 @@ PUBLIC_FILESYSTEM_DISK=local_public
|
|||||||
# REQUIRED: DATABASE SETTINGS
|
# REQUIRED: DATABASE SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=mariadb
|
DB_HOST=db
|
||||||
|
DB_PORT='3306'
|
||||||
DB_DATABASE=snipeit
|
DB_DATABASE=snipeit
|
||||||
DB_USERNAME=snipeit
|
DB_USERNAME=snipeit
|
||||||
DB_PASSWORD=changeme1234
|
DB_PASSWORD=changeme1234
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme1234
|
||||||
DB_PREFIX=null
|
DB_PREFIX=null
|
||||||
DB_DUMP_PATH='/usr/bin'
|
DB_DUMP_PATH='/usr/bin'
|
||||||
DB_CHARSET=utf8mb4
|
DB_CHARSET=utf8mb4
|
||||||
@@ -45,29 +47,35 @@ DB_SSL_KEY_PATH=null
|
|||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=mailhog
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=1025
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_TLS_VERIFY_PEER=true
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME='Snipe-IT'
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
MAIL_REPLYTO_ADDR=you@example.com
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
MAIL_REPLYTO_NAME='Snipe-IT'
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
MAIL_AUTO_EMBED_METHOD='attachment'
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DATA PROTECTION
|
||||||
|
# --------------------------------------------
|
||||||
|
ALLOW_BACKUP_DELETE=false
|
||||||
|
ALLOW_DATA_PURGE=false
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: IMAGE LIBRARY
|
# REQUIRED: IMAGE LIBRARY
|
||||||
# This should be gd or imagick
|
# This should be gd or imagick
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
IMAGE_LIB=gd
|
IMAGE_LIB=gd
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: BACKUP SETTINGS
|
# OPTIONAL: BACKUP SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
@@ -75,7 +83,6 @@ MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
|||||||
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||||
BACKUP_ENV=true
|
BACKUP_ENV=true
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: SESSION SETTINGS
|
# OPTIONAL: SESSION SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
@@ -90,7 +97,7 @@ API_TOKEN_EXPIRATION_YEARS=40
|
|||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: SECURITY HEADER SETTINGS
|
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1,172.0.0.0/8
|
||||||
ALLOW_IFRAMING=false
|
ALLOW_IFRAMING=false
|
||||||
REFERRER_POLICY=same-origin
|
REFERRER_POLICY=same-origin
|
||||||
ENABLE_CSP=false
|
ENABLE_CSP=false
|
||||||
@@ -108,7 +115,7 @@ CACHE_PREFIX=snipeit
|
|||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: REDIS SETTINGS
|
# OPTIONAL: REDIS SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=null
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -36,11 +36,12 @@ DB_SSL_KEY_PATH=null
|
|||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER="log"
|
MAIL_MAILER="log"
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|||||||
+10
-3
@@ -42,21 +42,26 @@ DB_SSL_KEY_PATH=null
|
|||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
|
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
|
||||||
MAIL_PORT=587
|
MAIL_PORT=587
|
||||||
MAIL_USERNAME=YOURUSERNAME
|
MAIL_USERNAME=YOURUSERNAME
|
||||||
MAIL_PASSWORD=YOURPASSWORD
|
MAIL_PASSWORD=YOURPASSWORD
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME='Snipe-IT'
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
MAIL_REPLYTO_ADDR=you@example.com
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
MAIL_REPLYTO_NAME='Snipe-IT'
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
MAIL_AUTO_EMBED_METHOD='attachment'
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
MAIL_TLS_VERIFY_PEER=true
|
||||||
|
|
||||||
|
# MAIL_ENCRYPTION is no longer supported. SymfonyMailer will use tls if it's
|
||||||
|
# advertised, and won't if it's not. If you want to use your mail server's IP but it's failing
|
||||||
|
# because of certificate errors, set MAIL_TLS_VERIFY_PEER-true
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: IMAGE LIBRARY
|
# REQUIRED: IMAGE LIBRARY
|
||||||
@@ -86,6 +91,7 @@ COOKIE_DOMAIN=null
|
|||||||
SECURE_COOKIES=false
|
SECURE_COOKIES=false
|
||||||
API_TOKEN_EXPIRATION_YEARS=15
|
API_TOKEN_EXPIRATION_YEARS=15
|
||||||
BS_TABLE_STORAGE=cookieStorage
|
BS_TABLE_STORAGE=cookieStorage
|
||||||
|
BS_TABLE_DEEPLINK=true
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: SECURITY HEADER SETTINGS
|
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||||
@@ -94,6 +100,7 @@ APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
|||||||
ALLOW_IFRAMING=false
|
ALLOW_IFRAMING=false
|
||||||
REFERRER_POLICY=same-origin
|
REFERRER_POLICY=same-origin
|
||||||
ENABLE_CSP=false
|
ENABLE_CSP=false
|
||||||
|
ADDITIONAL_CSP_URLS=null
|
||||||
CORS_ALLOWED_ORIGINS=null
|
CORS_ALLOWED_ORIGINS=null
|
||||||
ENABLE_HSTS=false
|
ENABLE_HSTS=false
|
||||||
|
|
||||||
@@ -190,4 +197,4 @@ ARGON_TIME=2
|
|||||||
# OPTIONAL: SCIM
|
# OPTIONAL: SCIM
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
SCIM_TRACE=false
|
SCIM_TRACE=false
|
||||||
SCIM_STANDARDS_COMPLIANCE=false
|
SCIM_STANDARDS_COMPLIANCE=false
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ DB_PASSWORD=null
|
|||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,6 @@ APP_KEY=base64:tu9NRh/a6+dCXBDGvg0Gv/0TcABnFsbT4AKxrr8mwQo=
|
|||||||
LOGIN_MAX_ATTEMPTS=1000000
|
LOGIN_MAX_ATTEMPTS=1000000
|
||||||
LOGIN_LOCKOUT_DURATION=100000000
|
LOGIN_LOCKOUT_DURATION=100000000
|
||||||
|
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME=Snipe-IT
|
MAIL_FROM_NAME=Snipe-IT
|
||||||
|
|||||||
+1
-1
@@ -15,6 +15,6 @@ APP_KEY=base64:tu9NRh/a6+dCXBDGvg0Gv/0TcABnFsbT4AKxrr8mwQo=
|
|||||||
LOGIN_MAX_ATTEMPTS=1000000
|
LOGIN_MAX_ATTEMPTS=1000000
|
||||||
LOGIN_LOCKOUT_DURATION=100000000
|
LOGIN_LOCKOUT_DURATION=100000000
|
||||||
|
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME=Snipe-IT
|
MAIL_FROM_NAME=Snipe-IT
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
|
|
||||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||||
- name: Run Codacy Analysis CLI
|
- name: Run Codacy Analysis CLI
|
||||||
uses: codacy/codacy-analysis-cli-action@v4.3.0
|
uses: codacy/codacy-analysis-cli-action@v4.4.1
|
||||||
with:
|
with:
|
||||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||||
# You can also omit the token and run the tools that support default configurations
|
# You can also omit the token and run the tools that support default configurations
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Crowdin push
|
- name: Crowdin push
|
||||||
uses: crowdin/github-action@v1
|
uses: crowdin/github-action@v2
|
||||||
with:
|
with:
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
# https://github.com/docker/build-push-action
|
# https://github.com/docker/build-push-action
|
||||||
- name: Build and push 'snipe-it' image
|
- name: Build and push 'snipe-it' image
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile.alpine
|
file: ./Dockerfile.alpine
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
# https://github.com/docker/build-push-action
|
# https://github.com/docker/build-push-action
|
||||||
- name: Build and push 'snipe-it' image
|
- name: Build and push 'snipe-it' image
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php-version:
|
php-version:
|
||||||
- "7.4"
|
- "8.1"
|
||||||
- "8.0"
|
- "8.2"
|
||||||
- "8.1.1"
|
- "8.3"
|
||||||
|
|
||||||
name: PHP ${{ matrix.php-version }}
|
name: PHP ${{ matrix.php-version }}
|
||||||
|
|
||||||
@@ -58,11 +58,17 @@ jobs:
|
|||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
- name: Generate key
|
- name: Setup Laravel
|
||||||
run: php artisan key:generate
|
env:
|
||||||
|
DB_CONNECTION: mysql
|
||||||
- name: Directory Permissions
|
DB_DATABASE: snipeit
|
||||||
run: chmod -R 777 storage bootstrap/cache
|
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||||
|
DB_USERNAME: root
|
||||||
|
run: |
|
||||||
|
php artisan key:generate
|
||||||
|
php artisan migrate --force
|
||||||
|
php artisan passport:install
|
||||||
|
chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
name: Tests in Postgres
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: postgres
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: snipeit
|
||||||
|
POSTGRES_USER: snipeit
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php-version:
|
||||||
|
- "8.2"
|
||||||
|
|
||||||
|
name: PHP ${{ matrix.php-version }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "${{ matrix.php-version }}"
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get Composer Cache Directory
|
||||||
|
id: composer-cache
|
||||||
|
run: |
|
||||||
|
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-composer-
|
||||||
|
|
||||||
|
- name: Copy .env
|
||||||
|
run: |
|
||||||
|
cp -v .env.testing.example .env
|
||||||
|
cp -v .env.testing.example .env.testing
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
|
- name: Setup Laravel
|
||||||
|
env:
|
||||||
|
DB_CONNECTION: pgsql
|
||||||
|
DB_DATABASE: snipeit
|
||||||
|
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||||
|
DB_USERNAME: snipeit
|
||||||
|
DB_PASSWORD: password
|
||||||
|
run: |
|
||||||
|
php artisan key:generate
|
||||||
|
php artisan migrate --force
|
||||||
|
php artisan passport:install
|
||||||
|
chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
|
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||||
|
env:
|
||||||
|
DB_CONNECTION: pgsql
|
||||||
|
DB_DATABASE: snipeit
|
||||||
|
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||||
|
DB_USERNAME: snipeit
|
||||||
|
DB_PASSWORD: password
|
||||||
|
run: php artisan test --parallel
|
||||||
@@ -49,6 +49,9 @@ jobs:
|
|||||||
- name: Generate key
|
- name: Generate key
|
||||||
run: php artisan key:generate
|
run: php artisan key:generate
|
||||||
|
|
||||||
|
- name: Setup Passport
|
||||||
|
run: php artisan passport:keys
|
||||||
|
|
||||||
- name: Directory Permissions
|
- name: Directory Permissions
|
||||||
run: chmod -R 777 storage bootstrap/cache
|
run: chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
|
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
|
||||||
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
|
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
|
||||||
"DOC4": "You should really just ignore it and run upgrade.php. Really",
|
"DOC4": "You should really just ignore it and run upgrade.php. Really",
|
||||||
"php_min_version": "7.4.0",
|
"php_min_version": "8.1.0",
|
||||||
"php_max_major_minor": "8.1",
|
"php_max_major_minor": "8.3",
|
||||||
"php_max_wontwork": "8.2.0",
|
"php_max_wontwork": "8.4.0",
|
||||||
"current_snipeit_version": "6.3"
|
"current_snipeit_version": "7.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,6 +432,23 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bilias"><img src="https://avatars.githubusercontent.com/u/47315739?v=4?s=110" width="110px;" alt="bilias"/><br /><sub><b>bilias</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bilias" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bilias"><img src="https://avatars.githubusercontent.com/u/47315739?v=4?s=110" width="110px;" alt="bilias"/><br /><sub><b>bilias</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bilias" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coach1988"><img src="https://avatars.githubusercontent.com/u/2565989?v=4?s=110" width="110px;" alt="coach1988"/><br /><sub><b>coach1988</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=coach1988" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coach1988"><img src="https://avatars.githubusercontent.com/u/2565989?v=4?s=110" width="110px;" alt="coach1988"/><br /><sub><b>coach1988</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=coach1988" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mauro-miatello"><img src="https://avatars.githubusercontent.com/u/11910225?v=4?s=110" width="110px;" alt="MrM"/><br /><sub><b>MrM</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mauro-miatello" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mauro-miatello"><img src="https://avatars.githubusercontent.com/u/11910225?v=4?s=110" width="110px;" alt="MrM"/><br /><sub><b>MrM</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mauro-miatello" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/koiakoia"><img src="https://avatars.githubusercontent.com/u/60405354?v=4?s=110" width="110px;" alt="koiakoia"/><br /><sub><b>koiakoia</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=koiakoia" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mustafa-online"><img src="https://avatars.githubusercontent.com/u/5323832?v=4?s=110" width="110px;" alt="Mustafa Online"/><br /><sub><b>Mustafa Online</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mustafa-online" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/franceslui"><img src="https://avatars.githubusercontent.com/u/104601439?v=4?s=110" width="110px;" alt="franceslui"/><br /><sub><b>franceslui</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=franceslui" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Q4kK"><img src="https://avatars.githubusercontent.com/u/125313163?v=4?s=110" width="110px;" alt="Q4kK"/><br /><sub><b>Q4kK</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Q4kK" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/squintfox"><img src="https://avatars.githubusercontent.com/u/55590532?v=4?s=110" width="110px;" alt="squintfox"/><br /><sub><b>squintfox</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=squintfox" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jeffclay"><img src="https://avatars.githubusercontent.com/u/1380084?v=4?s=110" width="110px;" alt="Jeff Clay"/><br /><sub><b>Jeff Clay</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jeffclay" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PP-JN-RL"><img src="https://avatars.githubusercontent.com/u/52716446?v=4?s=110" width="110px;" alt="Phil J R"/><br /><sub><b>Phil J R</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PP-JN-RL" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://www.corelight.com/"><img src="https://avatars.githubusercontent.com/u/1496725?v=4?s=110" width="110px;" alt="i_virus"/><br /><sub><b>i_virus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chandanchowdhury" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gitgrimbo"><img src="https://avatars.githubusercontent.com/u/1020541?v=4?s=110" width="110px;" alt="Paul Grime"/><br /><sub><b>Paul Grime</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gitgrimbo" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://leeporte.co.uk"><img src="https://avatars.githubusercontent.com/u/922815?v=4?s=110" width="110px;" alt="Lee Porte"/><br /><sub><b>Lee Porte</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=LeePorte" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bryanlopezinc"><img src="https://avatars.githubusercontent.com/u/23613427?v=4?s=110" width="110px;" alt="BRYAN "/><br /><sub><b>BRYAN </b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bryanlopezinc" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=bryanlopezinc" title="Tests">⚠️</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/U-H-T"><img src="https://avatars.githubusercontent.com/u/64061710?v=4?s=110" width="110px;" alt="U-H-T"/><br /><sub><b>U-H-T</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=U-H-T" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tyree"><img src="https://avatars.githubusercontent.com/u/5395363?v=4?s=110" width="110px;" alt="Matt Tyree"/><br /><sub><b>Matt Tyree</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Tyree" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
+1
-1
@@ -105,7 +105,7 @@ RUN \
|
|||||||
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
|
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
|
||||||
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
|
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
|
||||||
&& chown docker "/var/lib/snipeit/keys/" \
|
&& chown docker "/var/lib/snipeit/keys/" \
|
||||||
&& chown -h docker "/var/www/html/storage/" \
|
&& chown -Rh docker "/var/www/html/storage/" \
|
||||||
&& chmod +x /var/www/html/artisan \
|
&& chmod +x /var/www/html/artisan \
|
||||||
&& echo "Finished setting up application in /var/www/html"
|
&& echo "Finished setting up application in /var/www/html"
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.18.5
|
FROM alpine:3.18.6
|
||||||
# Apache + PHP
|
# Apache + PHP
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
apache2 \
|
apache2 \
|
||||||
@@ -29,6 +29,7 @@ RUN apk add --no-cache \
|
|||||||
php81-sodium \
|
php81-sodium \
|
||||||
php81-redis \
|
php81-redis \
|
||||||
php81-pecl-memcached \
|
php81-pecl-memcached \
|
||||||
|
php81-exif \
|
||||||
curl \
|
curl \
|
||||||
wget \
|
wget \
|
||||||
vim \
|
vim \
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeitapp) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) [](https://github.com/snipe/snipe-it/actions/workflows/tests.yml)
|
[](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeitapp) [](https://app.codacy.com/gh/snipe/snipe-it/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [](https://github.com/snipe/snipe-it/actions/workflows/tests.yml)
|
||||||
[](#contributors) [](https://discord.gg/yZFtShAcKk)
|
[](#contributing) [](https://discord.gg/yZFtShAcKk)
|
||||||
|
|
||||||
## Snipe-IT - Open Source Asset Management System
|
## Snipe-IT - Open Source Asset Management System
|
||||||
|
|
||||||
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
|
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
|
||||||
|
|
||||||
It is built on [Laravel 8](http://laravel.com).
|
It is built on [Laravel 10](http://laravel.com).
|
||||||
|
|
||||||
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
||||||
|
|
||||||
__This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
|
> [!TIP]
|
||||||
|
> __This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, any flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ For instructions on installing and configuring Snipe-IT on your server, check ou
|
|||||||
|
|
||||||
If you're having trouble with the installation, please check the [Common Issues](https://snipe-it.readme.io/docs/common-issues) and [Getting Help](https://snipe-it.readme.io/docs/getting-help) documentation, and search this repository's open *and* closed issues for help.
|
If you're having trouble with the installation, please check the [Common Issues](https://snipe-it.readme.io/docs/common-issues) and [Getting Help](https://snipe-it.readme.io/docs/getting-help) documentation, and search this repository's open *and* closed issues for help.
|
||||||
|
|
||||||
[](https://heroku.com/deploy)
|
<!-- [](https://heroku.com/deploy) -->
|
||||||
|
|
||||||
-----
|
-----
|
||||||
### User's Manual
|
### User's Manual
|
||||||
@@ -32,8 +33,9 @@ For help using Snipe-IT, check out the [user's manual](https://snipe-it.readme.i
|
|||||||
|
|
||||||
Feel free to check out the [GitHub Issues for this project](https://github.com/snipe/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open *and* closed) to see if your question has already been answered before opening a new issue.
|
Feel free to check out the [GitHub Issues for this project](https://github.com/snipe/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open *and* closed) to see if your question has already been answered before opening a new issue.
|
||||||
|
|
||||||
**PLEASE see the [Getting Help Guidelines](https://snipe-it.readme.io/docs/getting-help) and [Common Issues](https://snipe-it.readme.io/docs/common-issues) before opening a ticket, and be sure to complete all of the questions in the Github Issue template to help us to help you as quickly as possible.**
|
> [!IMPORTANT]
|
||||||
|
> **PLEASE see the [Getting Help Guidelines](https://snipe-it.readme.io/docs/getting-help) and [Common Issues](https://snipe-it.readme.io/docs/common-issues) before opening a ticket, and be sure to complete all of the questions in the Github Issue template to help us to help you as quickly as possible.**
|
||||||
|
>
|
||||||
-----
|
-----
|
||||||
|
|
||||||
### Upgrading
|
### Upgrading
|
||||||
@@ -57,6 +59,9 @@ Please see the [translations documentation](https://snipe-it.readme.io/docs/tran
|
|||||||
|
|
||||||
Since the release of the JSON REST API, several third-party developers have been developing modules and libraries to work with Snipe-IT.
|
Since the release of the JSON REST API, several third-party developers have been developing modules and libraries to work with Snipe-IT.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
|
||||||
|
|
||||||
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
|
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
|
||||||
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
|
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
|
||||||
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
|
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
|
||||||
@@ -73,8 +78,6 @@ Since the release of the JSON REST API, several third-party developers have been
|
|||||||
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
|
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
|
||||||
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
|
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
|
||||||
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
|
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
|
||||||
|
|
||||||
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -92,4 +95,5 @@ The ERD is available [online here](https://drawsql.app/templates/snipe-it).
|
|||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.
|
> [!IMPORTANT]
|
||||||
|
> **To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.**
|
||||||
|
|||||||
+15
-2
@@ -45,8 +45,21 @@ DB_PASSWORD={}
|
|||||||
|
|
||||||
Now you are ready to run the entire test suite from your terminal:
|
Now you are ready to run the entire test suite from your terminal:
|
||||||
|
|
||||||
`php artisan test`
|
```shell
|
||||||
|
php artisan test
|
||||||
|
````
|
||||||
|
|
||||||
To run individual test files, you can pass the path to the test that you want to run:
|
To run individual test files, you can pass the path to the test that you want to run:
|
||||||
|
|
||||||
`php artisan test tests/Unit/AccessoryTest.php`
|
```shell
|
||||||
|
php artisan test tests/Unit/AccessoryTest.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Some tests, like ones concerning LDAP, are marked with the `@group` annotation. Those groups can be run, or excluded, using the `--group` or `--exclude-group` flags:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
php artisan test --group=ldap
|
||||||
|
|
||||||
|
php artisan test --exclude-group=ldap
|
||||||
|
```
|
||||||
|
This can be helpful if a set of tests are failing because you don't have an extension, like LDAP, installed.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"description": "The maximum number of search results that can be returned at one time.",
|
"description": "The maximum number of search results that can be returned at one time.",
|
||||||
"value": "500"
|
"value": "500"
|
||||||
},
|
},
|
||||||
"MAIL_DRIVER": {
|
"MAIL_MAILER": {
|
||||||
"description": "Mail driver - Generally SMTP on Heroku - https://snipe-it.readme.io/docs/configuration#required-outgoing-mail-settings",
|
"description": "Mail driver - Generally SMTP on Heroku - https://snipe-it.readme.io/docs/configuration#required-outgoing-mail-settings",
|
||||||
"value": "smtp"
|
"value": "smtp"
|
||||||
},
|
},
|
||||||
@@ -58,9 +58,9 @@
|
|||||||
"description": "SMTP Server Password",
|
"description": "SMTP Server Password",
|
||||||
"value": "YOURPASSWORD"
|
"value": "YOURPASSWORD"
|
||||||
},
|
},
|
||||||
"MAIL_ENCRYPTION": {
|
"MAIL_TLS_VERIFY_PEER": {
|
||||||
"description": "Encryption protocol for email sending.",
|
"description": "Ensure validity of TLS certificate on remote mail server",
|
||||||
"value": "null"
|
"value": true
|
||||||
},
|
},
|
||||||
"MAIL_FROM_ADDR": {
|
"MAIL_FROM_ADDR": {
|
||||||
"description": "Email from address",
|
"description": "Email from address",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use Illuminate\Console\Command;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Laravel\Passport\TokenRepository;
|
use Laravel\Passport\TokenRepository;
|
||||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class GeneratePersonalAccessToken extends Command
|
class GeneratePersonalAccessToken extends Command
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use App\Models\Setting;
|
|||||||
use App\Models\Ldap;
|
use App\Models\Ldap;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class LdapSync extends Command
|
class LdapSync extends Command
|
||||||
{
|
{
|
||||||
@@ -298,7 +298,7 @@ class LdapSync extends Command
|
|||||||
try {
|
try {
|
||||||
$ldap_manager = Ldap::findLdapUsers($item['manager'], -1, $this->option('filter'));
|
$ldap_manager = Ldap::findLdapUsers($item['manager'], -1, $this->option('filter'));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::warning("Manager lookup caused an exception: " . $e->getMessage() . ". Falling back to direct username lookup");
|
Log::warning("Manager lookup caused an exception: " . $e->getMessage() . ". Falling back to direct username lookup");
|
||||||
// Hail-mary for Okta manager 'shortnames' - will only work if
|
// Hail-mary for Okta manager 'shortnames' - will only work if
|
||||||
// Okta configuration is using full email-address-style usernames
|
// Okta configuration is using full email-address-style usernames
|
||||||
$ldap_manager = [
|
$ldap_manager = [
|
||||||
@@ -390,7 +390,7 @@ class LdapSync extends Command
|
|||||||
$user->location_id = $location->id;
|
$user->location_id = $location->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$location = null;
|
||||||
$user->ldap_import = 1;
|
$user->ldap_import = 1;
|
||||||
|
|
||||||
$errors = '';
|
$errors = '';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
|||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given ip is in a network
|
* Check if a given ip is in a network
|
||||||
@@ -160,7 +160,7 @@ class LdapTroubleshooter extends Command
|
|||||||
$output[] = "-x";
|
$output[] = "-x";
|
||||||
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
||||||
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
||||||
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
|
$output[] = "-w ".escapeshellarg(Crypt::Decrypt($settings->ldap_pword));
|
||||||
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
|
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
|
||||||
if($settings->ldap_tls) {
|
if($settings->ldap_tls) {
|
||||||
$this->line("# adding STARTTLS option");
|
$this->line("# adding STARTTLS option");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Events\UserMerged;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
@@ -51,7 +52,7 @@ class MergeUsersByUsername extends Command
|
|||||||
|
|
||||||
$bad_users = User::where('username', '=', trim($parts[0]))
|
$bad_users = User::where('username', '=', trim($parts[0]))
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
|
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
|
||||||
@@ -105,10 +106,26 @@ class MergeUsersByUsername extends Command
|
|||||||
$managedLocation->save();
|
$managedLocation->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($bad_user->uploads as $upload) {
|
||||||
|
$this->info('Updating upload log record '.$upload->id.' to user '.$user->id);
|
||||||
|
$upload->item_id = $user->id;
|
||||||
|
$upload->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($bad_user->acceptances as $acceptance) {
|
||||||
|
$this->info('Updating acceptance log record '.$acceptance->id.' to user '.$user->id);
|
||||||
|
$acceptance->item_id = $user->id;
|
||||||
|
$acceptance->save();
|
||||||
|
}
|
||||||
|
|
||||||
// Mark the user as deleted
|
// Mark the user as deleted
|
||||||
$this->info('Marking the user as deleted');
|
$this->info('Marking the user as deleted');
|
||||||
$bad_user->deleted_at = Carbon::now()->timestamp;
|
$bad_user->deleted_at = Carbon::now()->timestamp;
|
||||||
$bad_user->save();
|
$bad_user->save();
|
||||||
|
|
||||||
|
event(new UserMerged($bad_user, $user, null));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class MoveUploadsToNewDisk extends Command
|
class MoveUploadsToNewDisk extends Command
|
||||||
{
|
{
|
||||||
@@ -74,7 +75,7 @@ class MoveUploadsToNewDisk extends Command
|
|||||||
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
|
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
|
||||||
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
|
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +117,7 @@ class MoveUploadsToNewDisk extends Command
|
|||||||
$new_url = Storage::url($private_type . '/' . $filename, $filename);
|
$new_url = Storage::url($private_type . '/' . $filename, $filename);
|
||||||
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
|
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +141,7 @@ class MoveUploadsToNewDisk extends Command
|
|||||||
unlink($filename);
|
unlink($filename);
|
||||||
$public_delete_count++;
|
$public_delete_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +154,7 @@ class MoveUploadsToNewDisk extends Command
|
|||||||
unlink($filename);
|
unlink($filename);
|
||||||
$private_delete_count++;
|
$private_delete_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Console\Commands;
|
|||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
|
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
|
||||||
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
|
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
|
||||||
@@ -59,7 +60,7 @@ class ObjectImportCommand extends Command
|
|||||||
|
|
||||||
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
|
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
|
||||||
// $logFile = $this->option('logfile');
|
// $logFile = $this->option('logfile');
|
||||||
// \Log::useFiles($logFile);
|
// Log::useFiles($logFile);
|
||||||
$this->comment('======= Importing Items from '.$filename.' =========');
|
$this->comment('======= Importing Items from '.$filename.' =========');
|
||||||
$importer->import();
|
$importer->import();
|
||||||
|
|
||||||
@@ -112,10 +113,10 @@ class ObjectImportCommand extends Command
|
|||||||
public function log($string, $level = 'info')
|
public function log($string, $level = 'info')
|
||||||
{
|
{
|
||||||
if ($level === 'warning') {
|
if ($level === 'warning') {
|
||||||
\Log::warning($string);
|
Log::warning($string);
|
||||||
$this->comment($string);
|
$this->comment($string);
|
||||||
} else {
|
} else {
|
||||||
\Log::Info($string);
|
Log::Info($string);
|
||||||
if ($this->option('verbose')) {
|
if ($this->option('verbose')) {
|
||||||
$this->comment($string);
|
$this->comment($string);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use Schema;
|
use Schema;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class PaveIt extends Command
|
class PaveIt extends Command
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class RecryptFromMcrypt extends Command
|
|||||||
$this->comment('INFO: No LDAP password found. Skipping... ');
|
$this->comment('INFO: No LDAP password found. Skipping... ');
|
||||||
} else {
|
} else {
|
||||||
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
|
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
|
||||||
$settings->ldap_pword = \Crypt::encrypt($decrypted_ldap_pword);
|
$settings->ldap_pword = Crypt::encrypt($decrypted_ldap_pword);
|
||||||
$settings->save();
|
$settings->save();
|
||||||
}
|
}
|
||||||
/** @var CustomField[] $custom_fields */
|
/** @var CustomField[] $custom_fields */
|
||||||
@@ -132,7 +132,7 @@ class RecryptFromMcrypt extends Command
|
|||||||
// Try to decrypt the payload using the legacy app key
|
// Try to decrypt the payload using the legacy app key
|
||||||
try {
|
try {
|
||||||
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
|
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
|
||||||
$asset->{$columnName} = \Crypt::encrypt($decrypted_field);
|
$asset->{$columnName} = Crypt::encrypt($decrypted_field);
|
||||||
$this->comment($decrypted_field);
|
$this->comment($decrypted_field);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class RegenerateAssetTags extends Command
|
class RegenerateAssetTags extends Command
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use App\Models\Actionlog;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class RestoreDeletedUsers extends Command
|
class RestoreDeletedUsers extends Command
|
||||||
|
|||||||
@@ -4,6 +4,152 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class SQLStreamer {
|
||||||
|
private $input;
|
||||||
|
private $output;
|
||||||
|
// embed the prefix here?
|
||||||
|
public ?string $prefix;
|
||||||
|
|
||||||
|
private bool $reading_beginning_of_line = true;
|
||||||
|
|
||||||
|
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
||||||
|
|
||||||
|
public array $tablenames = [];
|
||||||
|
private bool $should_guess = false;
|
||||||
|
private bool $statement_is_permitted = false;
|
||||||
|
|
||||||
|
public function __construct($input, $output, string $prefix = null)
|
||||||
|
{
|
||||||
|
$this->input = $input;
|
||||||
|
$this->output = $output;
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse_sql(string $line): string {
|
||||||
|
// take into account the 'start of line or not' setting as an instance variable?
|
||||||
|
// 'continuation' lines for a permitted statement are PERMITTED.
|
||||||
|
if($this->statement_is_permitted && $line[0] === ' ') {
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table_regex = '`?([a-zA-Z0-9_]+)`?';
|
||||||
|
$allowed_statements = [
|
||||||
|
"/^(DROP TABLE (?:IF EXISTS )?)`$table_regex(.*)$/" => false,
|
||||||
|
"/^(CREATE TABLE )$table_regex(.*)$/" => true, //sets up 'continuation'
|
||||||
|
"/^(LOCK TABLES )$table_regex(.*)$/" => false,
|
||||||
|
"/^(INSERT INTO )$table_regex(.*)$/" => false,
|
||||||
|
"/^UNLOCK TABLES/" => false,
|
||||||
|
// "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here?
|
||||||
|
"/^\\)[a-zA-Z0-9_= ]*;$/" => false
|
||||||
|
// ^^^^^^ that bit should *exit* the 'perimitted' black
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach($allowed_statements as $statement => $statechange) {
|
||||||
|
// $this->info("Checking regex: $statement...\n");
|
||||||
|
$matches = [];
|
||||||
|
if (preg_match($statement,$line,$matches)) {
|
||||||
|
$this->statement_is_permitted = $statechange;
|
||||||
|
// matches are: 1 => first part of the statement, 2 => tablename, 3 => rest of statement
|
||||||
|
// (with of course 0 being "the whole match")
|
||||||
|
if (@$matches[2]) {
|
||||||
|
// print "Found a tablename! It's: ".$matches[2]."\n";
|
||||||
|
if ($this->should_guess) {
|
||||||
|
@$this->tablenames[$matches[2]] += 1;
|
||||||
|
continue; //oh? FIXME
|
||||||
|
} else {
|
||||||
|
$cleaned_tablename = \DB::getTablePrefix().preg_replace('/^'.$this->prefix.'/','',$matches[2]);
|
||||||
|
$line = preg_replace($statement,'$1`'.$cleaned_tablename.'`$3' , $line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no explicit tablename in this one, leave the line alone
|
||||||
|
}
|
||||||
|
//how do we *replace* the tablename?
|
||||||
|
// print "RETURNING LINE: $line";
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all that is not allowed is denied.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is used in exactly *TWO* places, and in both cases should return a prefix I think?
|
||||||
|
// first - if you do the --sanitize-only one (which is mostly for testing/development)
|
||||||
|
// next - when you run *without* a guessed prefix, this is run first to figure out the prefix
|
||||||
|
// I think we have to *duplicate* the call to be able to run it again?
|
||||||
|
public static function guess_prefix($input):string
|
||||||
|
{
|
||||||
|
$parser = new self($input, null);
|
||||||
|
$parser->should_guess = true;
|
||||||
|
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
|
||||||
|
|
||||||
|
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
|
||||||
|
//can't use 'users' because the 'accessories_users' table?
|
||||||
|
// can't use 'assets' because 'ver1_components_assets'
|
||||||
|
foreach($check_tables as $check_table => $_ignore) {
|
||||||
|
foreach ($parser->tablenames as $tablename => $_count) {
|
||||||
|
// print "Comparing $tablename to $check_table\n";
|
||||||
|
if (str_ends_with($tablename,$check_table)) {
|
||||||
|
// print "Found one!\n";
|
||||||
|
$check_tables[$check_table] = substr($tablename,0,-strlen($check_table));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$guessed_prefix = null;
|
||||||
|
foreach ($check_tables as $clean_table => $prefix_guess) {
|
||||||
|
if(is_null($prefix_guess)) {
|
||||||
|
print("Couldn't find table $clean_table\n");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
if(is_null($guessed_prefix)) {
|
||||||
|
$guessed_prefix = $prefix_guess;
|
||||||
|
} else {
|
||||||
|
if ($guessed_prefix != $prefix_guess) {
|
||||||
|
print("Prefix mismatch! Had guessed $guessed_prefix but got $prefix_guess\n");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $guessed_prefix;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function line_aware_piping(): int
|
||||||
|
{
|
||||||
|
$bytes_read = 0;
|
||||||
|
if (! $this->input) {
|
||||||
|
throw new \Exception("No Input available for line_aware_piping");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (($buffer = fgets($this->input, SQLStreamer::$buffer_size)) !== false) {
|
||||||
|
$bytes_read += strlen($buffer);
|
||||||
|
if ($this->reading_beginning_of_line) {
|
||||||
|
// Log::debug("Buffer is: '$buffer'");
|
||||||
|
$cleaned_buffer = $this->parse_sql($buffer);
|
||||||
|
if ($this->output) {
|
||||||
|
$bytes_written = fwrite($this->output, $cleaned_buffer);
|
||||||
|
|
||||||
|
if ($bytes_written === false) {
|
||||||
|
throw new \Exception("Unable to write to pipe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we got a newline at the end of this, then the _next_ read is the beginning of a line
|
||||||
|
if($buffer[strlen($buffer)-1] === "\n") {
|
||||||
|
$this->reading_beginning_of_line = true;
|
||||||
|
} else {
|
||||||
|
$this->reading_beginning_of_line = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return $bytes_read;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RestoreFromBackup extends Command
|
class RestoreFromBackup extends Command
|
||||||
{
|
{
|
||||||
@@ -12,10 +158,13 @@ class RestoreFromBackup extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
|
// FIXME - , stripping prefixes and nonstandard SQL statements. Without --prefix, guess and return the correct prefix to strip
|
||||||
protected $signature = 'snipeit:restore
|
protected $signature = 'snipeit:restore
|
||||||
{--force : Skip the danger prompt; assuming you enter "y"}
|
{--force : Skip the danger prompt; assuming you enter "y"}
|
||||||
{filename : The zip file to be migrated}
|
{filename : The zip file to be migrated}
|
||||||
{--no-progress : Don\'t show a progress bar}';
|
{--no-progress : Don\'t show a progress bar}
|
||||||
|
{--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL}
|
||||||
|
{--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
@@ -34,8 +183,6 @@ class RestoreFromBackup extends Command
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
@@ -45,7 +192,7 @@ class RestoreFromBackup extends Command
|
|||||||
{
|
{
|
||||||
$dir = getcwd();
|
$dir = getcwd();
|
||||||
if( $dir != base_path() ) { // usually only the case when running via webserver, not via command-line
|
if( $dir != base_path() ) { // usually only the case when running via webserver, not via command-line
|
||||||
\Log::debug("Current working directory is: $dir, changing directory to: ".base_path());
|
Log::debug("Current working directory is: $dir, changing directory to: ".base_path());
|
||||||
chdir(base_path()); // TODO - is this *safe* to change on a running script?!
|
chdir(base_path()); // TODO - is this *safe* to change on a running script?!
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -55,7 +202,7 @@ class RestoreFromBackup extends Command
|
|||||||
return $this->error('Missing required filename');
|
return $this->error('Missing required filename');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->option('force') && ! $this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
|
if (! $this->option('force') && ! $this->option('sanitize-guess-prefix') && ! $this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
|
||||||
return $this->error('Data loss not confirmed');
|
return $this->error('Data loss not confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,18 +298,18 @@ class RestoreFromBackup extends Command
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
|
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
|
||||||
\Log::debug("Found a sql file!");
|
Log::debug("Found a sql file!");
|
||||||
$sqlfiles[] = $raw_path;
|
$sqlfiles[] = $raw_path;
|
||||||
$sqlfile_indices[] = $i;
|
$sqlfile_indices[] = $i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_merge($private_dirs, $public_dirs) as $dir) {
|
foreach (array_merge($private_dirs, $public_dirs) as $dir) {
|
||||||
$last_pos = strrpos($raw_path, $dir.'/');
|
$last_pos = strrpos($raw_path, $dir . '/');
|
||||||
if ($last_pos !== false) {
|
if ($last_pos !== false) {
|
||||||
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
|
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
|
||||||
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
|
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
|
||||||
$interesting_files[$raw_path] = ['dest' =>$dir, 'index' => $i];
|
$interesting_files[$raw_path] = ['dest' => $dir, 'index' => $i];
|
||||||
continue 2;
|
continue 2;
|
||||||
if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) {
|
if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) {
|
||||||
// we don't care about that; we just want files with the appropriate prefix
|
// we don't care about that; we just want files with the appropriate prefix
|
||||||
@@ -171,7 +318,7 @@ class RestoreFromBackup extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$good_extensions = ['png', 'gif', 'jpg', 'svg', 'jpeg', 'doc', 'docx', 'pdf', 'txt',
|
$good_extensions = ['png', 'gif', 'jpg', 'svg', 'jpeg', 'doc', 'docx', 'pdf', 'txt',
|
||||||
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico', ];
|
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico',];
|
||||||
foreach (array_merge($private_files, $public_files) as $file) {
|
foreach (array_merge($private_files, $public_files) as $file) {
|
||||||
$has_wildcard = (strpos($file, '*') !== false);
|
$has_wildcard = (strpos($file, '*') !== false);
|
||||||
if ($has_wildcard) {
|
if ($has_wildcard) {
|
||||||
@@ -180,8 +327,8 @@ class RestoreFromBackup extends Command
|
|||||||
$last_pos = strrpos($raw_path, $file); // no trailing slash!
|
$last_pos = strrpos($raw_path, $file); // no trailing slash!
|
||||||
if ($last_pos !== false) {
|
if ($last_pos !== false) {
|
||||||
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
|
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
|
||||||
if (! in_array($extension, $good_extensions)) {
|
if (!in_array($extension, $good_extensions)) {
|
||||||
$this->warn('Potentially unsafe file '.$raw_path.' is being skipped');
|
$this->warn('Potentially unsafe file ' . $raw_path . ' is being skipped');
|
||||||
$boring_files[] = $raw_path;
|
$boring_files[] = $raw_path;
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
@@ -196,7 +343,6 @@ class RestoreFromBackup extends Command
|
|||||||
}
|
}
|
||||||
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
|
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
|
||||||
} // end of pre-processing the ZIP file for-loop
|
} // end of pre-processing the ZIP file for-loop
|
||||||
|
|
||||||
// print_r($interesting_files);exit(-1);
|
// print_r($interesting_files);exit(-1);
|
||||||
|
|
||||||
if (count($sqlfiles) != 1) {
|
if (count($sqlfiles) != 1) {
|
||||||
@@ -208,6 +354,17 @@ class RestoreFromBackup extends Command
|
|||||||
//older Snipe-IT installs don't have the db-dumps subdirectory component
|
//older Snipe-IT installs don't have the db-dumps subdirectory component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
||||||
|
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
||||||
|
$sql_contents = $za->getStream($sql_stat['name']); // maybe copy *THIS* thing?
|
||||||
|
|
||||||
|
// OKAY, now that we *found* the sql file if we're doing just the guess-prefix thing, we can do that *HERE* I think?
|
||||||
|
if ($this->option('sanitize-guess-prefix')) {
|
||||||
|
$prefix = SQLStreamer::guess_prefix($sql_contents);
|
||||||
|
$this->line($prefix);
|
||||||
|
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
||||||
|
}
|
||||||
|
|
||||||
//how to invoke the restore?
|
//how to invoke the restore?
|
||||||
$pipes = [];
|
$pipes = [];
|
||||||
|
|
||||||
@@ -228,6 +385,7 @@ class RestoreFromBackup extends Command
|
|||||||
return $this->error('Unable to invoke mysql via CLI');
|
return $this->error('Unable to invoke mysql via CLI');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I'm not sure about these?
|
||||||
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
||||||
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
||||||
|
|
||||||
@@ -238,9 +396,9 @@ class RestoreFromBackup extends Command
|
|||||||
|
|
||||||
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
|
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
|
||||||
|
|
||||||
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
// FIXME - this feels like it wants to go somewhere else?
|
||||||
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
// and it doesn't seem 'right' - if you can't get a stream to the .sql file,
|
||||||
$sql_contents = $za->getStream($sql_stat['name']);
|
// why do we care what's happening with pipes and stdout and stderr?!
|
||||||
if ($sql_contents === false) {
|
if ($sql_contents === false) {
|
||||||
$stdout = fgets($pipes[1]);
|
$stdout = fgets($pipes[1]);
|
||||||
$this->info($stdout);
|
$this->info($stdout);
|
||||||
@@ -249,29 +407,35 @@ class RestoreFromBackup extends Command
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$bytes_read = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
if ( $this->option('sanitize-with-prefix') === null) {
|
||||||
$bytes_read += strlen($buffer);
|
// "Legacy" direct-piping
|
||||||
// \Log::debug("Buffer is: '$buffer'");
|
$bytes_read = 0;
|
||||||
|
while (($buffer = fgets($sql_contents, SQLStreamer::$buffer_size)) !== false) {
|
||||||
|
$bytes_read += strlen($buffer);
|
||||||
|
// Log::debug("Buffer is: '$buffer'");
|
||||||
$bytes_written = fwrite($pipes[0], $buffer);
|
$bytes_written = fwrite($pipes[0], $buffer);
|
||||||
|
|
||||||
if ($bytes_written === false) {
|
if ($bytes_written === false) {
|
||||||
throw new Exception("Unable to write to pipe");
|
throw new Exception("Unable to write to pipe");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$sql_importer = new SQLStreamer($sql_contents, $pipes[0], $this->option('sanitize-with-prefix'));
|
||||||
|
$bytes_read = $sql_importer->line_aware_piping();
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
Log::error("Error during restore!!!! ".$e->getMessage());
|
||||||
|
// FIXME - put these back and/or put them in the right places?!
|
||||||
$err_out = fgets($pipes[1]);
|
$err_out = fgets($pipes[1]);
|
||||||
$err_err = fgets($pipes[2]);
|
$err_err = fgets($pipes[2]);
|
||||||
\Log::error("Error OUTPUT: ".$err_out);
|
Log::error("Error OUTPUT: ".$err_out);
|
||||||
$this->info($err_out);
|
$this->info($err_out);
|
||||||
\Log::error("Error ERROR : ".$err_err);
|
Log::error("Error ERROR : ".$err_err);
|
||||||
$this->error($err_err);
|
$this->error($err_err);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!feof($sql_contents) || $bytes_read == 0) {
|
if (!feof($sql_contents) || $bytes_read == 0) {
|
||||||
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
||||||
}
|
}
|
||||||
@@ -303,7 +467,7 @@ class RestoreFromBackup extends Command
|
|||||||
$fp = $za->getStream($ugly_file_name);
|
$fp = $za->getStream($ugly_file_name);
|
||||||
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
||||||
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
||||||
while (($buffer = fgets($fp, self::$buffer_size)) !== false) {
|
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
|
||||||
fwrite($migrated_file, $buffer);
|
fwrite($migrated_file, $buffer);
|
||||||
}
|
}
|
||||||
fclose($migrated_file);
|
fclose($migrated_file);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Illuminate\Encryption\Encrypter;
|
use Illuminate\Encryption\Encrypter;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class SendCurrentInventoryToUsers extends Command
|
|||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0)) {
|
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0) || ($user->consumables->count() > 0)) {
|
||||||
$count++;
|
$count++;
|
||||||
$user->notify((new CurrentInventory($user)));
|
$user->notify((new CurrentInventory($user)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use App\Notifications\ExpectedCheckinAdminNotification;
|
|||||||
use App\Notifications\ExpectedCheckinNotification;
|
use App\Notifications\ExpectedCheckinNotification;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class SendExpectedCheckinAlerts extends Command
|
class SendExpectedCheckinAlerts extends Command
|
||||||
{
|
{
|
||||||
@@ -43,25 +42,31 @@ class SendExpectedCheckinAlerts extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$whenNotify = Carbon::now();
|
$interval = $settings->audit_warning_days ?? 0;
|
||||||
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
$today = Carbon::now();
|
||||||
|
$interval_date = $today->copy()->addDays($interval);
|
||||||
|
|
||||||
|
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForCheckin($settings)->orderBy('assets.expected_checkin', 'desc')->get();
|
||||||
|
|
||||||
|
$this->info($assets->count().' assets must be checked in on or before '.$interval_date.' is deadline');
|
||||||
|
|
||||||
$this->info($whenNotify.' is deadline');
|
|
||||||
$this->info($assets->count().' assets');
|
|
||||||
|
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
if ($asset->assigned && $asset->checkedOutToUser()) {
|
if ($asset->assignedTo && (isset($asset->assignedTo->email)) && ($asset->assignedTo->email!='') && $asset->checkedOutToUser()) {
|
||||||
Log::info('Sending ExpectedCheckinNotification to ' . $asset->assigned->email);
|
$this->info('Sending User ExpectedCheckinNotification to: '.$asset->assignedTo->email);
|
||||||
$asset->assigned->notify((new ExpectedCheckinNotification($asset)));
|
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
||||||
// Send a rollup to the admin, if settings dictate
|
// Send a rollup to the admin, if settings dictate
|
||||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
|
||||||
return new AlertRecipient($item);
|
return new AlertRecipient($item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->info('Sending Admin ExpectedCheckinNotification to: '.$settings->alert_email);
|
||||||
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
|
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,11 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\License;
|
use App\Models\Recipients\AlertRecipient;
|
||||||
use App\Models\Recipients;
|
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Notifications\ExpiringAssetsNotification;
|
|
||||||
use App\Notifications\SendUpcomingAuditNotification;
|
use App\Notifications\SendUpcomingAuditNotification;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SendUpcomingAuditReport extends Command
|
class SendUpcomingAuditReport extends Command
|
||||||
@@ -46,39 +44,24 @@ class SendUpcomingAuditReport extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
$interval = $settings->audit_warning_days ?? 0;
|
||||||
|
$today = Carbon::now();
|
||||||
|
$interval_date = $today->copy()->addDays($interval);
|
||||||
|
|
||||||
if (($settings->alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) {
|
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
|
||||||
|
$this->info($assets->count().' assets must be audited in on or before '.$interval_date.' is deadline');
|
||||||
|
|
||||||
|
|
||||||
|
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
||||||
// Send a rollup to the admin, if settings dictate
|
// Send a rollup to the admin, if settings dictate
|
||||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
|
||||||
return new \App\Models\Recipients\AlertRecipient($item);
|
return new AlertRecipient($item);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assets due for auditing
|
$this->info('Sending Admin SendUpcomingAuditNotification to: '.$settings->alert_email);
|
||||||
|
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
|
||||||
|
|
||||||
$assets = Asset::whereNotNull('next_audit_date')
|
|
||||||
->DueOrOverdueForAudit($settings)
|
|
||||||
->orderBy('last_audit_date', 'asc')->get();
|
|
||||||
|
|
||||||
if ($assets->count() > 0) {
|
|
||||||
$this->info(trans_choice('mail.upcoming-audits', $assets->count(),
|
|
||||||
['count' => $assets->count(), 'threshold' => $settings->audit_warning_days]));
|
|
||||||
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
|
|
||||||
$this->info('Audit report sent to '.$settings->alert_email);
|
|
||||||
} else {
|
|
||||||
$this->info('No assets to be audited. No report sent.');
|
|
||||||
}
|
|
||||||
} elseif ($settings->alert_email == '') {
|
|
||||||
$this->error('Could not send email. No alert email configured in settings');
|
|
||||||
} elseif (! $settings->audit_warning_days) {
|
|
||||||
$this->error('No audit warning days set in Admin Notifications. No mail will be sent.');
|
|
||||||
} elseif ($settings->alerts_enabled != 1) {
|
|
||||||
$this->info('Alerts are disabled in the settings. No mail will be sent');
|
|
||||||
} else {
|
|
||||||
$this->error('Something went wrong. :( ');
|
|
||||||
$this->error('Admin Notifications Email Setting: '.$settings->alert_email);
|
|
||||||
$this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days);
|
|
||||||
$this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class SyncAssetCounters extends Command
|
class SyncAssetCounters extends Command
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ class SyncAssetCounters extends Command
|
|||||||
$asset->save();
|
$asset->save();
|
||||||
$bar->advance();
|
$bar->advance();
|
||||||
|
|
||||||
\Log::debug('Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests');
|
Log::debug('Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\CustomField;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class ToggleCustomfieldEncryption extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'snipeit:customfield-encryption
|
||||||
|
{fieldname : the db_column_name of the field}';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'This command should be used to convert an unencrypted custom field into a custom field and encrypt the associated data in the assets table for that column.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$fieldname = $this->argument('fieldname');
|
||||||
|
|
||||||
|
if ($field = CustomField::where('db_column', $fieldname)->first()) {
|
||||||
|
|
||||||
|
// If the field is not encrypted, make it encrypted and encrypt the data in the assets table for the
|
||||||
|
// corresponding field.
|
||||||
|
DB::transaction(function () use ($field) {
|
||||||
|
|
||||||
|
if ($field->field_encrypted == 0) {
|
||||||
|
$assets = Asset::whereNotNull($field->db_column)->get();
|
||||||
|
|
||||||
|
foreach ($assets as $asset) {
|
||||||
|
$asset->{$field->db_column} = encrypt($asset->{$field->db_column});
|
||||||
|
$asset->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$field->field_encrypted = 1;
|
||||||
|
$field->save();
|
||||||
|
|
||||||
|
// This field is already encrypted. Do nothing.
|
||||||
|
} else {
|
||||||
|
$this->error('The custom field ' . $field->db_column.' is already encrypted. No action was taken.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// No matching column name found
|
||||||
|
} else {
|
||||||
|
$this->error('No matching results for unencrypted custom fields with db_column name: ' . $fieldname.'. Please check the fieldname.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ class UserMerged
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(User $from_user, User $to_user, User $admin)
|
public function __construct(User $from_user, User $to_user, ?User $admin)
|
||||||
{
|
{
|
||||||
$this->merged_from = $from_user;
|
$this->merged_from = $from_user;
|
||||||
$this->merged_to = $to_user;
|
$this->merged_to = $to_user;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use App\Helpers\Helper;
|
|||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
|
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use JsonException;
|
use JsonException;
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
@@ -44,8 +44,8 @@ class Handler extends ExceptionHandler
|
|||||||
public function report(Throwable $exception)
|
public function report(Throwable $exception)
|
||||||
{
|
{
|
||||||
if ($this->shouldReport($exception)) {
|
if ($this->shouldReport($exception)) {
|
||||||
if (class_exists(\Log::class)) {
|
if (class_exists(Log::class)) {
|
||||||
\Log::error($exception);
|
Log::error($exception);
|
||||||
}
|
}
|
||||||
return parent::report($exception);
|
return parent::report($exception);
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-14
@@ -11,10 +11,13 @@ use App\Models\CustomFieldset;
|
|||||||
use App\Models\Depreciation;
|
use App\Models\Depreciation;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\Statuslabel;
|
use App\Models\Statuslabel;
|
||||||
use Crypt;
|
use App\Models\License;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Image;
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Intervention\Image\ImageManagerStatic as Image;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class Helper
|
class Helper
|
||||||
{
|
{
|
||||||
@@ -411,7 +414,7 @@ class Helper
|
|||||||
|
|
||||||
if ($index >= $total_colors) {
|
if ($index >= $total_colors) {
|
||||||
|
|
||||||
\Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
||||||
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
||||||
$index = $index - $total_colors - 1;
|
$index = $index - $total_colors - 1;
|
||||||
|
|
||||||
@@ -715,18 +718,19 @@ class Helper
|
|||||||
*/
|
*/
|
||||||
public static function checkLowInventory()
|
public static function checkLowInventory()
|
||||||
{
|
{
|
||||||
|
$alert_threshold = \App\Models\Setting::getSettings()->alert_threshold;
|
||||||
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
|
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
|
||||||
$accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get();
|
$accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get();
|
||||||
$components = Component::whereNotNull('min_amt')->get();
|
$components = Component::whereNotNull('min_amt')->get();
|
||||||
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
|
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
|
||||||
|
$licenses = License::where('min_amt', '>', 0)->get();
|
||||||
|
|
||||||
$avail_consumables = 0;
|
|
||||||
$items_array = [];
|
$items_array = [];
|
||||||
$all_count = 0;
|
$all_count = 0;
|
||||||
|
|
||||||
foreach ($consumables as $consumable) {
|
foreach ($consumables as $consumable) {
|
||||||
$avail = $consumable->numRemaining();
|
$avail = $consumable->numRemaining();
|
||||||
if ($avail < ($consumable->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
if ($avail < ($consumable->min_amt) + $alert_threshold) {
|
||||||
if ($consumable->qty > 0) {
|
if ($consumable->qty > 0) {
|
||||||
$percent = number_format((($avail / $consumable->qty) * 100), 0);
|
$percent = number_format((($avail / $consumable->qty) * 100), 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -745,7 +749,7 @@ class Helper
|
|||||||
|
|
||||||
foreach ($accessories as $accessory) {
|
foreach ($accessories as $accessory) {
|
||||||
$avail = $accessory->qty - $accessory->users_count;
|
$avail = $accessory->qty - $accessory->users_count;
|
||||||
if ($avail < ($accessory->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
if ($avail < ($accessory->min_amt) + $alert_threshold) {
|
||||||
if ($accessory->qty > 0) {
|
if ($accessory->qty > 0) {
|
||||||
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -764,7 +768,7 @@ class Helper
|
|||||||
|
|
||||||
foreach ($components as $component) {
|
foreach ($components as $component) {
|
||||||
$avail = $component->numRemaining();
|
$avail = $component->numRemaining();
|
||||||
if ($avail < ($component->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
if ($avail < ($component->min_amt) + $alert_threshold) {
|
||||||
if ($component->qty > 0) {
|
if ($component->qty > 0) {
|
||||||
$percent = number_format((($avail / $component->qty) * 100), 0);
|
$percent = number_format((($avail / $component->qty) * 100), 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -787,7 +791,7 @@ class Helper
|
|||||||
$total_owned = $asset->where('model_id', '=', $asset_model->id)->count();
|
$total_owned = $asset->where('model_id', '=', $asset_model->id)->count();
|
||||||
$avail = $asset->where('model_id', '=', $asset_model->id)->whereNull('assigned_to')->count();
|
$avail = $asset->where('model_id', '=', $asset_model->id)->whereNull('assigned_to')->count();
|
||||||
|
|
||||||
if ($avail < ($asset_model->min_amt)+ \App\Models\Setting::getSettings()->alert_threshold) {
|
if ($avail < ($asset_model->min_amt) + $alert_threshold) {
|
||||||
if ($avail > 0) {
|
if ($avail > 0) {
|
||||||
$percent = number_format((($avail / $total_owned) * 100), 0);
|
$percent = number_format((($avail / $total_owned) * 100), 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -803,6 +807,26 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($licenses as $license){
|
||||||
|
$avail = $license->remaincount();
|
||||||
|
if ($avail < ($license->min_amt) + $alert_threshold) {
|
||||||
|
if ($avail > 0) {
|
||||||
|
$percent = number_format((($avail / $license->min_amt) * 100), 0);
|
||||||
|
} else {
|
||||||
|
$percent = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items_array[$all_count]['id'] = $license->id;
|
||||||
|
$items_array[$all_count]['name'] = $license->name;
|
||||||
|
$items_array[$all_count]['type'] = 'licenses';
|
||||||
|
$items_array[$all_count]['percent'] = $percent;
|
||||||
|
$items_array[$all_count]['remaining'] = $avail;
|
||||||
|
$items_array[$all_count]['min_amt'] = $license->min_amt;
|
||||||
|
$all_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return $items_array;
|
return $items_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,7 +844,7 @@ class Helper
|
|||||||
$filetype = @finfo_file($finfo, $file);
|
$filetype = @finfo_file($finfo, $file);
|
||||||
finfo_close($finfo);
|
finfo_close($finfo);
|
||||||
|
|
||||||
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif')) {
|
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif') || ($filetype == 'image/avif')) {
|
||||||
return $filetype;
|
return $filetype;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,12 +877,15 @@ class Helper
|
|||||||
$permission_name = $permission[$x]['permission'];
|
$permission_name = $permission[$x]['permission'];
|
||||||
|
|
||||||
if ($permission[$x]['display'] === true) {
|
if ($permission[$x]['display'] === true) {
|
||||||
if ($selected_arr) {
|
|
||||||
|
if (is_array($selected_arr)) {
|
||||||
|
|
||||||
if (array_key_exists($permission_name, $selected_arr)) {
|
if (array_key_exists($permission_name, $selected_arr)) {
|
||||||
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
|
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
|
||||||
} else {
|
} else {
|
||||||
$permissions_arr[$permission_name] = '0';
|
$permissions_arr[$permission_name] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$permissions_arr[$permission_name] = '0';
|
$permissions_arr[$permission_name] = '0';
|
||||||
}
|
}
|
||||||
@@ -990,7 +1017,7 @@ class Helper
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tmp_date = new \Carbon($date);
|
$tmp_date = new Carbon($date);
|
||||||
|
|
||||||
if ($type == 'datetime') {
|
if ($type == 'datetime') {
|
||||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||||
@@ -1007,7 +1034,7 @@ class Helper
|
|||||||
return $dt['formatted'];
|
return $dt['formatted'];
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::warning($e);
|
Log::warning($e);
|
||||||
return $date.' (Invalid '.$type.' value.)';
|
return $date.' (Invalid '.$type.' value.)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,6 +1111,8 @@ class Helper
|
|||||||
'jpeg' => 'far fa-image',
|
'jpeg' => 'far fa-image',
|
||||||
'gif' => 'far fa-image',
|
'gif' => 'far fa-image',
|
||||||
'png' => 'far fa-image',
|
'png' => 'far fa-image',
|
||||||
|
'webp' => 'far fa-image',
|
||||||
|
'avif' => 'far fa-image',
|
||||||
// word
|
// word
|
||||||
'doc' => 'far fa-file-word',
|
'doc' => 'far fa-file-word',
|
||||||
'docx' => 'far fa-file-word',
|
'docx' => 'far fa-file-word',
|
||||||
@@ -1119,6 +1148,8 @@ class Helper
|
|||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
case 'gif':
|
case 'gif':
|
||||||
case 'png':
|
case 'png':
|
||||||
|
case 'webp':
|
||||||
|
case 'avif':
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1316,7 +1347,7 @@ class Helper
|
|||||||
public static function isDemoMode() {
|
public static function isDemoMode() {
|
||||||
if (config('app.lock_passwords') === true) {
|
if (config('app.lock_passwords') === true) {
|
||||||
return true;
|
return true;
|
||||||
\Log::debug('app locked!');
|
Log::debug('app locked!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1409,7 +1440,7 @@ class Helper
|
|||||||
|
|
||||||
foreach (self::$language_map as $legacy => $new) {
|
foreach (self::$language_map as $legacy => $new) {
|
||||||
if ($language_code == $legacy) {
|
if ($language_code == $legacy) {
|
||||||
\Log::debug('Current language is '.$legacy.', using '.$new.' instead');
|
Log::debug('Current language is '.$legacy.', using '.$new.' instead');
|
||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1433,4 +1464,38 @@ class Helper
|
|||||||
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static public function getRedirectOption($request, $id, $table, $asset_id = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
$redirect_option = Session::get('redirect_option');
|
||||||
|
$checkout_to_type = Session::get('checkout_to_type');
|
||||||
|
|
||||||
|
//return to index
|
||||||
|
if ($redirect_option == '0') {
|
||||||
|
switch ($table) {
|
||||||
|
case "Assets":
|
||||||
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return to thing being assigned
|
||||||
|
if ($redirect_option == '1') {
|
||||||
|
switch ($table) {
|
||||||
|
case "Assets":
|
||||||
|
return redirect()->route('hardware.show', $id ? $id : $asset_id)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return to thing being assigned to
|
||||||
|
if ($redirect_option == '2') {
|
||||||
|
switch ($checkout_to_type) {
|
||||||
|
case 'user':
|
||||||
|
return redirect()->route('users.show', $request->assigned_user)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
case 'location':
|
||||||
|
return redirect()->route('locations.show', $request->assigned_location)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
case 'asset':
|
||||||
|
return redirect()->route('hardware.show', $request->assigned_asset)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/** This controller handles all actions related to Accessories for
|
/** This controller handles all actions related to Accessories for
|
||||||
* the Snipe-IT Asset Management application.
|
* the Snipe-IT Asset Management application.
|
||||||
@@ -57,7 +58,7 @@ class AccessoriesController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request)
|
||||||
@@ -150,7 +151,7 @@ class AccessoriesController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $accessoryId = null)
|
public function update(ImageUploadRequest $request, $accessoryId = null)
|
||||||
@@ -204,7 +205,7 @@ class AccessoriesController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function destroy($accessoryId)
|
public function destroy($accessoryId)
|
||||||
@@ -224,7 +225,7 @@ class AccessoriesController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
|
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,28 +4,28 @@ namespace App\Http\Controllers\Accessories;
|
|||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class AccessoriesFilesController extends Controller
|
class AccessoriesFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a accessory.
|
* Validates and stores files associated with a accessory.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $accessoryId = null)
|
public function store(UploadFileRequest $request, $accessoryId = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
@@ -45,30 +45,7 @@ class AccessoriesFilesController extends Controller
|
|||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
|
||||||
$extension = $file->getClientOriginalExtension();
|
$file_name = $request->handleFile('private_uploads/accessories/', 'accessory-'.$accessory->id, $file);
|
||||||
$file_name = 'accessory-'.$accessory->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/accessories/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/accessories/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$accessory->logUpload($file_name, e($request->input('notes')));
|
$accessory->logUpload($file_name, e($request->input('notes')));
|
||||||
}
|
}
|
||||||
@@ -109,7 +86,7 @@ class AccessoriesFilesController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::delete('accessories/'.$log->filename);
|
Storage::delete('accessories/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +113,7 @@ class AccessoriesFilesController extends Controller
|
|||||||
public function show($accessoryId = null, $fileId = null, $download = true)
|
public function show($accessoryId = null, $fileId = null, $download = true)
|
||||||
{
|
{
|
||||||
|
|
||||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||||
$accessory = Accessory::find($accessoryId);
|
$accessory = Accessory::find($accessoryId);
|
||||||
|
|
||||||
|
|
||||||
@@ -153,8 +130,8 @@ class AccessoriesFilesController extends Controller
|
|||||||
$file = 'private_uploads/accessories/'.$log->filename;
|
$file = 'private_uploads/accessories/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class AccessoryCheckinController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param null $accessoryUserId
|
* @param null $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
* @internal param int $accessoryId
|
* @internal param int $accessoryId
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class AccessoryCheckoutController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $accessoryId)
|
public function store(Request $request, $accessoryId)
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ use App\Notifications\AcceptanceAssetAcceptedNotification;
|
|||||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Http\Controllers\SettingsController;
|
use App\Http\Controllers\SettingsController;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use phpDocumentor\Reflection\Types\Compound;
|
use phpDocumentor\Reflection\Types\Compound;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class AcceptanceController extends Controller
|
class AcceptanceController extends Controller
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,7 @@ class AcceptanceController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $id)
|
public function store(Request $request, $id)
|
||||||
{
|
{
|
||||||
@@ -223,6 +223,7 @@ class AcceptanceController extends Controller
|
|||||||
'item_model' => $display_model,
|
'item_model' => $display_model,
|
||||||
'item_serial' => $item->serial,
|
'item_serial' => $item->serial,
|
||||||
'eula' => $item->getEula(),
|
'eula' => $item->getEula(),
|
||||||
|
'note' => $request->input('note'),
|
||||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
||||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
||||||
'assigned_to' => $assigned_to,
|
'assigned_to' => $assigned_to,
|
||||||
@@ -233,12 +234,12 @@ class AcceptanceController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
if ($pdf_view_route!='') {
|
||||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||||
}
|
}
|
||||||
|
|
||||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename);
|
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||||
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
||||||
event(new CheckoutAccepted($acceptance));
|
event(new CheckoutAccepted($acceptance));
|
||||||
|
|
||||||
@@ -306,10 +307,12 @@ class AcceptanceController extends Controller
|
|||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'item_tag' => $item->asset_tag,
|
'item_tag' => $item->asset_tag,
|
||||||
'item_model' => $display_model,
|
'item_model' => $display_model,
|
||||||
'item_serial' => $item->serial,
|
'item_serial' => $item->serial,
|
||||||
|
'note' => $request->input('note'),
|
||||||
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
|
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
|
||||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||||
'assigned_to' => $assigned_to,
|
'assigned_to' => $assigned_to,
|
||||||
@@ -318,12 +321,12 @@ class AcceptanceController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
if ($pdf_view_route!='') {
|
||||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||||
}
|
}
|
||||||
|
|
||||||
$acceptance->decline($sig_filename);
|
$acceptance->decline($sig_filename, $request->input('note'));
|
||||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||||
event(new CheckoutDeclined($acceptance));
|
event(new CheckoutDeclined($acceptance));
|
||||||
$return_msg = trans('admin/users/message.declined');
|
$return_msg = trans('admin/users/message.declined');
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
class ActionlogController extends Controller
|
class ActionlogController extends Controller
|
||||||
{
|
{
|
||||||
public function displaySig($filename)
|
public function displaySig($filename)
|
||||||
@@ -14,19 +15,26 @@ class ActionlogController extends Controller
|
|||||||
// file_get_contents, so we set the error reporting for just this class
|
// file_get_contents, so we set the error reporting for just this class
|
||||||
error_reporting(0);
|
error_reporting(0);
|
||||||
|
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
$disk = config('filesystems.default');
|
||||||
$file = config('app.private_uploads').'/signatures/'.$filename;
|
switch (config("filesystems.disks.$disk.driver")) {
|
||||||
$filetype = Helper::checkUploadIsImage($file);
|
case 's3':
|
||||||
|
$file = 'private_uploads/signatures/'.$filename;
|
||||||
|
return redirect()->away(Storage::disk($disk)->temporaryUrl($file, now()->addMinutes(5)));
|
||||||
|
default:
|
||||||
|
$this->authorize('view', \App\Models\Asset::class);
|
||||||
|
$file = config('app.private_uploads').'/signatures/'.$filename;
|
||||||
|
$filetype = Helper::checkUploadIsImage($file);
|
||||||
|
|
||||||
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
|
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
|
||||||
if ($contents === false) {
|
if ($contents === false) {
|
||||||
\Log::warn('File '.$file.' not found');
|
Log::warning('File '.$file.' not found');
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return Response::make($contents)->header('Content-Type', $filetype);
|
return Response::make($contents)->header('Content-Type', $filetype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStoredEula($filename){
|
public function getStoredEula($filename){
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
$this->authorize('view', \App\Models\Asset::class);
|
||||||
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\AccessoriesTransformer;
|
use App\Http\Transformers\AccessoriesTransformer;
|
||||||
@@ -9,9 +10,9 @@ use App\Http\Transformers\SelectlistTransformer;
|
|||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
|
||||||
@@ -273,12 +274,12 @@ class AccessoriesController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function checkout(Request $request, $accessoryId)
|
public function checkout(Request $request, $accessoryId)
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
// Check if the accessory exists
|
||||||
if (is_null($accessory = Accessory::find($accessoryId))) {
|
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +303,7 @@ class AccessoriesController extends Controller
|
|||||||
'note' => $request->get('note'),
|
'note' => $request->get('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$accessory->logCheckout($request->input('note'), $user);
|
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
||||||
}
|
}
|
||||||
@@ -319,7 +320,7 @@ class AccessoriesController extends Controller
|
|||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryUserId
|
* @param int $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @internal param int $accessoryId
|
* @internal param int $accessoryId
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $accessoryUserId = null)
|
public function checkin(Request $request, $accessoryUserId = null)
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\StorageHelper;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\AssetModel;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use \Illuminate\Support\Facades\Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DB;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Http\Requests\UploadFileRequest;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Input;
|
||||||
|
use Paginator;
|
||||||
|
use Slack;
|
||||||
|
use Str;
|
||||||
|
use TCPDF;
|
||||||
|
use Validator;
|
||||||
|
use Route;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class controls file related actions related
|
||||||
|
* to assets for the Snipe-IT Asset Management application.
|
||||||
|
*
|
||||||
|
* Based on the Assets/AssetFilesController by A. Gianotto <snipe@snipe.net>
|
||||||
|
*
|
||||||
|
* @version v1.0
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
class AssetFilesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Accepts a POST to upload a file to the server.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param int $assetId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function store(UploadFileRequest $request, $assetId = null)
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we are allowed to update this asset
|
||||||
|
$this->authorize('update', $asset);
|
||||||
|
|
||||||
|
if ($request->hasFile('file')) {
|
||||||
|
// If the file storage directory doesn't exist; create it
|
||||||
|
if (! Storage::exists('private_uploads/assets')) {
|
||||||
|
Storage::makeDirectory('private_uploads/assets', 775);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over the attached files and add them to the asset
|
||||||
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||||
|
|
||||||
|
$asset->logUpload($file_name, e($request->get('notes')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done - report success
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only reach here if no files were included in the POST, so tell the user this
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.upload.nofiles')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the files for an asset.
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function list($assetId = null)
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the asset is valid
|
||||||
|
if (isset($asset->id)) {
|
||||||
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
|
// Check that there are some uploads on this asset that can be listed
|
||||||
|
if ($asset->uploads->count() > 0) {
|
||||||
|
$files = array();
|
||||||
|
foreach ($asset->uploads as $upload) {
|
||||||
|
array_push($files, $upload);
|
||||||
|
}
|
||||||
|
// Give the list of files back to the user
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $files, trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are no files.
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', array(), trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back an error message
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for permissions and display the file.
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @param int $fileId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function show($assetId = null, $fileId = null)
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the asset is valid
|
||||||
|
if (isset($asset->id)) {
|
||||||
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
|
// Check that the file being requested exists for the asset
|
||||||
|
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.no_match', ['id' => $fileId])), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form the full filename with path
|
||||||
|
$file = 'private_uploads/assets/'.$log->filename;
|
||||||
|
\Log::debug('Checking for '.$file);
|
||||||
|
|
||||||
|
if ($log->action_type == 'audit') {
|
||||||
|
$file = 'private_uploads/audits/'.$log->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the file actually exists on the filesystem
|
||||||
|
if (! Storage::exists($file)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.does_not_exist', ['id' => $fileId])), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request('inline') == 'true') {
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Content-Disposition' => 'inline',
|
||||||
|
];
|
||||||
|
|
||||||
|
return Storage::download($file, $log->filename, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StorageHelper::downloader($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back an error message
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error', ['id' => $fileId])), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the associated file
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @param int $fileId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function destroy($assetId = null, $fileId = null)
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rel_path = 'private_uploads/assets';
|
||||||
|
|
||||||
|
// the asset is valid
|
||||||
|
if (isset($asset->id)) {
|
||||||
|
$this->authorize('update', $asset);
|
||||||
|
|
||||||
|
// Check for the file
|
||||||
|
$log = Actionlog::find($fileId);
|
||||||
|
if ($log) {
|
||||||
|
// Check the file actually exists, and delete it
|
||||||
|
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||||
|
Storage::delete($rel_path.'/'.$log->filename);
|
||||||
|
}
|
||||||
|
// Delete the record of the file
|
||||||
|
$log->delete();
|
||||||
|
|
||||||
|
// All deleting done - notify the user of success
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.deletefile.success')), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The file doesn't seem to really exist, so report an error
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use App\Http\Transformers\AssetMaintenancesTransformer;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetMaintenance;
|
use App\Models\AssetMaintenance;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
@@ -36,7 +36,8 @@ class AssetMaintenancesController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'admin');
|
$maintenances = AssetMaintenance::select('asset_maintenances.*')
|
||||||
|
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'admin');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$maintenances = $maintenances->TextSearch($request->input('search'));
|
$maintenances = $maintenances->TextSearch($request->input('search'));
|
||||||
@@ -47,7 +48,7 @@ class AssetMaintenancesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('supplier_id')) {
|
if ($request->filled('supplier_id')) {
|
||||||
$maintenances->where('supplier_id', '=', $request->input('supplier_id'));
|
$maintenances->where('asset_maintenances.supplier_id', '=', $request->input('supplier_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('asset_maintenance_type')) {
|
if ($request->filled('asset_maintenance_type')) {
|
||||||
@@ -70,10 +71,13 @@ class AssetMaintenancesController extends Controller
|
|||||||
'notes',
|
'notes',
|
||||||
'asset_tag',
|
'asset_tag',
|
||||||
'asset_name',
|
'asset_name',
|
||||||
|
'serial',
|
||||||
'user_id',
|
'user_id',
|
||||||
'supplier',
|
'supplier',
|
||||||
'is_warranty',
|
'is_warranty',
|
||||||
|
'status_label',
|
||||||
];
|
];
|
||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||||
|
|
||||||
@@ -90,6 +94,12 @@ class AssetMaintenancesController extends Controller
|
|||||||
case 'asset_name':
|
case 'asset_name':
|
||||||
$maintenances = $maintenances->OrderByAssetName($order);
|
$maintenances = $maintenances->OrderByAssetName($order);
|
||||||
break;
|
break;
|
||||||
|
case 'serial':
|
||||||
|
$maintenances = $maintenances->OrderByAssetSerial($order);
|
||||||
|
break;
|
||||||
|
case 'status_label':
|
||||||
|
$maintenances = $maintenances->OrderStatusName($order);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$maintenances = $maintenances->orderBy($sort, $order);
|
$maintenances = $maintenances->orderBy($sort, $order);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use App\Models\AssetModel;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to asset models for
|
* This class controls all actions related to asset models for
|
||||||
@@ -224,7 +225,7 @@ class AssetModelsController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('assetmodels/'.$assetmodel->image);
|
Storage::disk('public')->delete('assetmodels/'.$assetmodel->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::info($e);
|
Log::info($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ namespace App\Http\Controllers\Api;
|
|||||||
|
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
use App\Http\Requests\StoreAssetRequest;
|
use App\Http\Requests\StoreAssetRequest;
|
||||||
|
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||||
|
use App\Models\CheckoutAcceptance;
|
||||||
|
use App\Models\LicenseSeat;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
@@ -23,17 +27,16 @@ use App\Models\Setting;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use \Illuminate\Support\Facades\Auth;
|
use \Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Input;
|
|
||||||
use Paginator;
|
use Paginator;
|
||||||
use Slack;
|
use Slack;
|
||||||
use Str;
|
use Str;
|
||||||
use TCPDF;
|
use TCPDF;
|
||||||
use Validator;
|
use Validator;
|
||||||
use Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,6 +48,8 @@ use Route;
|
|||||||
*/
|
*/
|
||||||
class AssetsController extends Controller
|
class AssetsController extends Controller
|
||||||
{
|
{
|
||||||
|
use MigratesLegacyAssetLocations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns JSON listing of all assets
|
* Returns JSON listing of all assets
|
||||||
*
|
*
|
||||||
@@ -53,7 +58,7 @@ class AssetsController extends Controller
|
|||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function index(Request $request, $audit = null)
|
public function index(Request $request, $action = null, $upcoming_status = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
$filter_non_deprecable_assets = false;
|
$filter_non_deprecable_assets = false;
|
||||||
@@ -88,6 +93,7 @@ class AssetsController extends Controller
|
|||||||
'serial',
|
'serial',
|
||||||
'model_number',
|
'model_number',
|
||||||
'last_checkout',
|
'last_checkout',
|
||||||
|
'last_checkin',
|
||||||
'notes',
|
'notes',
|
||||||
'expected_checkin',
|
'expected_checkin',
|
||||||
'order_number',
|
'order_number',
|
||||||
@@ -105,6 +111,7 @@ class AssetsController extends Controller
|
|||||||
'requests_counter',
|
'requests_counter',
|
||||||
'byod',
|
'byod',
|
||||||
'asset_eol_date',
|
'asset_eol_date',
|
||||||
|
'requestable',
|
||||||
];
|
];
|
||||||
|
|
||||||
$filter = [];
|
$filter = [];
|
||||||
@@ -147,17 +154,44 @@ class AssetsController extends Controller
|
|||||||
$assets->TextSearch($request->input('search'));
|
$assets->TextSearch($request->input('search'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used by the audit reporting routes
|
|
||||||
if (Gate::allows('audit', Asset::class)) {
|
/**
|
||||||
switch ($audit) {
|
* Handle due and overdue audits and checkin dates
|
||||||
case 'due':
|
*/
|
||||||
$assets->DueOrOverdueForAudit($settings);
|
switch ($action) {
|
||||||
break;
|
case 'audits':
|
||||||
case 'overdue':
|
|
||||||
$assets->overdueForAudit($settings);
|
switch ($upcoming_status) {
|
||||||
break;
|
case 'due':
|
||||||
|
$assets->DueForAudit($settings);
|
||||||
|
break;
|
||||||
|
case 'overdue':
|
||||||
|
$assets->OverdueForAudit();
|
||||||
|
break;
|
||||||
|
case 'due-or-overdue':
|
||||||
|
$assets->DueOrOverdueForAudit($settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'checkins':
|
||||||
|
switch ($upcoming_status) {
|
||||||
|
case 'due':
|
||||||
|
$assets->DueForCheckin($settings);
|
||||||
|
break;
|
||||||
|
case 'overdue':
|
||||||
|
$assets->OverdueForCheckin();
|
||||||
|
break;
|
||||||
|
case 'due-or-overdue':
|
||||||
|
$assets->DueOrOverdueForCheckin($settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* End handling due and overdue audits and checkin dates
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// This is used by the sidenav, mostly
|
// This is used by the sidenav, mostly
|
||||||
@@ -551,44 +585,8 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset = $request->handleImages($asset);
|
$asset = $request->handleImages($asset);
|
||||||
|
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||||
|
|
||||||
// Update custom fields in the database.
|
|
||||||
$model = AssetModel::find($request->input('model_id'));
|
|
||||||
|
|
||||||
// Check that it's an object and not a collection
|
|
||||||
// (Sometimes people send arrays here and they shouldn't
|
|
||||||
if (($model) && ($model instanceof AssetModel) && ($model->fieldset)) {
|
|
||||||
foreach ($model->fieldset->fields as $field) {
|
|
||||||
|
|
||||||
// Set the field value based on what was sent in the request
|
|
||||||
$field_val = $request->input($field->db_column, null);
|
|
||||||
|
|
||||||
// If input value is null, use custom field's default value
|
|
||||||
if ($field_val == null) {
|
|
||||||
Log::debug('Field value for '.$field->db_column.' is null');
|
|
||||||
$field_val = $field->defaultValue($request->get('model_id'));
|
|
||||||
Log::debug('Use the default fieldset value of '.$field->defaultValue($request->get('model_id')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the field is set to encrypted, make sure we encrypt the value
|
|
||||||
if ($field->field_encrypted == '1') {
|
|
||||||
Log::debug('This model field is encrypted in this fieldset.');
|
|
||||||
|
|
||||||
if (Gate::allows('admin')) {
|
|
||||||
|
|
||||||
// If input value is null, use custom field's default value
|
|
||||||
if (($field_val == null) && ($request->has('model_id') != '')) {
|
|
||||||
$field_val = Crypt::encrypt($field->defaultValue($request->get('model_id')));
|
|
||||||
} else {
|
|
||||||
$field_val = Crypt::encrypt($request->input($field->db_column));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$asset->{$field->db_column} = $field_val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
if ($request->get('assigned_user')) {
|
if ($request->get('assigned_user')) {
|
||||||
@@ -607,6 +605,8 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
@@ -647,22 +647,7 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset = $request->handleImages($asset);
|
$asset = $request->handleImages($asset);
|
||||||
$model = AssetModel::find($asset->model_id);
|
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||||
|
|
||||||
// Update custom fields
|
|
||||||
if (($model) && (isset($model->fieldset))) {
|
|
||||||
foreach ($model->fieldset->fields as $field) {
|
|
||||||
if ($request->has($field->db_column)) {
|
|
||||||
if ($field->field_encrypted == '1') {
|
|
||||||
if (Gate::allows('admin')) {
|
|
||||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
@@ -685,7 +670,11 @@ class AssetsController extends Controller
|
|||||||
$asset->image = $asset->getImageUrl();
|
$asset->image = $asset->getImageUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
if ($problems_updating_encrypted_custom_fields) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||||
|
} else {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
@@ -795,7 +784,6 @@ class AssetsController extends Controller
|
|||||||
'asset_tag' => $asset->asset_tag,
|
'asset_tag' => $asset->asset_tag,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// This item is checked out to a location
|
// This item is checked out to a location
|
||||||
if (request('checkout_to_type') == 'location') {
|
if (request('checkout_to_type') == 'location') {
|
||||||
$target = Location::find(request('assigned_location'));
|
$target = Location::find(request('assigned_location'));
|
||||||
@@ -822,13 +810,10 @@ class AssetsController extends Controller
|
|||||||
$asset->status_id = $request->get('status_id');
|
$asset->status_id = $request->get('status_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (! isset($target)) {
|
if (! isset($target)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset '.e($asset->asset_tag).' is invalid - '.$error_payload['target_type'].' does not exist.'));
|
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset '.e($asset->asset_tag).' is invalid - '.$error_payload['target_type'].' does not exist.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
|
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
|
||||||
$expected_checkin = request('expected_checkin', null);
|
$expected_checkin = request('expected_checkin', null);
|
||||||
$note = request('note', null);
|
$note = request('note', null);
|
||||||
@@ -844,8 +829,6 @@ class AssetsController extends Controller
|
|||||||
// $asset->location_id = $target->rtd_location_id;
|
// $asset->location_id = $target->rtd_location_id;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($asset->checkOut($target, Auth::user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id)) {
|
if ($asset->checkOut($target, Auth::user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
|
||||||
}
|
}
|
||||||
@@ -864,11 +847,9 @@ class AssetsController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $asset_id)
|
public function checkin(Request $request, $asset_id)
|
||||||
{
|
{
|
||||||
$this->authorize('checkin', Asset::class);
|
|
||||||
$asset = Asset::with('model')->findOrFail($asset_id);
|
$asset = Asset::with('model')->findOrFail($asset_id);
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
|
|
||||||
$target = $asset->assignedTo;
|
$target = $asset->assignedTo;
|
||||||
if (is_null($target)) {
|
if (is_null($target)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', [
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
@@ -879,9 +860,8 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset->expected_checkin = null;
|
$asset->expected_checkin = null;
|
||||||
$asset->last_checkout = null;
|
//$asset->last_checkout = null;
|
||||||
$asset->last_checkin = now();
|
$asset->last_checkin = now();
|
||||||
$asset->assigned_to = null;
|
|
||||||
$asset->assignedTo()->disassociate($asset);
|
$asset->assignedTo()->disassociate($asset);
|
||||||
$asset->accepted = null;
|
$asset->accepted = null;
|
||||||
|
|
||||||
@@ -889,10 +869,16 @@ class AssetsController extends Controller
|
|||||||
$asset->name = $request->input('name');
|
$asset->name = $request->input('name');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->migrateLegacyLocations($asset);
|
||||||
|
|
||||||
$asset->location_id = $asset->rtd_location_id;
|
$asset->location_id = $asset->rtd_location_id;
|
||||||
|
|
||||||
if ($request->filled('location_id')) {
|
if ($request->filled('location_id')) {
|
||||||
$asset->location_id = $request->input('location_id');
|
$asset->location_id = $request->input('location_id');
|
||||||
|
|
||||||
|
if ($request->input('update_default_location')){
|
||||||
|
$asset->rtd_location_id = $request->input('location_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->has('status_id')) {
|
if ($request->has('status_id')) {
|
||||||
@@ -906,6 +892,23 @@ class AssetsController extends Controller
|
|||||||
$originalValues['action_date'] = $checkin_at;
|
$originalValues['action_date'] = $checkin_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
||||||
|
$seat->update(['assigned_to' => null]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get all pending Acceptances for this asset and delete them
|
||||||
|
CheckoutAcceptance::pending()
|
||||||
|
->whereHasMorph(
|
||||||
|
'checkoutable',
|
||||||
|
[Asset::class],
|
||||||
|
function (Builder $query) use ($asset) {
|
||||||
|
$query->where('id', $asset->id);
|
||||||
|
})
|
||||||
|
->get()
|
||||||
|
->map(function ($acceptance) {
|
||||||
|
$acceptance->delete();
|
||||||
|
});
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
|
|
||||||
@@ -956,25 +959,39 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('audit', Asset::class);
|
||||||
$rules = [
|
|
||||||
'asset_tag' => 'required',
|
|
||||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
|
||||||
'next_audit_date' => 'date|nullable',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||||
|
|
||||||
|
// No tag passed - return an error
|
||||||
|
if (!$request->filled('asset_tag')) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> '',
|
||||||
|
'error'=> trans('admin/hardware/message.no_tag'),
|
||||||
|
], trans('admin/hardware/message.no_tag')), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
|
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
|
||||||
|
|
||||||
|
|
||||||
if ($asset) {
|
if ($asset) {
|
||||||
// We don't want to log this as a normal update, so let's bypass that
|
|
||||||
|
/**
|
||||||
|
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
|
||||||
|
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
|
||||||
|
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
|
||||||
|
* the audit log entry we're creating through this controller.
|
||||||
|
*
|
||||||
|
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
|
||||||
|
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
|
||||||
|
* will bypass normal model-level validation that's usually handled at the observer )
|
||||||
|
*
|
||||||
|
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
|
||||||
|
* which manually invokes Watson Validating to make sure the asset's model is valid.
|
||||||
|
*
|
||||||
|
* @see \App\Observers\AssetObserver::updating()
|
||||||
|
*/
|
||||||
$asset->unsetEventDispatcher();
|
$asset->unsetEventDispatcher();
|
||||||
$asset->next_audit_date = $dt;
|
$asset->next_audit_date = $dt;
|
||||||
|
|
||||||
@@ -990,8 +1007,12 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
$asset->last_audit_date = date('Y-m-d H:i:s');
|
$asset->last_audit_date = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
if ($asset->save()) {
|
/**
|
||||||
$log = $asset->logAudit(request('note'), request('location_id'));
|
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
|
||||||
|
* We have to invoke this manually because of the unsetEventDispatcher() above.)
|
||||||
|
*/
|
||||||
|
if ($asset->isValid() && $asset->save()) {
|
||||||
|
$asset->logAudit(request('note'), request('location_id'));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', [
|
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||||
'asset_tag'=> e($asset->asset_tag),
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
@@ -999,9 +1020,23 @@ class AssetsController extends Controller
|
|||||||
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
|
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
|
||||||
], trans('admin/hardware/message.audit.success')));
|
], trans('admin/hardware/message.audit.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asset failed validation or was not able to be saved
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
'error'=> $asset->getErrors()->first(),
|
||||||
|
], trans('admin/hardware/message.audit.error', ['error' => $asset->getErrors()->first()])), 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.e($request->input('asset_tag')).' not found'));
|
|
||||||
|
// No matching asset for the asset tag that was passed.
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> e($request->input('asset_tag')),
|
||||||
|
'error'=> trans('admin/hardware/message.audit.error'),
|
||||||
|
], trans('admin/hardware/message.audit.error', ['error' => trans('admin/hardware/message.does_not_exist')])), 200);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1035,8 +1070,7 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
$assets = Asset::select('assets.*')
|
$assets = Asset::select('assets.*')
|
||||||
->with('location', 'assetstatus', 'assetlog', 'company','assignedTo',
|
->with('location', 'assetstatus', 'assetlog', 'company','assignedTo',
|
||||||
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier', 'requests')
|
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier', 'requests');
|
||||||
->requestableAssets();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1044,7 +1078,7 @@ class AssetsController extends Controller
|
|||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$assets->TextSearch($request->input('search'));
|
$assets->TextSearch($request->input('search'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search custom fields by column name
|
// Search custom fields by column name
|
||||||
foreach ($all_custom_fields as $field) {
|
foreach ($all_custom_fields as $field) {
|
||||||
if ($request->filled($field->db_column_name())) {
|
if ($request->filled($field->db_column_name())) {
|
||||||
@@ -1074,6 +1108,7 @@ class AssetsController extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$assets->requestableAssets();
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : app('api_offset_value');
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ class CompaniesController extends Controller
|
|||||||
'components_count',
|
'components_count',
|
||||||
];
|
];
|
||||||
|
|
||||||
$companies = Company::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
$companies = Company::withCount(['assets as assets_count' => function ($query) {
|
||||||
|
$query->AssetsForShow();
|
||||||
|
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$companies->TextSearch($request->input('search'));
|
$companies->TextSearch($request->input('search'));
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use App\Events\ComponentCheckedIn;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Database\Query\Builder;
|
use Illuminate\Database\Query\Builder;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ComponentsController extends Controller
|
class ComponentsController extends Controller
|
||||||
{
|
{
|
||||||
@@ -331,7 +332,7 @@ class ComponentsController extends Controller
|
|||||||
// actually checked out.
|
// actually checked out.
|
||||||
$component_assets->assigned_qty = $qty_remaining_in_checkout;
|
$component_assets->assigned_qty = $qty_remaining_in_checkout;
|
||||||
|
|
||||||
\Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
|
Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
|
||||||
|
|
||||||
\DB::table('components_assets')->where('id',
|
\DB::table('components_assets')->where('id',
|
||||||
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
|
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\ConsumablesTransformer;
|
use App\Http\Transformers\ConsumablesTransformer;
|
||||||
@@ -11,6 +12,8 @@ use App\Models\Consumable;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ConsumablesController extends Controller
|
class ConsumablesController extends Controller
|
||||||
{
|
{
|
||||||
@@ -275,7 +278,7 @@ class ConsumablesController extends Controller
|
|||||||
if (!$user = User::find($request->input('assigned_to'))) {
|
if (!$user = User::find($request->input('assigned_to'))) {
|
||||||
// Return error message
|
// Return error message
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
||||||
\Log::debug('No valid user');
|
Log::debug('No valid user');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the consumable data
|
// Update the consumable data
|
||||||
@@ -290,17 +293,9 @@ class ConsumablesController extends Controller
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Log checkout event
|
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
||||||
$logaction = $consumable->logCheckout($request->input('note'), $user);
|
|
||||||
$data['log_id'] = $logaction->id;
|
|
||||||
$data['eula'] = $consumable->getEula();
|
|
||||||
$data['first_name'] = $user->first_name;
|
|
||||||
$data['item_name'] = $consumable->name;
|
|
||||||
$data['checkout_date'] = $logaction->created_at;
|
|
||||||
$data['note'] = $logaction->note;
|
|
||||||
$data['require_acceptance'] = $consumable->requireAcceptance();
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class CustomFieldsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($field_id)
|
public function destroy($field_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class CustomFieldsetsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use App\Http\Transformers\DepartmentsTransformer;
|
|||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Department;
|
use App\Models\Department;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Http\Transformers\GroupsTransformer;
|
use App\Http\Transformers\GroupsTransformer;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
|
||||||
class GroupsController extends Controller
|
class GroupsController extends Controller
|
||||||
@@ -25,7 +26,7 @@ class GroupsController extends Controller
|
|||||||
$this->authorize('view', Group::class);
|
$this->authorize('view', Group::class);
|
||||||
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
|
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
|
||||||
|
|
||||||
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at')->withCount('users as users_count');
|
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('admin')->withCount('users as users_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$groups = $groups->TextSearch($request->input('search'));
|
$groups = $groups->TextSearch($request->input('search'));
|
||||||
@@ -61,12 +62,16 @@ class GroupsController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = new Group;
|
$group = new Group;
|
||||||
|
// Get all the available permissions
|
||||||
|
$permissions = config('permissions');
|
||||||
|
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
|
||||||
|
|
||||||
$group->name = $request->input('name');
|
$group->name = $request->input('name');
|
||||||
$group->permissions = json_encode($request->input('permissions')); // Todo - some JSON validation stuff here
|
$group->created_by = Auth::user()->id;
|
||||||
|
$group->permissions = json_encode($request->input('permissions', $groupPermissions));
|
||||||
|
|
||||||
if ($group->save()) {
|
if ($group->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.create.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new GroupsTransformer)->transformGroup($group), trans('admin/groups/message.success.create')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
||||||
@@ -84,7 +89,6 @@ class GroupsController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = Group::findOrFail($id);
|
$group = Group::findOrFail($id);
|
||||||
|
|
||||||
return (new GroupsTransformer)->transformGroup($group);
|
return (new GroupsTransformer)->transformGroup($group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +110,7 @@ class GroupsController extends Controller
|
|||||||
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
||||||
|
|
||||||
if ($group->save()) {
|
if ($group->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new GroupsTransformer)->transformGroup($group), trans('admin/groups/message.success.update')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ use App\Http\Transformers\ImportsTransformer;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Import;
|
use App\Models\Import;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Database\Eloquent\JsonEncodingException;
|
use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||||
use Illuminate\Support\Facades\Request;
|
use Illuminate\Support\Facades\Request;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use League\Csv\Reader;
|
use League\Csv\Reader;
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ImportController extends Controller
|
class ImportController extends Controller
|
||||||
{
|
{
|
||||||
@@ -159,10 +160,10 @@ class ImportController extends Controller
|
|||||||
|
|
||||||
// Run a backup immediately before processing
|
// Run a backup immediately before processing
|
||||||
if ($request->get('run-backup')) {
|
if ($request->get('run-backup')) {
|
||||||
\Log::debug('Backup manually requested via importer');
|
Log::debug('Backup manually requested via importer');
|
||||||
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]);
|
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]);
|
||||||
} else {
|
} else {
|
||||||
\Log::debug('NO BACKUP requested via importer');
|
Log::debug('NO BACKUP requested via importer');
|
||||||
}
|
}
|
||||||
|
|
||||||
$import = Import::find($import_id);
|
$import = Import::find($import_id);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use App\Http\Transformers\LabelsTransformer;
|
|||||||
use App\Models\Labels\Label;
|
use App\Models\Labels\Label;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\ItemNotFoundException;
|
use Illuminate\Support\ItemNotFoundException;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class LabelsController extends Controller
|
class LabelsController extends Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use App\Models\Asset;
|
|||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class LicenseSeatsController extends Controller
|
class LicenseSeatsController extends Controller
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ class LicensesController extends Controller
|
|||||||
'seats',
|
'seats',
|
||||||
'termination_date',
|
'termination_date',
|
||||||
'depreciation_id',
|
'depreciation_id',
|
||||||
|
'min_amt',
|
||||||
];
|
];
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||||
$licenses = $licenses->orderBy($sort, $order);
|
$licenses = $licenses->orderBy($sort, $order);
|
||||||
|
|||||||
@@ -25,9 +25,27 @@ class LocationsController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('view', Location::class);
|
$this->authorize('view', Location::class);
|
||||||
$allowed_columns = [
|
$allowed_columns = [
|
||||||
'id', 'name', 'address', 'address2', 'city', 'state', 'country', 'zip', 'created_at',
|
'id',
|
||||||
'updated_at', 'manager_id', 'image',
|
'name',
|
||||||
'assigned_assets_count', 'users_count', 'assets_count','assigned_assets_count', 'assets_count', 'rtd_assets_count', 'currency', 'ldap_ou', ];
|
'address',
|
||||||
|
'address2',
|
||||||
|
'city',
|
||||||
|
'state',
|
||||||
|
'country',
|
||||||
|
'zip',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'manager_id',
|
||||||
|
'image',
|
||||||
|
'assigned_assets_count',
|
||||||
|
'users_count',
|
||||||
|
'assets_count',
|
||||||
|
'assigned_assets_count',
|
||||||
|
'assets_count',
|
||||||
|
'rtd_assets_count',
|
||||||
|
'currency',
|
||||||
|
'ldap_ou',
|
||||||
|
];
|
||||||
|
|
||||||
$locations = Location::with('parent', 'manager', 'children')->select([
|
$locations = Location::with('parent', 'manager', 'children')->select([
|
||||||
'locations.id',
|
'locations.id',
|
||||||
@@ -50,6 +68,7 @@ class LocationsController extends Controller
|
|||||||
])->withCount('assignedAssets as assigned_assets_count')
|
])->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count');
|
->withCount('users as users_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
@@ -80,6 +99,10 @@ class LocationsController extends Controller
|
|||||||
$locations->where('locations.country', '=', $request->input('country'));
|
$locations->where('locations.country', '=', $request->input('country'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manager_id')) {
|
||||||
|
$locations->where('locations.manager_id', '=', $request->input('manager_id'));
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// 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');
|
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
@@ -212,10 +235,16 @@ class LocationsController extends Controller
|
|||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Location::class);
|
$this->authorize('delete', Location::class);
|
||||||
$location = Location::findOrFail($id);
|
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||||
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
|
->withCount('users as users_count')
|
||||||
|
->findOrFail($id);
|
||||||
|
|
||||||
if (! $location->isDeletable()) {
|
if (! $location->isDeletable()) {
|
||||||
return response()
|
return response()
|
||||||
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
|
->json(Helper::formatStandardApiResponse('error', null, trans('admin/locations/message.assoc_users')));
|
||||||
}
|
}
|
||||||
$this->authorize('delete', $location);
|
$this->authorize('delete', $location);
|
||||||
$location->delete();
|
$location->delete();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use Laravel\Passport\TokenRepository;
|
|||||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class ProfileController extends Controller
|
class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,14 +32,26 @@ class ReportsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
|
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
|
||||||
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
|
$actionlogs = $actionlogs->where(function($query) use ($request)
|
||||||
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
|
{
|
||||||
|
$query->where('item_id', '=', $request->input('item_id'))
|
||||||
|
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')))
|
||||||
|
->orWhere(function($query) use ($request)
|
||||||
|
{
|
||||||
|
$query->where('target_id', '=', $request->input('item_id'))
|
||||||
|
->where('target_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('action_type')) {
|
if ($request->filled('action_type')) {
|
||||||
$actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc');
|
$actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('user_id')) {
|
||||||
|
$actionlogs = $actionlogs->where('user_id', '=', $request->input('user_id'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('action_source')) {
|
if ($request->filled('action_source')) {
|
||||||
$actionlogs = $actionlogs->where('action_source', '=', $request->input('action_source'))->orderBy('created_at', 'desc');
|
$actionlogs = $actionlogs->where('action_source', '=', $request->input('action_source'))->orderBy('created_at', 'desc');
|
||||||
}
|
}
|
||||||
@@ -66,13 +78,14 @@ class ReportsController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$total = $actionlogs->count();
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $actionlogs->count()) ? $actionlogs->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $total) ? $total : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||||
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
|
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
|
||||||
$total = $actionlogs->count();
|
|
||||||
|
|
||||||
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
|
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
|
||||||
|
|
||||||
|
|||||||
@@ -33,18 +33,18 @@ class SettingsController extends Controller
|
|||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
|
||||||
if ($settings->ldap_enabled!='1') {
|
if ($settings->ldap_enabled!='1') {
|
||||||
\Log::debug('LDAP is not enabled cannot test.');
|
Log::debug('LDAP is not enabled cannot test.');
|
||||||
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug('Preparing to test LDAP connection');
|
Log::debug('Preparing to test LDAP connection');
|
||||||
|
|
||||||
$message = []; //where we collect together test messages
|
$message = []; //where we collect together test messages
|
||||||
try {
|
try {
|
||||||
$connection = Ldap::connectToLdap();
|
$connection = Ldap::connectToLdap();
|
||||||
try {
|
try {
|
||||||
$message['bind'] = ['message' => 'Successfully bound to LDAP server.'];
|
$message['bind'] = ['message' => 'Successfully bound to LDAP server.'];
|
||||||
\Log::debug('attempting to bind to LDAP for LDAP test');
|
Log::debug('attempting to bind to LDAP for LDAP test');
|
||||||
Ldap::bindAdminToLdap($connection);
|
Ldap::bindAdminToLdap($connection);
|
||||||
$message['login'] = [
|
$message['login'] = [
|
||||||
'message' => 'Successfully connected to LDAP server.',
|
'message' => 'Successfully connected to LDAP server.',
|
||||||
@@ -75,13 +75,13 @@ class SettingsController extends Controller
|
|||||||
|
|
||||||
return response()->json($message, 200);
|
return response()->json($message, 200);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Bind failed');
|
Log::debug('Bind failed');
|
||||||
\Log::debug("Exception was: ".$e->getMessage());
|
Log::debug("Exception was: ".$e->getMessage());
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
//return response()->json(['message' => $e->getMessage()], 500);
|
//return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Connection failed but we cannot debug it any further on our end.');
|
Log::debug('Connection failed but we cannot debug it any further on our end.');
|
||||||
return response()->json(['message' => $e->getMessage()], 500);
|
return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ class SettingsController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (Setting::getSettings()->ldap_enabled != '1') {
|
if (Setting::getSettings()->ldap_enabled != '1') {
|
||||||
\Log::debug('LDAP is not enabled. Cannot test.');
|
Log::debug('LDAP is not enabled. Cannot test.');
|
||||||
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,39 +104,39 @@ class SettingsController extends Controller
|
|||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules);
|
$validator = Validator::make($request->all(), $rules);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
\Log::debug('LDAP Validation test failed.');
|
Log::debug('LDAP Validation test failed.');
|
||||||
$validation_errors = implode(' ',$validator->errors()->all());
|
$validation_errors = implode(' ',$validator->errors()->all());
|
||||||
return response()->json(['message' => $validator->errors()->all()], 400);
|
return response()->json(['message' => $validator->errors()->all()], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\Log::debug('Preparing to test LDAP login');
|
Log::debug('Preparing to test LDAP login');
|
||||||
try {
|
try {
|
||||||
$connection = Ldap::connectToLdap();
|
$connection = Ldap::connectToLdap();
|
||||||
try {
|
try {
|
||||||
Ldap::bindAdminToLdap($connection);
|
Ldap::bindAdminToLdap($connection);
|
||||||
\Log::debug('Attempting to bind to LDAP for LDAP test');
|
Log::debug('Attempting to bind to LDAP for LDAP test');
|
||||||
try {
|
try {
|
||||||
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
|
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
|
||||||
if ($ldap_user) {
|
if ($ldap_user) {
|
||||||
\Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
|
Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
|
||||||
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
|
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
|
||||||
}
|
}
|
||||||
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
|
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('LDAP login failed');
|
Log::debug('LDAP login failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Bind failed');
|
Log::debug('Bind failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
//return response()->json(['message' => $e->getMessage()], 500);
|
//return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Connection failed');
|
Log::debug('Connection failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 500);
|
return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ class SettingsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function ajaxTestEmail()
|
public function ajaxTestEmail()
|
||||||
{
|
{
|
||||||
@@ -170,7 +170,7 @@ class SettingsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @return Response
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function purgeBarcodes()
|
public function purgeBarcodes()
|
||||||
{
|
{
|
||||||
@@ -181,19 +181,19 @@ class SettingsController extends Controller
|
|||||||
|
|
||||||
$file_parts = explode('.', $file);
|
$file_parts = explode('.', $file);
|
||||||
$extension = end($file_parts);
|
$extension = end($file_parts);
|
||||||
\Log::debug($extension);
|
Log::debug($extension);
|
||||||
|
|
||||||
// Only generated barcodes would have a .png file extension
|
// Only generated barcodes would have a .png file extension
|
||||||
if ($extension == 'png') {
|
if ($extension == 'png') {
|
||||||
\Log::debug('Deleting: '.$file);
|
Log::debug('Deleting: '.$file);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete($file);
|
Storage::disk('public')->delete($file);
|
||||||
\Log::debug('Deleting: '.$file);
|
Log::debug('Deleting: '.$file);
|
||||||
$file_count++;
|
$file_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ class SettingsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return array
|
* @return array | JsonResponse
|
||||||
*/
|
*/
|
||||||
public function showLoginAttempts(Request $request)
|
public function showLoginAttempts(Request $request)
|
||||||
{
|
{
|
||||||
@@ -229,6 +229,12 @@ class SettingsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists backup files
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @return array | JsonResponse
|
||||||
|
*/
|
||||||
public function listBackups() {
|
public function listBackups() {
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$path = 'app/backups';
|
$path = 'app/backups';
|
||||||
@@ -249,12 +255,12 @@ class SettingsController extends Controller
|
|||||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||||
'modified_value' => $file_timestamp,
|
'modified_value' => $file_timestamp,
|
||||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||||
|
'backup_url' => config('app.url').'/settings/backups/download/'.basename($backup_files[$f]),
|
||||||
|
|
||||||
];
|
];
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,15 +270,56 @@ class SettingsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a backup file.
|
||||||
|
* We use response()->download() here instead of Storage::download() because Storage::download()
|
||||||
|
* exhausts memory on larger files.
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||||
|
*/
|
||||||
public function downloadBackup($file) {
|
public function downloadBackup($file) {
|
||||||
|
|
||||||
$path = 'app/backups';
|
$path = storage_path('app/backups');
|
||||||
if (Storage::exists($path.'/'.$file)) {
|
|
||||||
|
if (Storage::exists('app/backups/'.$file)) {
|
||||||
$headers = ['ContentType' => 'application/zip'];
|
$headers = ['ContentType' => 'application/zip'];
|
||||||
return Storage::download($path.'/'.$file, $file, $headers);
|
return response()->download($path.'/'.$file, $file, $headers);
|
||||||
} else {
|
} else {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines and downloads the latest backup
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @since [v6.3.1]
|
||||||
|
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||||
|
*/
|
||||||
|
public function downloadLatestBackup() {
|
||||||
|
|
||||||
|
$fileData = collect();
|
||||||
|
foreach (Storage::files('app/backups') as $file) {
|
||||||
|
if (pathinfo($file, PATHINFO_EXTENSION) == 'zip') {
|
||||||
|
$fileData->push([
|
||||||
|
'file' => $file,
|
||||||
|
'date' => Storage::lastModified($file)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$newest = $fileData->sortByDesc('date')->first();
|
||||||
|
if (Storage::exists($newest['file'])) {
|
||||||
|
$headers = ['ContentType' => 'application/zip'];
|
||||||
|
return response()->download(storage_path($newest['file']), basename($newest['file']), $headers);
|
||||||
|
} else {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,15 +13,17 @@ use App\Http\Transformers\SelectlistTransformer;
|
|||||||
use App\Http\Transformers\UsersTransformer;
|
use App\Http\Transformers\UsersTransformer;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Consumable;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\CurrentInventory;
|
use App\Notifications\CurrentInventory;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Http\Requests\DeleteUserRequest;
|
||||||
|
|
||||||
class UsersController extends Controller
|
class UsersController extends Controller
|
||||||
{
|
{
|
||||||
@@ -31,7 +33,7 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
@@ -73,11 +75,16 @@ class UsersController extends Controller
|
|||||||
'users.end_date',
|
'users.end_date',
|
||||||
'users.vip',
|
'users.vip',
|
||||||
'users.autoassign_licenses',
|
'users.autoassign_licenses',
|
||||||
|
'users.website',
|
||||||
|
|
||||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
|
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations')
|
||||||
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
|
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count');
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->filled('search') != '') {
|
||||||
|
$users = $users->TextSearch($request->input('search'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('activated')) {
|
if ($request->filled('activated')) {
|
||||||
$users = $users->where('users.activated', '=', $request->input('activated'));
|
$users = $users->where('users.activated', '=', $request->input('activated'));
|
||||||
}
|
}
|
||||||
@@ -122,6 +129,10 @@ class UsersController extends Controller
|
|||||||
$users = $users->where('users.country', '=', $request->input('country'));
|
$users = $users->where('users.country', '=', $request->input('country'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('website')) {
|
||||||
|
$users = $users->where('users.website', '=', $request->input('website'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('zip')) {
|
if ($request->filled('zip')) {
|
||||||
$users = $users->where('users.zip', '=', $request->input('zip'));
|
$users = $users->where('users.zip', '=', $request->input('zip'));
|
||||||
}
|
}
|
||||||
@@ -182,12 +193,23 @@ class UsersController extends Controller
|
|||||||
$users->has('accessories', '=', $request->input('accessories_count'));
|
$users->has('accessories', '=', $request->input('accessories_count'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manages_users_count')) {
|
||||||
|
$users->has('manages_users_count', '=', $request->input('manages_users_count'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manages_locations_count')) {
|
||||||
|
$users->has('manages_locations_count', '=', $request->input('manages_locations_count'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('autoassign_licenses')) {
|
if ($request->filled('autoassign_licenses')) {
|
||||||
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
|
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
|
||||||
$users = $users->TextSearch($request->input('search'));
|
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
|
||||||
|
$users = $users->onlyTrashed();
|
||||||
|
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
|
||||||
|
$users = $users->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
@@ -225,10 +247,6 @@ class UsersController extends Controller
|
|||||||
'jobtitle',
|
'jobtitle',
|
||||||
'username',
|
'username',
|
||||||
'employee_num',
|
'employee_num',
|
||||||
'assets',
|
|
||||||
'accessories',
|
|
||||||
'consumables',
|
|
||||||
'licenses',
|
|
||||||
'groups',
|
'groups',
|
||||||
'activated',
|
'activated',
|
||||||
'created_at',
|
'created_at',
|
||||||
@@ -239,6 +257,8 @@ class UsersController extends Controller
|
|||||||
'licenses_count',
|
'licenses_count',
|
||||||
'consumables_count',
|
'consumables_count',
|
||||||
'accessories_count',
|
'accessories_count',
|
||||||
|
'manages_users_count',
|
||||||
|
'manages_locations_count',
|
||||||
'phone',
|
'phone',
|
||||||
'address',
|
'address',
|
||||||
'city',
|
'city',
|
||||||
@@ -254,31 +274,20 @@ class UsersController extends Controller
|
|||||||
'start_date',
|
'start_date',
|
||||||
'end_date',
|
'end_date',
|
||||||
'autoassign_licenses',
|
'autoassign_licenses',
|
||||||
|
'website',
|
||||||
];
|
];
|
||||||
|
|
||||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name';
|
||||||
$users = $users->orderBy($sort, $order);
|
$users = $users->orderBy($sort, $order);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
|
|
||||||
$users = $users->onlyTrashed();
|
|
||||||
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
|
|
||||||
$users = $users->withTrashed();
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = Company::scopeCompanyables($users);
|
|
||||||
|
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
\Log::debug('Requested offset: '. $request->input('offset'));
|
|
||||||
\Log::debug('App offset: '. app('api_offset_value'));
|
|
||||||
\Log::debug('Actual offset: '. $offset);
|
|
||||||
\Log::debug('Limit: '. $limit);
|
|
||||||
|
|
||||||
$total = $users->count();
|
$total = $users->count();
|
||||||
$users = $users->skip($offset)->take($limit)->get();
|
$users = $users->skip($offset)->take($limit)->get();
|
||||||
|
|
||||||
@@ -307,8 +316,6 @@ class UsersController extends Controller
|
|||||||
]
|
]
|
||||||
)->where('show_in_list', '=', '1');
|
)->where('show_in_list', '=', '1');
|
||||||
|
|
||||||
$users = Company::scopeCompanyables($users);
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$users = $users->where(function ($query) use ($request) {
|
$users = $users->where(function ($query) use ($request) {
|
||||||
$query->SimpleNameSearch($request->get('search'))
|
$query->SimpleNameSearch($request->get('search'))
|
||||||
@@ -350,7 +357,7 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return array | \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function store(SaveUserRequest $request)
|
public function store(SaveUserRequest $request)
|
||||||
{
|
{
|
||||||
@@ -397,14 +404,19 @@ class UsersController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return array | \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count')->findOrFail($id);
|
|
||||||
|
|
||||||
return (new UsersTransformer)->transformUser($user);
|
if ($user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count')->find($id)) {
|
||||||
|
$this->authorize('view', $user);
|
||||||
|
return (new UsersTransformer)->transformUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -415,89 +427,89 @@ class UsersController extends Controller
|
|||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function update(SaveUserRequest $request, $id)
|
public function update(SaveUserRequest $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('update', User::class);
|
$this->authorize('update', User::class);
|
||||||
|
|
||||||
$user = User::findOrFail($id);
|
if ($user = User::find($id)) {
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
|
||||||
*
|
|
||||||
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
|
||||||
*
|
|
||||||
* Thanks, jerks. You are why we can't have nice things. - snipe
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
|
$this->authorize('update', $user);
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
|
||||||
}
|
/**
|
||||||
|
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
||||||
|
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
||||||
|
* Thanks, jerks. You are why we can't have nice things. - snipe
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
$user->fill($request->all());
|
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
||||||
if ($user->id == $request->input('manager_id')) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->filled('password')) {
|
|
||||||
$user->password = bcrypt($request->input('password'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to use has() instead of filled()
|
|
||||||
// here because we need to overwrite permissions
|
|
||||||
// if someone needs to null them out
|
|
||||||
if ($request->has('permissions')) {
|
|
||||||
$permissions_array = $request->input('permissions');
|
|
||||||
|
|
||||||
// Strip out the superuser permission if the API user isn't a superadmin
|
|
||||||
if (! Auth::user()->isSuperUser()) {
|
|
||||||
unset($permissions_array['superuser']);
|
|
||||||
}
|
}
|
||||||
$user->permissions = $permissions_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
$user->fill($request->all());
|
||||||
|
|
||||||
// Update the location of any assets checked out to this user
|
if ($user->id == $request->input('manager_id')) {
|
||||||
Asset::where('assigned_type', User::class)
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
||||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
}
|
||||||
|
|
||||||
|
if ($request->filled('password')) {
|
||||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
$user->password = bcrypt($request->input('password'));
|
||||||
|
}
|
||||||
if ($user->save()) {
|
|
||||||
|
|
||||||
// Sync group memberships:
|
// We need to use has() instead of filled()
|
||||||
// This was changed in Snipe-IT v4.6.x to 4.7, since we upgraded to Laravel 5.5
|
// here because we need to overwrite permissions
|
||||||
// which changes the behavior of has vs filled.
|
// if someone needs to null them out
|
||||||
// The $request->has method will now return true even if the input value is an empty string or null.
|
if ($request->has('permissions')) {
|
||||||
// A new $request->filled method has was added that provides the previous behavior of the has method.
|
$permissions_array = $request->input('permissions');
|
||||||
|
|
||||||
// Check if the request has groups passed and has a value
|
// Strip out the individual superuser permission if the API user isn't a superadmin
|
||||||
if ($request->filled('groups')) {
|
if (!Auth::user()->isSuperUser()) {
|
||||||
$validator = Validator::make($request->all(), [
|
unset($permissions_array['superuser']);
|
||||||
'groups.*' => 'integer|exists:permission_groups,id',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails()){
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
|
||||||
}
|
}
|
||||||
$user->groups()->sync($request->input('groups'));
|
|
||||||
// The groups field has been passed but it is null, so we should blank it out
|
$user->permissions = $permissions_array;
|
||||||
} elseif ($request->has('groups')) {
|
|
||||||
$user->groups()->sync([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
// Update the location of any assets checked out to this user
|
||||||
|
Asset::where('assigned_type', User::class)
|
||||||
|
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||||
|
|
||||||
|
|
||||||
|
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||||
|
|
||||||
|
if ($user->save()) {
|
||||||
|
|
||||||
|
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||||
|
if (($request->has('groups')) && (Auth::user()->isSuperUser())) {
|
||||||
|
|
||||||
|
$validator = Validator::make($request->only('groups'), [
|
||||||
|
'groups.*' => 'integer|exists:permission_groups,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync the groups since the user is a superuser and the groups pass validation
|
||||||
|
$user->groups()->sync($request->input('groups'));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -506,45 +518,36 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy(DeleteUserRequest $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('delete', User::class);
|
$this->authorize('delete', User::class);
|
||||||
$user = User::findOrFail($id);
|
|
||||||
$this->authorize('delete', $user);
|
|
||||||
|
|
||||||
if (($user->assets) && ($user->assets->count() > 0)) {
|
if ($user = User::withTrashed()->find($id)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->licenses) && ($user->licenses->count() > 0)) {
|
$this->authorize('delete', $user);
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->licenses->count().' license(s) associated with them and cannot be deleted.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->accessories) && ($user->accessories->count() > 0)) {
|
if ($user->delete()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->accessories->count().' accessories associated with them.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) {
|
// Remove the user's avatar if they have one
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->managedLocations()->count().' locations that they manage.'));
|
if (Storage::disk('public')->exists('avatars/' . $user->avatar)) {
|
||||||
}
|
try {
|
||||||
|
Storage::disk('public')->delete('avatars/' . $user->avatar);
|
||||||
if ($user->delete()) {
|
} catch (\Exception $e) {
|
||||||
|
Log::debug($e);
|
||||||
// Remove the user's avatar if they have one
|
}
|
||||||
if (Storage::disk('public')->exists('avatars/'.$user->avatar)) {
|
|
||||||
try {
|
|
||||||
Storage::disk('public')->delete('avatars/'.$user->avatar);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -553,15 +556,42 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
* @return array | \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function assets(Request $request, $id)
|
public function assets(Request $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model')->get();
|
|
||||||
|
|
||||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
if ($user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id)) {
|
||||||
|
$this->authorize('view', $user);
|
||||||
|
|
||||||
|
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model');
|
||||||
|
|
||||||
|
|
||||||
|
// Filter on category ID
|
||||||
|
if ($request->filled('category_id')) {
|
||||||
|
$assets = $assets->InCategory($request->input('category_id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Filter on model ID
|
||||||
|
if ($request->filled('model_id')) {
|
||||||
|
|
||||||
|
$model_ids = $request->input('model_id');
|
||||||
|
if (!is_array($model_ids)) {
|
||||||
|
$model_ids = array($model_ids);
|
||||||
|
}
|
||||||
|
$assets = $assets->InModelList($model_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$assets = $assets->get();
|
||||||
|
|
||||||
|
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -575,15 +605,22 @@ class UsersController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function emailAssetList(Request $request, $id)
|
public function emailAssetList(Request $request, $id)
|
||||||
{
|
{
|
||||||
$user = User::findOrFail($id);
|
$this->authorize('update', User::class);
|
||||||
|
|
||||||
if (empty($user->email)) {
|
if ($user = User::find($id)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
|
$this->authorize('update', $user);
|
||||||
|
|
||||||
|
if (empty($user->email)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->notify((new CurrentInventory($user)));
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->notify((new CurrentInventory($user)));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -592,13 +629,14 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
* @return array | \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function consumables(Request $request, $id)
|
public function consumables(Request $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$this->authorize('view', Consumable::class);
|
$this->authorize('view', Consumable::class);
|
||||||
$user = User::findOrFail($id);
|
$user = User::findOrFail($id);
|
||||||
|
$this->authorize('view', $user);
|
||||||
$consumables = $user->consumables;
|
$consumables = $user->consumables;
|
||||||
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
|
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
|
||||||
}
|
}
|
||||||
@@ -609,12 +647,13 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.6.14]
|
* @since [v4.6.14]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function accessories($id)
|
public function accessories($id)
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$user = User::findOrFail($id);
|
$user = User::findOrFail($id);
|
||||||
|
$this->authorize('view', $user);
|
||||||
$this->authorize('view', Accessory::class);
|
$this->authorize('view', Accessory::class);
|
||||||
$accessories = $user->accessories;
|
$accessories = $user->accessories;
|
||||||
|
|
||||||
@@ -627,7 +666,7 @@ class UsersController extends Controller
|
|||||||
* @author [N. Mathar] [<snipe@snipe.net>]
|
* @author [N. Mathar] [<snipe@snipe.net>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
* @return array | \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function licenses($id)
|
public function licenses($id)
|
||||||
{
|
{
|
||||||
@@ -635,6 +674,7 @@ class UsersController extends Controller
|
|||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
|
||||||
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
||||||
|
$this->authorize('update', $user);
|
||||||
$licenses = $user->licenses()->get();
|
$licenses = $user->licenses()->get();
|
||||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||||
}
|
}
|
||||||
@@ -658,9 +698,20 @@ class UsersController extends Controller
|
|||||||
if ($request->filled('id')) {
|
if ($request->filled('id')) {
|
||||||
try {
|
try {
|
||||||
$user = User::find($request->get('id'));
|
$user = User::find($request->get('id'));
|
||||||
|
$this->authorize('update', $user);
|
||||||
$user->two_factor_secret = null;
|
$user->two_factor_secret = null;
|
||||||
$user->two_factor_enrolled = 0;
|
$user->two_factor_enrolled = 0;
|
||||||
$user->save();
|
$user->saveQuietly();
|
||||||
|
|
||||||
|
// Log the reset
|
||||||
|
$logaction = new Actionlog();
|
||||||
|
$logaction->target_type = User::class;
|
||||||
|
$logaction->target_id = $user->id;
|
||||||
|
$logaction->item_type = User::class;
|
||||||
|
$logaction->item_id = $user->id;
|
||||||
|
$logaction->created_at = date('Y-m-d H:i:s');
|
||||||
|
$logaction->user_id = Auth::user()->id;
|
||||||
|
$logaction->logaction('2FA reset');
|
||||||
|
|
||||||
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
|
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -678,7 +729,7 @@ class UsersController extends Controller
|
|||||||
* @author [Juan Font] [<juanfontalonso@gmail.com>]
|
* @author [Juan Font] [<juanfontalonso@gmail.com>]
|
||||||
* @since [v4.4.2]
|
* @since [v4.4.2]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCurrentUserInfo(Request $request)
|
public function getCurrentUserInfo(Request $request)
|
||||||
{
|
{
|
||||||
@@ -691,12 +742,14 @@ class UsersController extends Controller
|
|||||||
* @author [E. Taylor] [<dev@evantaylor.name>]
|
* @author [E. Taylor] [<dev@evantaylor.name>]
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @since [v6.0.0]
|
* @since [v6.0.0]
|
||||||
* @return JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function restore($userId = null)
|
public function restore($userId)
|
||||||
{
|
{
|
||||||
|
$this->authorize('delete', User::class);
|
||||||
|
|
||||||
if ($user = User::withTrashed()->find($userId)) {
|
if ($user = User::withTrashed()->find($userId)) {
|
||||||
|
|
||||||
$this->authorize('delete', $user);
|
$this->authorize('delete', $user);
|
||||||
|
|
||||||
if ($user->deleted_at == '') {
|
if ($user->deleted_at == '') {
|
||||||
@@ -715,8 +768,6 @@ class UsersController extends Controller
|
|||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check validation to make sure we're not restoring a user with the same username as an existing user
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200);
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Helpers\Helper;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetMaintenance;
|
use App\Models\AssetMaintenance;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Slack;
|
use Slack;
|
||||||
@@ -148,30 +148,20 @@ class AssetMaintenancesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit($assetMaintenanceId = null)
|
public function edit($assetMaintenanceId = null)
|
||||||
{
|
{
|
||||||
|
$this->authorize('update', Asset::class);
|
||||||
|
// Check if the asset maintenance exists
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||||
// Redirect to the improvement management page
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
|
||||||
->with('error', trans('admin/asset_maintenances/message.not_found'));
|
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
|
||||||
} elseif (! $assetMaintenance->asset) {
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
||||||
->with('error', 'The asset associated with this maintenance does not exist.');
|
|
||||||
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||||
return static::getInsufficientPermissionsRedirect();
|
return static::getInsufficientPermissionsRedirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($assetMaintenance->completion_date == '0000-00-00') {
|
|
||||||
$assetMaintenance->completion_date = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($assetMaintenance->start_date == '0000-00-00') {
|
|
||||||
$assetMaintenance->start_date = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($assetMaintenance->cost == '0.00') {
|
|
||||||
$assetMaintenance->cost = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare Improvement Type List
|
// Prepare Improvement Type List
|
||||||
$assetMaintenanceType = [
|
$assetMaintenanceType = [
|
||||||
@@ -203,8 +193,10 @@ class AssetMaintenancesController extends Controller
|
|||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||||
// Redirect to the asset maintenance management page
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
|
||||||
->with('error', trans('admin/asset_maintenances/message.not_found'));
|
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
|
||||||
|
// Redirect to the asset maintenance management page
|
||||||
|
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
||||||
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||||
return static::getInsufficientPermissionsRedirect();
|
return static::getInsufficientPermissionsRedirect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ use App\Http\Requests\ImageUploadRequest;
|
|||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
|
use App\Models\CustomField;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Input;
|
|
||||||
use Illuminate\Support\Facades\View;
|
use Illuminate\Support\Facades\View;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Redirect;
|
use Illuminate\Http\Request;
|
||||||
use Request;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Storage;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to asset models for
|
* This class controls all actions related to asset models for
|
||||||
@@ -66,7 +66,7 @@ class AssetModelsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request)
|
||||||
@@ -85,7 +85,7 @@ class AssetModelsController extends Controller
|
|||||||
$model->category_id = $request->input('category_id');
|
$model->category_id = $request->input('category_id');
|
||||||
$model->notes = $request->input('notes');
|
$model->notes = $request->input('notes');
|
||||||
$model->user_id = Auth::id();
|
$model->user_id = Auth::id();
|
||||||
$model->requestable = Request::has('requestable');
|
$model->requestable = $request->has('requestable');
|
||||||
|
|
||||||
if ($request->input('fieldset_id') != '') {
|
if ($request->input('fieldset_id') != '') {
|
||||||
$model->fieldset_id = $request->input('fieldset_id');
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
@@ -139,7 +139,7 @@ class AssetModelsController extends Controller
|
|||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $modelId = null)
|
public function update(ImageUploadRequest $request, $modelId = null)
|
||||||
@@ -200,7 +200,7 @@ class AssetModelsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function destroy($modelId)
|
public function destroy($modelId)
|
||||||
@@ -220,7 +220,7 @@ class AssetModelsController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('models/'.$model->image);
|
Storage::disk('public')->delete('models/'.$model->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::info($e);
|
Log::info($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ class AssetModelsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function getRestore($id)
|
public function getRestore($id)
|
||||||
@@ -288,7 +288,7 @@ class AssetModelsController extends Controller
|
|||||||
public function show($modelId = null)
|
public function show($modelId = null)
|
||||||
{
|
{
|
||||||
$this->authorize('view', AssetModel::class);
|
$this->authorize('view', AssetModel::class);
|
||||||
$model = AssetModel::withTrashed()->withCount('assets')->find($modelId);
|
$model = AssetModel::withTrashed()->find($modelId);
|
||||||
|
|
||||||
if (isset($model->id)) {
|
if (isset($model->id)) {
|
||||||
return view('models/view', compact('model'));
|
return view('models/view', compact('model'));
|
||||||
@@ -429,7 +429,7 @@ class AssetModelsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function postBulkDelete(Request $request)
|
public function postBulkDelete(Request $request)
|
||||||
{
|
{
|
||||||
@@ -442,7 +442,6 @@ class AssetModelsController extends Controller
|
|||||||
$del_count = 0;
|
$del_count = 0;
|
||||||
|
|
||||||
foreach ($models as $model) {
|
foreach ($models as $model) {
|
||||||
\Log::debug($model->id);
|
|
||||||
|
|
||||||
if ($model->assets_count > 0) {
|
if ($model->assets_count > 0) {
|
||||||
$del_error_count++;
|
$del_error_count++;
|
||||||
@@ -452,8 +451,6 @@ class AssetModelsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug($del_count);
|
|
||||||
\Log::debug($del_error_count);
|
|
||||||
|
|
||||||
if ($del_error_count == 0) {
|
if ($del_error_count == 0) {
|
||||||
return redirect()->route('models.index')
|
return redirect()->route('models.index')
|
||||||
@@ -489,11 +486,11 @@ class AssetModelsController extends Controller
|
|||||||
* @param array $defaultValues
|
* @param array $defaultValues
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues)
|
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues): bool
|
||||||
{
|
{
|
||||||
$data = array();
|
$data = array();
|
||||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||||
$customField = \App\Models\CustomField::find($customFieldId);
|
$customField = CustomField::find($customFieldId);
|
||||||
|
|
||||||
$data[$customField->db_column] = $defaultValue;
|
$data[$customField->db_column] = $defaultValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,25 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class AssetModelsFilesController extends Controller
|
class AssetModelsFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Upload a file to the server.
|
* Upload a file to the server.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @param UploadFileRequest $request
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @since [v1.0]
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@since [v1.0]
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $modelId = null)
|
public function store(UploadFileRequest $request, $modelId = null)
|
||||||
{
|
{
|
||||||
if (! $model = AssetModel::find($modelId)) {
|
if (! $model = AssetModel::find($modelId)) {
|
||||||
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
@@ -37,29 +36,9 @@ class AssetModelsFilesController extends Controller
|
|||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
|
||||||
$extension = $file->getClientOriginalExtension();
|
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
|
||||||
$file_name = 'model-'.$model->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
$model->logUpload($file_name, $request->get('notes'));
|
||||||
if ($extension=='svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/assetmodels/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/assetmodels/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$model->logUpload($file_name, e($request->get('notes')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
||||||
@@ -91,8 +70,6 @@ class AssetModelsFilesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
$file = 'private_uploads/assetmodels/'.$log->filename;
|
||||||
\Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
|
|
||||||
if (! Storage::exists($file)) {
|
if (! Storage::exists($file)) {
|
||||||
return response('File '.$file.' not found on server', 404)
|
return response('File '.$file.' not found on server', 404)
|
||||||
|
|||||||
@@ -6,15 +6,20 @@ use App\Events\CheckoutableCheckedIn;
|
|||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetCheckinRequest;
|
use App\Http\Requests\AssetCheckinRequest;
|
||||||
|
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
|
use App\Models\LicenseSeat;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Redirect;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\View;
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class AssetCheckinController extends Controller
|
class AssetCheckinController extends Controller
|
||||||
{
|
{
|
||||||
|
use MigratesLegacyAssetLocations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view that presents a form to check an asset back into inventory.
|
* Returns a view that presents a form to check an asset back into inventory.
|
||||||
*
|
*
|
||||||
@@ -35,7 +40,17 @@ class AssetCheckinController extends Controller
|
|||||||
|
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto);
|
// This asset is already checked in, redirect
|
||||||
|
|
||||||
|
if (is_null($asset->assignedTo)) {
|
||||||
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto)->with('table_name', 'Assets');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +60,7 @@ class AssetCheckinController extends Controller
|
|||||||
* @param AssetCheckinRequest $request
|
* @param AssetCheckinRequest $request
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @param null $backto
|
* @param null $backto
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
@@ -60,6 +75,11 @@ class AssetCheckinController extends Controller
|
|||||||
if (is_null($target = $asset->assignedTo)) {
|
if (is_null($target = $asset->assignedTo)) {
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
if ($asset->assignedType() == Asset::USER) {
|
if ($asset->assignedType() == Asset::USER) {
|
||||||
@@ -67,11 +87,9 @@ class AssetCheckinController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset->expected_checkin = null;
|
$asset->expected_checkin = null;
|
||||||
$asset->last_checkout = null;
|
//$asset->last_checkout = null;
|
||||||
$asset->last_checkin = now();
|
$asset->last_checkin = now();
|
||||||
$asset->assigned_to = null;
|
|
||||||
$asset->assignedTo()->disassociate($asset);
|
$asset->assignedTo()->disassociate($asset);
|
||||||
$asset->assigned_type = null;
|
|
||||||
$asset->accepted = null;
|
$asset->accepted = null;
|
||||||
$asset->name = $request->get('name');
|
$asset->name = $request->get('name');
|
||||||
|
|
||||||
@@ -79,29 +97,12 @@ class AssetCheckinController extends Controller
|
|||||||
$asset->status_id = e($request->get('status_id'));
|
$asset->status_id = e($request->get('status_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is just meant to correct legacy issues where some user data would have 0
|
$this->migrateLegacyLocations($asset);
|
||||||
// as a location ID, which isn't valid. Later versions of Snipe-IT have stricter validation
|
|
||||||
// rules, so it's necessary to fix this for long-time users. It's kinda gross, but will help
|
|
||||||
// people (and their data) in the long run
|
|
||||||
|
|
||||||
if ($asset->rtd_location_id == '0') {
|
|
||||||
\Log::debug('Manually override the RTD location IDs');
|
|
||||||
\Log::debug('Original RTD Location ID: '.$asset->rtd_location_id);
|
|
||||||
$asset->rtd_location_id = '';
|
|
||||||
\Log::debug('New RTD Location ID: '.$asset->rtd_location_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($asset->location_id == '0') {
|
|
||||||
\Log::debug('Manually override the location IDs');
|
|
||||||
\Log::debug('Original Location ID: '.$asset->location_id);
|
|
||||||
$asset->location_id = '';
|
|
||||||
\Log::debug('New Location ID: '.$asset->location_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$asset->location_id = $asset->rtd_location_id;
|
$asset->location_id = $asset->rtd_location_id;
|
||||||
|
|
||||||
if ($request->filled('location_id')) {
|
if ($request->filled('location_id')) {
|
||||||
\Log::debug('NEW Location ID: '.$request->get('location_id'));
|
Log::debug('NEW Location ID: '.$request->get('location_id'));
|
||||||
$asset->location_id = $request->get('location_id');
|
$asset->location_id = $request->get('location_id');
|
||||||
|
|
||||||
if ($request->get('update_default_location') == 0){
|
if ($request->get('update_default_location') == 0){
|
||||||
@@ -117,12 +118,9 @@ class AssetCheckinController extends Controller
|
|||||||
$checkin_at = $request->get('checkin_at');
|
$checkin_at = $request->get('checkin_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($asset->licenseseats->all())){
|
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
||||||
foreach ($asset->licenseseats as $seat){
|
$seat->update(['assigned_to' => null]);
|
||||||
$seat->assigned_to = null;
|
});
|
||||||
$seat->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all pending Acceptances for this asset and delete them
|
// Get all pending Acceptances for this asset and delete them
|
||||||
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
|
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
|
||||||
@@ -134,15 +132,12 @@ class AssetCheckinController extends Controller
|
|||||||
$acceptance->delete();
|
$acceptance->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Session::put('redirect_option', $request->get('redirect_option'));
|
||||||
// Was the asset updated?
|
// Was the asset updated?
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
|
return Helper::getRedirectOption($asset, $assetId, 'Assets');
|
||||||
if ((isset($user)) && ($backto == 'user')) {
|
|
||||||
return redirect()->route('users.show', $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkin.success'));
|
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use App\Http\Requests\AssetCheckoutRequest;
|
|||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class AssetCheckoutController extends Controller
|
class AssetCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
@@ -33,11 +34,17 @@ class AssetCheckoutController extends Controller
|
|||||||
|
|
||||||
$this->authorize('checkout', $asset);
|
$this->authorize('checkout', $asset);
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($asset->availableForCheckout()) {
|
if ($asset->availableForCheckout()) {
|
||||||
return view('hardware/checkout', compact('asset'))
|
return view('hardware/checkout', compact('asset'))
|
||||||
->with('statusLabel_list', Helper::deployableStatusLabelList());
|
->with('statusLabel_list', Helper::deployableStatusLabelList())
|
||||||
|
->with('table_name', 'Assets');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +54,7 @@ class AssetCheckoutController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param AssetCheckoutRequest $request
|
* @param AssetCheckoutRequest $request
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function store(AssetCheckoutRequest $request, $assetId)
|
public function store(AssetCheckoutRequest $request, $assetId)
|
||||||
@@ -60,9 +67,14 @@ class AssetCheckoutController extends Controller
|
|||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
||||||
}
|
}
|
||||||
$this->authorize('checkout', $asset);
|
$this->authorize('checkout', $asset);
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
$admin = Auth::user();
|
$admin = Auth::user();
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget($asset);
|
$target = $this->determineCheckoutTarget();
|
||||||
|
|
||||||
$asset = $this->updateAssetLocation($asset, $target);
|
$asset = $this->updateAssetLocation($asset, $target);
|
||||||
|
|
||||||
@@ -97,11 +109,12 @@ class AssetCheckoutController extends Controller
|
|||||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Session::put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
|
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
||||||
|
return Helper::getRedirectOption($request, $assetId, 'Assets');
|
||||||
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
|
|||||||
@@ -4,26 +4,25 @@ namespace App\Http\Controllers\Assets;
|
|||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class AssetFilesController extends Controller
|
class AssetFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Upload a file to the server.
|
* Upload a file to the server.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @param UploadFileRequest $request
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @since [v1.0]
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@since [v1.0]
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $assetId = null)
|
public function store(UploadFileRequest $request, $assetId = null)
|
||||||
{
|
{
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
@@ -37,30 +36,9 @@ class AssetFilesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'hardware-'.$asset->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension=='svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/assets/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$asset->logUpload($file_name, e($request->get('notes')));
|
$asset->logUpload($file_name, $request->get('notes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
||||||
@@ -92,7 +70,6 @@ class AssetFilesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$file = 'private_uploads/assets/'.$log->filename;
|
$file = 'private_uploads/assets/'.$log->filename;
|
||||||
\Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
if ($log->action_type == 'audit') {
|
if ($log->action_type == 'audit') {
|
||||||
$file = 'private_uploads/audits/'.$log->filename;
|
$file = 'private_uploads/audits/'.$log->filename;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Helpers\Helper;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Manufacturer;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
@@ -96,12 +96,16 @@ class AssetsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request)
|
||||||
{
|
{
|
||||||
$this->authorize(Asset::class);
|
$this->authorize(Asset::class);
|
||||||
|
|
||||||
|
// There are a lot more rules to add here but prevents
|
||||||
|
// errors around `asset_tags` not being present below.
|
||||||
|
$this->validate($request, ['asset_tags' => ['required', 'array']]);
|
||||||
|
|
||||||
// Handle asset tags - there could be one, or potentially many.
|
// Handle asset tags - there could be one, or potentially many.
|
||||||
// This is only necessary on create, not update, since bulk editing is handled
|
// This is only necessary on create, not update, since bulk editing is handled
|
||||||
// differently
|
// differently
|
||||||
@@ -146,7 +150,8 @@ class AssetsController extends Controller
|
|||||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->assigned_to == '') {
|
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||||
|
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
|
||||||
$asset->location_id = $request->input('rtd_location_id', null);
|
$asset->location_id = $request->input('rtd_location_id', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,29 +160,7 @@ class AssetsController extends Controller
|
|||||||
$asset = $request->handleImages($asset);
|
$asset = $request->handleImages($asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update custom fields in the database.
|
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||||
// 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) {
|
|
||||||
if ($field->field_encrypted == '1') {
|
|
||||||
if (Gate::allows('admin')) {
|
|
||||||
if (is_array($request->input($field->db_column))) {
|
|
||||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (is_array($request->input($field->db_column))) {
|
|
||||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the asset before saving
|
// Validate the asset before saving
|
||||||
if ($asset->isValid() && $asset->save()) {
|
if ($asset->isValid() && $asset->save()) {
|
||||||
@@ -202,7 +185,7 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
\Log::debug(e($asset->asset_tag));
|
Log::debug(e($asset->asset_tag));
|
||||||
return redirect()->route('hardware.index')
|
return redirect()->route('hardware.index')
|
||||||
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
||||||
|
|
||||||
@@ -288,7 +271,7 @@ class AssetsController extends Controller
|
|||||||
*
|
*
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return \Illuminate\Http\RedirectResponse|Redirect
|
* @return \Illuminate\Http\RedirectResponse|Redirect
|
||||||
*@since [v1.0]
|
* @since [v1.0]
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $assetId = null)
|
public function update(ImageUploadRequest $request, $assetId = null)
|
||||||
@@ -303,7 +286,8 @@ class AssetsController extends Controller
|
|||||||
$asset->status_id = $request->input('status_id', null);
|
$asset->status_id = $request->input('status_id', null);
|
||||||
$asset->warranty_months = $request->input('warranty_months', null);
|
$asset->warranty_months = $request->input('warranty_months', null);
|
||||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||||
$asset->purchase_date = $request->input('purchase_date', null);
|
$asset->purchase_date = $request->input('purchase_date', null);
|
||||||
|
$asset->next_audit_date = $request->input('next_audit_date', null);
|
||||||
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
|
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
|
||||||
$asset->purchase_date = $request->input('purchase_date', null);
|
$asset->purchase_date = $request->input('purchase_date', null);
|
||||||
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||||
@@ -364,32 +348,7 @@ class AssetsController extends Controller
|
|||||||
$asset->notes = $request->input('notes');
|
$asset->notes = $request->input('notes');
|
||||||
|
|
||||||
$asset = $request->handleImages($asset);
|
$asset = $request->handleImages($asset);
|
||||||
|
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||||
// Update custom fields in the database.
|
|
||||||
// Validation for these fields is handlded through the AssetRequest form request
|
|
||||||
// FIXME: No idea why this is returning a Builder error on db_column_name.
|
|
||||||
// Need to investigate and fix. Using static method for now.
|
|
||||||
$model = AssetModel::find($request->get('model_id'));
|
|
||||||
if (($model) && ($model->fieldset)) {
|
|
||||||
foreach ($model->fieldset->fields as $field) {
|
|
||||||
if ($field->field_encrypted == '1') {
|
|
||||||
if (Gate::allows('admin')) {
|
|
||||||
if (is_array($request->input($field->db_column))) {
|
|
||||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (is_array($request->input($field->db_column))) {
|
|
||||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
return redirect()->route('hardware.show', $assetId)
|
return redirect()->route('hardware.show', $assetId)
|
||||||
@@ -405,7 +364,7 @@ class AssetsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($assetId)
|
public function destroy($assetId)
|
||||||
{
|
{
|
||||||
@@ -439,7 +398,7 @@ class AssetsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getAssetBySerial(Request $request)
|
public function getAssetBySerial(Request $request)
|
||||||
{
|
{
|
||||||
@@ -457,7 +416,7 @@ class AssetsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getAssetByTag(Request $request, $tag=null)
|
public function getAssetByTag(Request $request, $tag=null)
|
||||||
{
|
{
|
||||||
@@ -521,31 +480,33 @@ class AssetsController extends Controller
|
|||||||
public function getBarCode($assetId = null)
|
public function getBarCode($assetId = null)
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$asset = Asset::find($assetId);
|
if ($asset = Asset::withTrashed()->find($assetId)) {
|
||||||
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
|
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
|
||||||
|
|
||||||
if (isset($asset->id, $asset->asset_tag)) {
|
if (isset($asset->id, $asset->asset_tag)) {
|
||||||
if (file_exists($barcode_file)) {
|
if (file_exists($barcode_file)) {
|
||||||
$header = ['Content-type' => 'image/png'];
|
$header = ['Content-type' => 'image/png'];
|
||||||
|
|
||||||
return response()->file($barcode_file, $header);
|
return response()->file($barcode_file, $header);
|
||||||
} else {
|
} else {
|
||||||
// Calculate barcode width in pixel based on label width (inch)
|
// Calculate barcode width in pixel based on label width (inch)
|
||||||
$barcode_width = ($settings->labels_width - $settings->labels_display_sgutter) * 200.000000000001;
|
$barcode_width = ($settings->labels_width - $settings->labels_display_sgutter) * 200.000000000001;
|
||||||
|
|
||||||
$barcode = new \Com\Tecnick\Barcode\Barcode();
|
$barcode = new \Com\Tecnick\Barcode\Barcode();
|
||||||
try {
|
try {
|
||||||
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode, $asset->asset_tag, ($barcode_width < 300 ? $barcode_width : 300), 50);
|
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode, $asset->asset_tag, ($barcode_width < 300 ? $barcode_width : 300), 50);
|
||||||
file_put_contents($barcode_file, $barcode_obj->getPngData());
|
file_put_contents($barcode_file, $barcode_obj->getPngData());
|
||||||
|
|
||||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::debug('The barcode format is invalid.');
|
Log::debug('The barcode format is invalid.');
|
||||||
|
|
||||||
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
|
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -734,11 +695,11 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
if ($isCheckinHeaderExplicit) {
|
if ($isCheckinHeaderExplicit) {
|
||||||
|
|
||||||
//if checkin date header exists, assume that empty or future date is still checked out
|
// if checkin date header exists, assume that empty or future date is still checked out
|
||||||
//if checkin is before todays date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items is checked out
|
// if checkin is before today's date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items are checked out
|
||||||
|
|
||||||
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date))
|
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date)))
|
||||||
) {
|
{
|
||||||
//only do this if item is checked out
|
//only do this if item is checked out
|
||||||
$asset->assigned_to = $user->id;
|
$asset->assigned_to = $user->id;
|
||||||
$asset->assigned_type = User::class;
|
$asset->assigned_type = User::class;
|
||||||
@@ -847,15 +808,15 @@ class AssetsController extends Controller
|
|||||||
return view('hardware/audit-due');
|
return view('hardware/audit-due');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function overdueForAudit()
|
public function dueForCheckin()
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('checkin', Asset::class);
|
||||||
|
|
||||||
return view('hardware/audit-overdue');
|
return view('hardware/checkin-due');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function auditStore(Request $request, $id)
|
public function auditStore(UploadFileRequest $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('audit', Asset::class);
|
||||||
|
|
||||||
@@ -872,7 +833,21 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
$asset = Asset::findOrFail($id);
|
$asset = Asset::findOrFail($id);
|
||||||
|
|
||||||
// We don't want to log this as a normal update, so let's bypass that
|
/**
|
||||||
|
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
|
||||||
|
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
|
||||||
|
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
|
||||||
|
* the audit log entry we're creating through this controller.
|
||||||
|
*
|
||||||
|
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
|
||||||
|
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
|
||||||
|
* will bypass normal model-level validation that's usually handled at the observer )
|
||||||
|
*
|
||||||
|
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
|
||||||
|
* which manually invokes Watson Validating to make sure the asset's model is valid.
|
||||||
|
*
|
||||||
|
* @see \App\Observers\AssetObserver::updating()
|
||||||
|
*/
|
||||||
$asset->unsetEventDispatcher();
|
$asset->unsetEventDispatcher();
|
||||||
|
|
||||||
$asset->next_audit_date = $request->input('next_audit_date');
|
$asset->next_audit_date = $request->input('next_audit_date');
|
||||||
@@ -881,29 +856,27 @@ class AssetsController extends Controller
|
|||||||
// Check to see if they checked the box to update the physical location,
|
// Check to see if they checked the box to update the physical location,
|
||||||
// not just note it in the audit notes
|
// not just note it in the audit notes
|
||||||
if ($request->input('update_location') == '1') {
|
if ($request->input('update_location') == '1') {
|
||||||
Log::debug('update location in audit');
|
|
||||||
$asset->location_id = $request->input('location_id');
|
$asset->location_id = $request->input('location_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
|
||||||
|
* We have to invoke this manually because of the unsetEventDispatcher() above.)
|
||||||
|
*/
|
||||||
|
if ($asset->isValid() && $asset->save()) {
|
||||||
|
|
||||||
if ($asset->save()) {
|
$file_name = null;
|
||||||
$file_name = '';
|
// Create the image (if one was chosen.)
|
||||||
// Upload an image, if attached
|
|
||||||
if ($request->hasFile('image')) {
|
if ($request->hasFile('image')) {
|
||||||
$path = 'private_uploads/audits';
|
$file_name = $request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image'));
|
||||||
if (! Storage::exists($path)) {
|
|
||||||
Storage::makeDirectory($path, 775);
|
|
||||||
}
|
|
||||||
$upload = $image = $request->file('image');
|
|
||||||
$ext = $image->getClientOriginalExtension();
|
|
||||||
$file_name = 'audit-'.str_random(18).'.'.$ext;
|
|
||||||
Storage::putFileAs($path, $upload, $file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
|
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
|
||||||
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
|
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestedIndex($user_id = null)
|
public function getRequestedIndex($user_id = null)
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ use App\Models\Setting;
|
|||||||
use App\View\Label;
|
use App\View\Label;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use App\Http\Requests\AssetCheckoutRequest;
|
use App\Http\Requests\AssetCheckoutRequest;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
@@ -93,6 +96,59 @@ class BulkAssetsController extends Controller
|
|||||||
|
|
||||||
$assets = Asset::with('assignedTo', 'location', 'model')->whereIn('assets.id', $asset_ids);
|
$assets = Asset::with('assignedTo', 'location', 'model')->whereIn('assets.id', $asset_ids);
|
||||||
|
|
||||||
|
$assets = $assets->get();
|
||||||
|
|
||||||
|
if ($assets->isEmpty()) {
|
||||||
|
Log::debug('No assets were found for the provided IDs', ['ids' => $asset_ids]);
|
||||||
|
return redirect()->back()->with('error', trans('admin/hardware/message.update.assets_do_not_exist_or_are_invalid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$models = $assets->unique('model_id');
|
||||||
|
$modelNames = [];
|
||||||
|
foreach($models as $model) {
|
||||||
|
$modelNames[] = $model->model->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('bulk_actions')) {
|
||||||
|
|
||||||
|
|
||||||
|
switch ($request->input('bulk_actions')) {
|
||||||
|
case 'labels':
|
||||||
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
|
return (new Label)
|
||||||
|
->with('assets', $assets)
|
||||||
|
->with('settings', Setting::getSettings())
|
||||||
|
->with('bulkedit', true)
|
||||||
|
->with('count', 0);
|
||||||
|
|
||||||
|
case 'delete':
|
||||||
|
$this->authorize('delete', Asset::class);
|
||||||
|
$assets->each(function ($assets) {
|
||||||
|
$this->authorize('delete', $assets);
|
||||||
|
});
|
||||||
|
|
||||||
|
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||||
|
|
||||||
|
case 'restore':
|
||||||
|
$this->authorize('update', Asset::class);
|
||||||
|
$assets = Asset::withTrashed()->find($asset_ids);
|
||||||
|
$assets->each(function ($asset) {
|
||||||
|
$this->authorize('delete', $asset);
|
||||||
|
});
|
||||||
|
return view('hardware/bulk-restore')->with('assets', $assets);
|
||||||
|
|
||||||
|
case 'edit':
|
||||||
|
$this->authorize('update', Asset::class);
|
||||||
|
|
||||||
|
return view('hardware/bulk')
|
||||||
|
->with('assets', $asset_ids)
|
||||||
|
->with('statuslabel_list', Helper::statusLabelList())
|
||||||
|
->with('models', $models->pluck(['model']))
|
||||||
|
->with('modelNames', $modelNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch ($sort_override) {
|
switch ($sort_override) {
|
||||||
case 'model':
|
case 'model':
|
||||||
$assets->OrderModels($order);
|
$assets->OrderModels($order);
|
||||||
@@ -128,54 +184,6 @@ class BulkAssetsController extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$assets = $assets->get();
|
|
||||||
|
|
||||||
$models = $assets->unique('model_id');
|
|
||||||
$modelNames = [];
|
|
||||||
foreach($models as $model) {
|
|
||||||
$modelNames[] = $model->model->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->filled('bulk_actions')) {
|
|
||||||
|
|
||||||
|
|
||||||
switch ($request->input('bulk_actions')) {
|
|
||||||
case 'labels':
|
|
||||||
$this->authorize('view', Asset::class);
|
|
||||||
|
|
||||||
return (new Label)
|
|
||||||
->with('assets', $assets)
|
|
||||||
->with('settings', Setting::getSettings())
|
|
||||||
->with('bulkedit', true)
|
|
||||||
->with('count', 0);
|
|
||||||
|
|
||||||
case 'delete':
|
|
||||||
$this->authorize('delete', Asset::class);
|
|
||||||
$assets->each(function ($assets) {
|
|
||||||
$this->authorize('delete', $assets);
|
|
||||||
});
|
|
||||||
|
|
||||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
|
||||||
|
|
||||||
case 'restore':
|
|
||||||
$this->authorize('update', Asset::class);
|
|
||||||
$assets = Asset::withTrashed()->find($asset_ids);
|
|
||||||
$assets->each(function ($asset) {
|
|
||||||
$this->authorize('delete', $asset);
|
|
||||||
});
|
|
||||||
return view('hardware/bulk-restore')->with('assets', $assets);
|
|
||||||
|
|
||||||
case 'edit':
|
|
||||||
$this->authorize('update', Asset::class);
|
|
||||||
|
|
||||||
return view('hardware/bulk')
|
|
||||||
->with('assets', $asset_ids)
|
|
||||||
->with('statuslabel_list', Helper::statusLabelList())
|
|
||||||
->with('models', $models->pluck(['model']))
|
|
||||||
->with('modelNames', $modelNames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->back()->with('error', 'No action selected');
|
return redirect()->back()->with('error', 'No action selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +191,6 @@ class BulkAssetsController extends Controller
|
|||||||
* Save bulk edits
|
* Save bulk edits
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return Redirect
|
|
||||||
* @internal param array $assets
|
* @internal param array $assets
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
*/
|
*/
|
||||||
@@ -208,7 +215,7 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$assets = Asset::whereIn('id', array_keys($request->input('ids')))->get();
|
$assets = Asset::whereIn('id', $request->input('ids'))->get();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -373,28 +380,30 @@ class BulkAssetsController extends Controller
|
|||||||
foreach ($asset->model->fieldset->fields as $field) {
|
foreach ($asset->model->fieldset->fields as $field) {
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
if (Gate::allows('admin')) {
|
||||||
|
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the decrypted existing value is different from one we just submitted
|
|
||||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
|
||||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
|
||||||
* different times will have different values, so it will *look* like it was updated
|
|
||||||
* but it wasn't.
|
|
||||||
*/
|
|
||||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
|
||||||
$asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]);
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
* Check if the decrypted existing value is different from one we just submitted
|
||||||
|
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||||
|
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||||
|
* different times will have different values, so it will *look* like it was updated
|
||||||
|
* but it wasn't.
|
||||||
*/
|
*/
|
||||||
unset($this->update_array[$field->db_column]);
|
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||||
unset($asset->{$field->db_column});
|
$asset->{$field->db_column} = Crypt::encrypt($this->update_array[$field->db_column]);
|
||||||
}
|
} else {
|
||||||
|
/*
|
||||||
|
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||||
|
*/
|
||||||
|
unset($this->update_array[$field->db_column]);
|
||||||
|
unset($asset->{$field->db_column});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These custom fields aren't encrypted, just carry on as usual
|
* These custom fields aren't encrypted, just carry on as usual
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
class ForgotPasswordController extends Controller
|
class ForgotPasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -79,16 +79,16 @@ class ForgotPasswordController extends Controller
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
\Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
|
Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent timing attack to enumerate users.
|
// Prevent timing attack to enumerate users.
|
||||||
usleep(500000 + random_int(0, 1500000));
|
usleep(500000 + random_int(0, 1500000));
|
||||||
|
|
||||||
if ($response === \Password::RESET_LINK_SENT) {
|
if ($response === \Password::RESET_LINK_SENT) {
|
||||||
\Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');
|
Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');
|
||||||
} else {
|
} else {
|
||||||
\Log::info('Password reset attempt: User matching username '.$request->input('username').' NOT FOUND or user is inactive');
|
Log::info('Password reset attempt: User matching username '.$request->input('username').' NOT FOUND or user is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use Illuminate\Support\Carbon;
|
|||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +122,7 @@ class LoginController extends Controller
|
|||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
} else {
|
} else {
|
||||||
$username = $saml->getUsername();
|
$username = $saml->getUsername();
|
||||||
\Log::debug("SAML user '$username' could not be found in database.");
|
Log::debug("SAML user '$username' could not be found in database.");
|
||||||
$request->session()->flash('error', trans('auth/message.signin.error'));
|
$request->session()->flash('error', trans('auth/message.signin.error'));
|
||||||
$saml->clearData();
|
$saml->clearData();
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ class LoginController extends Controller
|
|||||||
$s->save();
|
$s->save();
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
|
Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class LoginController extends Controller
|
|||||||
|
|
||||||
// Better logging
|
// Better logging
|
||||||
if (empty($samlData)) {
|
if (empty($samlData)) {
|
||||||
\Log::debug("SAML page requested, but samlData seems empty.");
|
Log::debug("SAML page requested, but samlData seems empty.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,19 +261,19 @@ class LoginController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Account sign in form processing.
|
* Account sign in form processing.
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
//If the environment is set to ALWAYS require SAML, return access denied
|
//If the environment is set to ALWAYS require SAML, return access denied
|
||||||
if (config('app.require_saml')) {
|
if (config('app.require_saml')) {
|
||||||
\Log::debug('require SAML is enabled in the .env - return a 403');
|
Log::debug('require SAML is enabled in the .env - return a 403');
|
||||||
return view('errors.403');
|
return view('errors.403');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->login_common_disabled == '1') {
|
if (Setting::getSettings()->login_common_disabled == '1') {
|
||||||
\Log::debug('login_common_disabled is set to 1 - return a 403');
|
Log::debug('login_common_disabled is set to 1 - return a 403');
|
||||||
return view('errors.403');
|
return view('errors.403');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ class LoginController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Two factor enrollment page
|
* Two factor enrollment page
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getTwoFactorEnroll()
|
public function getTwoFactorEnroll()
|
||||||
{
|
{
|
||||||
@@ -389,7 +389,7 @@ class LoginController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Two factor code form page
|
* Two factor code form page
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getTwoFactorAuth()
|
public function getTwoFactorAuth()
|
||||||
{
|
{
|
||||||
@@ -415,7 +415,7 @@ class LoginController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function postTwoFactorAuth(Request $request)
|
public function postTwoFactorAuth(Request $request)
|
||||||
{
|
{
|
||||||
@@ -427,10 +427,6 @@ class LoginController extends Controller
|
|||||||
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
|
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $request->has('two_factor_secret')) { // TODO this seems almost the same as above?
|
|
||||||
return redirect()->route('two-factor')->with('error', 'Two-factor code is required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$secret = $request->input('two_factor_secret');
|
$secret = $request->input('two_factor_secret');
|
||||||
|
|
||||||
@@ -439,7 +435,7 @@ class LoginController extends Controller
|
|||||||
$user->saveQuietly();
|
$user->saveQuietly();
|
||||||
$request->session()->put('2fa_authed', $user->id);
|
$request->session()->put('2fa_authed', $user->id);
|
||||||
|
|
||||||
return redirect()->route('home')->with('success', 'You are logged in!');
|
return redirect()->route('home')->with('success', trans('auth/message.signin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
|
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
|
||||||
@@ -451,7 +447,7 @@ class LoginController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function logout(Request $request)
|
public function logout(Request $request)
|
||||||
{
|
{
|
||||||
@@ -537,7 +533,7 @@ class LoginController extends Controller
|
|||||||
|
|
||||||
$minutes = round($seconds / 60);
|
$minutes = round($seconds / 60);
|
||||||
|
|
||||||
$message = \Lang::get('auth/message.throttle', ['minutes' => $minutes]);
|
$message = trans('auth/message.throttle', ['minutes' => $minutes]);
|
||||||
|
|
||||||
return redirect()->back()
|
return redirect()->back()
|
||||||
->withInput($request->only($this->username(), 'remember'))
|
->withInput($request->only($this->username(), 'remember'))
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use App\Models\Setting;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ class ResetPasswordController extends Controller
|
|||||||
$credentials = $request->only('email', 'token');
|
$credentials = $request->only('email', 'token');
|
||||||
|
|
||||||
if (is_null($this->broker()->getUser($credentials))) {
|
if (is_null($this->broker()->getUser($credentials))) {
|
||||||
\Log::debug('Password reset form FAILED - this token is not valid.');
|
Log::debug('Password reset form FAILED - this token is not valid.');
|
||||||
return redirect()->route('password.request')->with('error', trans('passwords.token'));
|
return redirect()->route('password.request')->with('error', trans('passwords.token'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,10 +89,10 @@ class ResetPasswordController extends Controller
|
|||||||
|
|
||||||
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
||||||
|
|
||||||
\Log::debug('Checking if '.$request->input('username').' exists');
|
Log::debug('Checking if '.$request->input('username').' exists');
|
||||||
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
|
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
|
||||||
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
|
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
|
||||||
\Log::debug($user->username.' exists');
|
Log::debug($user->username.' exists');
|
||||||
|
|
||||||
|
|
||||||
// handle the password validation rules set by the admin settings
|
// handle the password validation rules set by the admin settings
|
||||||
@@ -112,17 +112,17 @@ class ResetPasswordController extends Controller
|
|||||||
|
|
||||||
// Check if the password reset above actually worked
|
// Check if the password reset above actually worked
|
||||||
if ($response == \Password::PASSWORD_RESET) {
|
if ($response == \Password::PASSWORD_RESET) {
|
||||||
\Log::debug('Password reset for '.$user->username.' worked');
|
Log::debug('Password reset for '.$user->username.' worked');
|
||||||
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
|
Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
|
||||||
return redirect()->back()->withInput($request->only('email'))->with('success', trans('passwords.reset'));
|
return redirect()->back()->withInput($request->only('email'))->with('success', trans('passwords.reset'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
\Log::debug('Password reset for '.$request->input('username').' FAILED - user does not exist or does not have an email address - but make it look like it succeeded');
|
Log::debug('Password reset for '.$request->input('username').' FAILED - user does not exist or does not have an email address - but make it look like it succeeded');
|
||||||
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Services\Saml;
|
use App\Services\Saml;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller provides the endpoint for SAML communication and metadata.
|
* This controller provides the endpoint for SAML communication and metadata.
|
||||||
@@ -51,7 +51,7 @@ class SamlController extends Controller
|
|||||||
$metadata = $this->saml->getSPMetadata();
|
$metadata = $this->saml->getSPMetadata();
|
||||||
|
|
||||||
if (empty($metadata)) {
|
if (empty($metadata)) {
|
||||||
\Log::debug('SAML metadata is empty - return a 403');
|
Log::debug('SAML metadata is empty - return a 403');
|
||||||
return response()->view('errors.403', [], 403);
|
return response()->view('errors.403', [], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ class SamlController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ class SamlController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function acs(Request $request)
|
public function acs(Request $request)
|
||||||
{
|
{
|
||||||
@@ -126,7 +126,7 @@ class SamlController extends Controller
|
|||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function sls(Request $request)
|
public function sls(Request $request)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class BulkAssetModelsController extends Controller
|
|||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy(Request $request)
|
public function destroy(Request $request)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Category as Category;
|
use App\Models\Category as Category;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Str;
|
use Str;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Http\Requests\ImageUploadRequest;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Companies for
|
* This controller handles all actions related to Companies for
|
||||||
@@ -154,7 +155,7 @@ final class CompaniesController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('companies'.'/'.$company->image);
|
Storage::disk('public')->delete('companies'.'/'.$company->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to Components for
|
* This class controls all actions related to Components for
|
||||||
@@ -188,7 +189,7 @@ class ComponentsController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('components/'.$component->image);
|
Storage::disk('public')->delete('components/'.$component->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,28 +4,28 @@ namespace App\Http\Controllers\Components;
|
|||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ComponentsFilesController extends Controller
|
class ComponentsFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a component.
|
* Validates and stores files associated with a component.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $componentId
|
* @param int $componentId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $componentId = null)
|
public function store(UploadFileRequest $request, $componentId = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
@@ -43,30 +43,7 @@ class ComponentsFilesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/components/','component-'.$component->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'component-'.$component->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/components/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/components/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$component->logUpload($file_name, e($request->input('notes')));
|
$component->logUpload($file_name, e($request->input('notes')));
|
||||||
@@ -108,7 +85,7 @@ class ComponentsFilesController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::delete('components/'.$log->filename);
|
Storage::delete('components/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +111,7 @@ class ComponentsFilesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show($componentId = null, $fileId = null)
|
public function show($componentId = null, $fileId = null)
|
||||||
{
|
{
|
||||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||||
$component = Component::find($componentId);
|
$component = Component::find($componentId);
|
||||||
|
|
||||||
// the component is valid
|
// the component is valid
|
||||||
@@ -150,8 +127,8 @@ class ComponentsFilesController extends Controller
|
|||||||
$file = 'private_uploads/components/'.$log->filename;
|
$file = 'private_uploads/components/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|||||||
@@ -71,11 +71,16 @@ class ConsumableCheckoutController extends Controller
|
|||||||
|
|
||||||
$this->authorize('checkout', $consumable);
|
$this->authorize('checkout', $consumable);
|
||||||
|
|
||||||
// Make sure there is at least one available to checkout
|
// If the quantity is not present in the request or is not a positive integer, set it to 1
|
||||||
if ($consumable->numRemaining() <= 0) {
|
$quantity = $request->input('qty');
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
if (!isset($quantity) || !ctype_digit((string)$quantity) || $quantity <= 0) {
|
||||||
|
$quantity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure there is at least one available to checkout
|
||||||
|
if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) {
|
||||||
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||||
|
}
|
||||||
|
|
||||||
$admin_user = Auth::user();
|
$admin_user = Auth::user();
|
||||||
$assigned_to = e($request->input('assigned_to'));
|
$assigned_to = e($request->input('assigned_to'));
|
||||||
@@ -89,13 +94,14 @@ class ConsumableCheckoutController extends Controller
|
|||||||
// Update the consumable data
|
// Update the consumable data
|
||||||
$consumable->assigned_to = e($request->input('assigned_to'));
|
$consumable->assigned_to = e($request->input('assigned_to'));
|
||||||
|
|
||||||
|
for($i = 0; $i < $quantity; $i++){
|
||||||
$consumable->users()->attach($consumable->id, [
|
$consumable->users()->attach($consumable->id, [
|
||||||
'consumable_id' => $consumable->id,
|
'consumable_id' => $consumable->id,
|
||||||
'user_id' => $admin_user->id,
|
'user_id' => $admin_user->id,
|
||||||
'assigned_to' => e($request->input('assigned_to')),
|
'assigned_to' => e($request->input('assigned_to')),
|
||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
||||||
|
|
||||||
// Redirect to the new consumable page
|
// Redirect to the new consumable page
|
||||||
|
|||||||
@@ -4,28 +4,27 @@ namespace App\Http\Controllers\Consumables;
|
|||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ConsumablesFilesController extends Controller
|
class ConsumablesFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a consumable.
|
* Validates and stores files associated with a consumable.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $consumableId
|
* @param int $consumableId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $consumableId = null)
|
public function store(UploadFileRequest $request, $consumableId = null)
|
||||||
{
|
{
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
||||||
@@ -42,30 +41,7 @@ class ConsumablesFilesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/consumables/','consumable-'.$consumable->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'consumable-'.$consumable->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/consumables/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/consumables/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$consumable->logUpload($file_name, e($request->input('notes')));
|
$consumable->logUpload($file_name, e($request->input('notes')));
|
||||||
@@ -107,7 +83,7 @@ class ConsumablesFilesController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::delete('consumables/'.$log->filename);
|
Storage::delete('consumables/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +124,8 @@ class ConsumablesFilesController extends Controller
|
|||||||
$file = 'private_uploads/consumables/'.$log->filename;
|
$file = 'private_uploads/consumables/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use App\Models\CustomField;
|
|||||||
use App\Models\CustomFieldset;
|
use App\Models\CustomFieldset;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Redirect;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Custom Asset Fields for
|
* This controller handles all actions related to Custom Asset Fields for
|
||||||
@@ -260,7 +259,7 @@ class CustomFieldsController extends Controller
|
|||||||
|
|
||||||
$field->name = trim(e($request->get("name")));
|
$field->name = trim(e($request->get("name")));
|
||||||
$field->element = e($request->get("element"));
|
$field->element = e($request->get("element"));
|
||||||
$field->field_values = e($request->get("field_values"));
|
$field->field_values = $request->get("field_values");
|
||||||
$field->user_id = Auth::id();
|
$field->user_id = Auth::id();
|
||||||
$field->help_text = $request->get("help_text");
|
$field->help_text = $request->get("help_text");
|
||||||
$field->show_in_email = $show_in_email;
|
$field->show_in_email = $show_in_email;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class CustomFieldsetsController extends Controller
|
|||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
@@ -126,7 +126,7 @@ class CustomFieldsetsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v6.0.14]
|
* @since [v6.0.14]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function edit($id)
|
public function edit($id)
|
||||||
@@ -147,7 +147,7 @@ class CustomFieldsetsController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v6.0.14]
|
* @since [v6.0.14]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Models\Department;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class DepartmentsController extends Controller
|
class DepartmentsController extends Controller
|
||||||
{
|
{
|
||||||
@@ -129,7 +130,7 @@ class DepartmentsController extends Controller
|
|||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('departments'.'/'.$department->image);
|
Storage::disk('public')->delete('departments'.'/'.$department->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$department->delete();
|
$department->delete();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Laravel\Socialite\Facades\Socialite;
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
use Laravel\Socialite\Two\InvalidStateException;
|
use Laravel\Socialite\Two\InvalidStateException;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class GoogleAuthController extends Controller
|
class GoogleAuthController extends Controller
|
||||||
{
|
{
|
||||||
@@ -34,9 +34,9 @@ class GoogleAuthController extends Controller
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$socialUser = Socialite::driver('google')->user();
|
$socialUser = Socialite::driver('google')->user();
|
||||||
\Log::debug('Google user found in Google Workspace');
|
Log::debug('Google user found in Google Workspace');
|
||||||
} catch (InvalidStateException $exception) {
|
} catch (InvalidStateException $exception) {
|
||||||
\Log::debug('Google user NOT found in Google Workspace');
|
Log::debug('Google user NOT found in Google Workspace');
|
||||||
return redirect()->route('login')
|
return redirect()->route('login')
|
||||||
->withErrors(
|
->withErrors(
|
||||||
[
|
[
|
||||||
@@ -52,7 +52,7 @@ class GoogleAuthController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
\Log::debug('Google user '.$socialUser->getEmail().' found in Snipe-IT');
|
Log::debug('Google user '.$socialUser->getEmail().' found in Snipe-IT');
|
||||||
$user->update([
|
$user->update([
|
||||||
'avatar' => $socialUser->avatar,
|
'avatar' => $socialUser->avatar,
|
||||||
]);
|
]);
|
||||||
@@ -61,7 +61,7 @@ class GoogleAuthController extends Controller
|
|||||||
return redirect()->route('home');
|
return redirect()->route('home');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug('Google user '.$socialUser->getEmail().' NOT found in Snipe-IT');
|
Log::debug('Google user '.$socialUser->getEmail().' NOT found in Snipe-IT');
|
||||||
return redirect()->route('login')
|
return redirect()->route('login')
|
||||||
->withErrors(
|
->withErrors(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to User Groups for
|
* This controller handles all actions related to User Groups for
|
||||||
@@ -63,6 +64,7 @@ class GroupsController extends Controller
|
|||||||
$group = new Group();
|
$group = new Group();
|
||||||
$group->name = $request->input('name');
|
$group->name = $request->input('name');
|
||||||
$group->permissions = json_encode($request->input('permission'));
|
$group->permissions = json_encode($request->input('permission'));
|
||||||
|
$group->created_by = Auth::user()->id;
|
||||||
|
|
||||||
if ($group->save()) {
|
if ($group->save()) {
|
||||||
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
|
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class CheckoutKitController extends Controller
|
|||||||
* Validate and process the new Predefined Kit data.
|
* Validate and process the new Predefined Kit data.
|
||||||
*
|
*
|
||||||
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
|
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $kit_id)
|
public function store(Request $request, $kit_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class PredefinedKitsController extends Controller
|
|||||||
* Validate and process the new Predefined Kit data.
|
* Validate and process the new Predefined Kit data.
|
||||||
*
|
*
|
||||||
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request)
|
||||||
{
|
{
|
||||||
@@ -95,7 +95,7 @@ class PredefinedKitsController extends Controller
|
|||||||
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $kit_id = null)
|
public function update(ImageUploadRequest $request, $kit_id = null)
|
||||||
{
|
{
|
||||||
@@ -122,7 +122,7 @@ class PredefinedKitsController extends Controller
|
|||||||
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($kit_id)
|
public function destroy($kit_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Models\Asset;
|
|||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Models\CustomField;
|
||||||
use App\Models\Labels\Label;
|
use App\Models\Labels\Label;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Manufacturer;
|
use App\Models\Manufacturer;
|
||||||
@@ -13,6 +14,7 @@ use App\Models\Setting;
|
|||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\View\Label as LabelView;
|
use App\View\Label as LabelView;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class LabelsController extends Controller
|
class LabelsController extends Controller
|
||||||
@@ -20,9 +22,9 @@ class LabelsController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Returns the Label view with test data
|
* Returns the Label view with test data
|
||||||
*
|
*
|
||||||
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
* @param string $labelName
|
||||||
* @param string $labelName
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
||||||
*/
|
*/
|
||||||
public function show(string $labelName)
|
public function show(string $labelName)
|
||||||
{
|
{
|
||||||
@@ -65,6 +67,20 @@ class LabelsController extends Controller
|
|||||||
$exampleAsset->model->category->id = 999999;
|
$exampleAsset->model->category->id = 999999;
|
||||||
$exampleAsset->model->category->name = trans('admin/labels/table.example_category');
|
$exampleAsset->model->category->name = trans('admin/labels/table.example_category');
|
||||||
|
|
||||||
|
$customFieldColumns = CustomField::where('field_encrypted', '=', 0)->pluck('db_column');
|
||||||
|
|
||||||
|
collect(explode(';', Setting::getSettings()->label2_fields))
|
||||||
|
->filter()
|
||||||
|
->each(function ($item) use ($customFieldColumns, $exampleAsset) {
|
||||||
|
$pair = explode('=', $item);
|
||||||
|
|
||||||
|
if (array_key_exists(1, $pair)) {
|
||||||
|
if ($customFieldColumns->contains($pair[1])) {
|
||||||
|
$exampleAsset->{$pair[1]} = "{{$pair[0]}}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
if (request()->has('settings')) {
|
if (request()->has('settings')) {
|
||||||
$overrides = request()->get('settings');
|
$overrides = request()->get('settings');
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class LicenseCheckinController extends Controller
|
class LicenseCheckinController extends Controller
|
||||||
{
|
{
|
||||||
@@ -145,7 +146,7 @@ class LicenseCheckinController extends Controller
|
|||||||
$user_seat->assigned_to = null;
|
$user_seat->assigned_to = null;
|
||||||
|
|
||||||
if ($user_seat->save()) {
|
if ($user_seat->save()) {
|
||||||
\Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
|
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'));
|
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +161,7 @@ class LicenseCheckinController extends Controller
|
|||||||
$asset_seat->asset_id = null;
|
$asset_seat->asset_id = null;
|
||||||
|
|
||||||
if ($asset_seat->save()) {
|
if ($asset_seat->save()) {
|
||||||
\Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
|
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'));
|
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use App\Models\License;
|
|||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class LicenseCheckoutController extends Controller
|
class LicenseCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
@@ -155,16 +156,16 @@ class LicenseCheckoutController extends Controller
|
|||||||
|
|
||||||
public function bulkCheckout($licenseId) {
|
public function bulkCheckout($licenseId) {
|
||||||
|
|
||||||
\Log::debug('Checking out '.$licenseId.' via bulk');
|
Log::debug('Checking out '.$licenseId.' via bulk');
|
||||||
$license = License::findOrFail($licenseId);
|
$license = License::findOrFail($licenseId);
|
||||||
$this->authorize('checkin', $license);
|
$this->authorize('checkin', $license);
|
||||||
$avail_count = $license->getAvailSeatsCountAttribute();
|
$avail_count = $license->getAvailSeatsCountAttribute();
|
||||||
|
|
||||||
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '=', 1)->with('licenses')->get();
|
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '=', 1)->with('licenses')->get();
|
||||||
\Log::debug($avail_count.' will be assigned');
|
Log::debug($avail_count.' will be assigned');
|
||||||
|
|
||||||
if ($users->count() > $avail_count) {
|
if ($users->count() > $avail_count) {
|
||||||
\Log::debug('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
|
Log::debug('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the license is valid, check that there is an available seat
|
// If the license is valid, check that there is an available seat
|
||||||
@@ -179,7 +180,7 @@ class LicenseCheckoutController extends Controller
|
|||||||
|
|
||||||
// Check to make sure this user doesn't already have this license checked out to them
|
// Check to make sure this user doesn't already have this license checked out to them
|
||||||
if ($user->licenses->where('id', '=', $licenseId)->count()) {
|
if ($user->licenses->where('id', '=', $licenseId)->count()) {
|
||||||
\Log::debug($user->username.' already has this license checked out to them. Skipping... ');
|
Log::debug($user->username.' already has this license checked out to them. Skipping... ');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +193,7 @@ class LicenseCheckoutController extends Controller
|
|||||||
$avail_count--;
|
$avail_count--;
|
||||||
$assigned_count++;
|
$assigned_count++;
|
||||||
$licenseSeat->logCheckout(trans('admin/licenses/general.bulk.checkout_all.log_msg'), $user);
|
$licenseSeat->logCheckout(trans('admin/licenses/general.bulk.checkout_all.log_msg'), $user);
|
||||||
\Log::debug('License '.$license->name.' seat '.$licenseSeat->id.' checked out to '.$user->username);
|
Log::debug('License '.$license->name.' seat '.$licenseSeat->id.' checked out to '.$user->username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($avail_count == 0) {
|
if ($avail_count == 0) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user